summaryrefslogtreecommitdiff
path: root/indra/newview/llpreviewgesture.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llpreviewgesture.cpp')
-rw-r--r--indra/newview/llpreviewgesture.cpp3632
1 files changed, 1816 insertions, 1816 deletions
diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp
index 010dc48391..56f23a0458 100644
--- a/indra/newview/llpreviewgesture.cpp
+++ b/indra/newview/llpreviewgesture.cpp
@@ -1,1816 +1,1816 @@
-/**
- * @file llpreviewgesture.cpp
- * @brief Editing UI for inventory-based gestures.
- *
- * $LicenseInfo:firstyear=2004&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 "llpreviewgesture.h"
-
-#include "llagent.h"
-#include "llanimstatelabels.h"
-#include "llanimationstates.h"
-#include "llappviewer.h"
-#include "llcheckboxctrl.h"
-#include "llcombobox.h"
-#include "lldatapacker.h"
-#include "lldelayedgestureerror.h"
-#include "llfloaterreg.h"
-#include "llgesturemgr.h"
-#include "llinventorydefines.h"
-#include "llinventoryfunctions.h"
-#include "llinventorymodel.h"
-#include "llinventorymodelbackgroundfetch.h"
-#include "llkeyboard.h"
-#include "llmultigesture.h"
-#include "llnotificationsutil.h"
-#include "llradiogroup.h"
-#include "llresmgr.h"
-#include "lltrans.h"
-#include "llfilesystem.h"
-#include "llviewerobjectlist.h"
-#include "llviewerregion.h"
-#include "llviewerstats.h"
-#include "llviewerassetupload.h"
-
-std::string NONE_LABEL;
-std::string SHIFT_LABEL;
-std::string CTRL_LABEL;
-
-void dialog_refresh_all();
-
-// used for getting
-
-class LLInventoryGestureAvailable : public LLInventoryCompletionObserver
-{
-public:
- LLInventoryGestureAvailable() {}
-
-protected:
- virtual void done();
-};
-
-void LLInventoryGestureAvailable::done()
-{
- for(uuid_vec_t::iterator it = mComplete.begin(); it != mComplete.end(); ++it)
- {
- LLPreviewGesture* preview = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", *it);
- if(preview)
- {
- preview->refresh();
- }
- }
- gInventory.removeObserver(this);
- delete this;
-}
-
-// Used for sorting
-struct SortItemPtrsByName
-{
- bool operator()(const LLInventoryItem* i1, const LLInventoryItem* i2)
- {
- return (LLStringUtil::compareDict(i1->getName(), i2->getName()) < 0);
- }
-};
-
-// static
-LLPreviewGesture* LLPreviewGesture::show(const LLUUID& item_id, const LLUUID& object_id)
-{
- LLPreviewGesture* preview = LLFloaterReg::showTypedInstance<LLPreviewGesture>("preview_gesture", LLSD(item_id), TAKE_FOCUS_YES);
- if (!preview)
- {
- return NULL;
- }
-
- preview->setObjectID(object_id);
-
- // Start speculative download of sounds and animations
- const LLUUID animation_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_ANIMATION);
- LLInventoryModelBackgroundFetch::instance().start(animation_folder_id);
-
- const LLUUID sound_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_SOUND);
- LLInventoryModelBackgroundFetch::instance().start(sound_folder_id);
-
- // this will call refresh when we have everything.
- LLViewerInventoryItem* item = (LLViewerInventoryItem*)preview->getItem();
- if (item && !item->isFinished())
- {
- LLInventoryGestureAvailable* observer;
- observer = new LLInventoryGestureAvailable();
- observer->watchItem(item_id);
- gInventory.addObserver(observer);
- item->fetchFromServer();
- }
- else
- {
- // not sure this is necessary.
- preview->refresh();
- }
-
- return preview;
-}
-
-void LLPreviewGesture::draw()
-{
- // Skip LLPreview::draw() to avoid description update
- LLFloater::draw();
-}
-
-// virtual
-bool LLPreviewGesture::handleKeyHere(KEY key, MASK mask)
-{
- if(('S' == key) && (MASK_CONTROL == (mask & MASK_CONTROL)))
- {
- saveIfNeeded();
- return true;
- }
-
- return LLPreview::handleKeyHere(key, mask);
-}
-
-
-// virtual
-bool LLPreviewGesture::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop,
- EDragAndDropType cargo_type,
- void* cargo_data,
- EAcceptance* accept,
- std::string& tooltip_msg)
-{
- bool handled = true;
- switch(cargo_type)
- {
- case DAD_ANIMATION:
- case DAD_SOUND:
- {
- // TODO: Don't allow this if you can't transfer the sound/animation
-
- // make a script step
- LLInventoryItem* item = (LLInventoryItem*)cargo_data;
- if (item
- && gInventory.getItem(item->getUUID()))
- {
- LLPermissions perm = item->getPermissions();
- if (!((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED))
- {
- *accept = ACCEPT_NO;
- if (tooltip_msg.empty())
- {
- tooltip_msg.assign("Only animations and sounds\n"
- "with unrestricted permissions\n"
- "can be added to a gesture.");
- }
- break;
- }
- else if (drop)
- {
- LLScrollListItem* line = NULL;
- if (cargo_type == DAD_ANIMATION)
- {
- line = addStep( STEP_ANIMATION );
- LLGestureStepAnimation* anim = (LLGestureStepAnimation*)line->getUserdata();
- anim->mAnimAssetID = item->getAssetUUID();
- anim->mAnimName = item->getName();
- }
- else if (cargo_type == DAD_SOUND)
- {
- line = addStep( STEP_SOUND );
- LLGestureStepSound* sound = (LLGestureStepSound*)line->getUserdata();
- sound->mSoundAssetID = item->getAssetUUID();
- sound->mSoundName = item->getName();
- }
- updateLabel(line);
- mDirty = true;
- refresh();
- }
- *accept = ACCEPT_YES_COPY_MULTI;
- }
- else
- {
- // Not in user's inventory means it was in object inventory
- *accept = ACCEPT_NO;
- }
- break;
- }
- default:
- *accept = ACCEPT_NO;
- if (tooltip_msg.empty())
- {
- tooltip_msg.assign("Only animations and sounds\n"
- "can be added to a gesture.");
- }
- break;
- }
- return handled;
-}
-
-
-// virtual
-bool LLPreviewGesture::canClose()
-{
-
- if(!mDirty || mForceClose)
- {
- return true;
- }
- else
- {
- if(!mSaveDialogShown)
- {
- mSaveDialogShown = true;
- // Bring up view-modal dialog: Save changes? Yes, No, Cancel
- LLNotificationsUtil::add("SaveChanges", LLSD(), LLSD(),
- boost::bind(&LLPreviewGesture::handleSaveChangesDialog, this, _1, _2) );
- }
- return false;
- }
-}
-
-// virtual
-void LLPreviewGesture::onClose(bool app_quitting)
-{
- LLGestureMgr::instance().stopGesture(mPreviewGesture);
-}
-
-// virtual
-void LLPreviewGesture::onUpdateSucceeded()
-{
- refresh();
-}
-
-void LLPreviewGesture::onVisibilityChanged ( const LLSD& new_visibility )
-{
- if (new_visibility.asBoolean())
- {
- refresh();
- }
-}
-
-
-bool LLPreviewGesture::handleSaveChangesDialog(const LLSD& notification, const LLSD& response)
-{
- mSaveDialogShown = false;
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- switch(option)
- {
- case 0: // "Yes"
- LLGestureMgr::instance().stopGesture(mPreviewGesture);
- mCloseAfterSave = true;
- onClickSave(this);
- break;
-
- case 1: // "No"
- LLGestureMgr::instance().stopGesture(mPreviewGesture);
- mDirty = false; // Force the dirty flag because user has clicked NO on confirm save dialog...
- closeFloater();
- break;
-
- case 2: // "Cancel"
- default:
- // If we were quitting, we didn't really mean it.
- LLAppViewer::instance()->abortQuit();
- break;
- }
- return false;
-}
-
-
-LLPreviewGesture::LLPreviewGesture(const LLSD& key)
-: LLPreview(key),
- mTriggerEditor(NULL),
- mModifierCombo(NULL),
- mKeyCombo(NULL),
- mLibraryList(NULL),
- mAddBtn(NULL),
- mUpBtn(NULL),
- mDownBtn(NULL),
- mDeleteBtn(NULL),
- mStepList(NULL),
- mOptionsText(NULL),
- mAnimationRadio(NULL),
- mAnimationCombo(NULL),
- mSoundCombo(NULL),
- mChatEditor(NULL),
- mSaveBtn(NULL),
- mPreviewBtn(NULL),
- mPreviewGesture(NULL),
- mDirty(false)
-{
- NONE_LABEL = LLTrans::getString("---");
- SHIFT_LABEL = LLTrans::getString("KBShift");
- CTRL_LABEL = LLTrans::getString("KBCtrl");
-}
-
-
-LLPreviewGesture::~LLPreviewGesture()
-{
- // Userdata for all steps is a LLGestureStep we need to clean up
- std::vector<LLScrollListItem*> data_list = mStepList->getAllData();
- std::vector<LLScrollListItem*>::iterator data_itor;
- for (data_itor = data_list.begin(); data_itor != data_list.end(); ++data_itor)
- {
- LLScrollListItem* item = *data_itor;
- LLGestureStep* step = (LLGestureStep*)item->getUserdata();
- delete step;
- step = NULL;
- }
-}
-
-
-bool LLPreviewGesture::postBuild()
-{
- setVisibleCallback(boost::bind(&LLPreviewGesture::onVisibilityChanged, this, _2));
-
- LLLineEditor* edit;
- LLComboBox* combo;
- LLButton* btn;
- LLScrollListCtrl* list;
- LLTextBox* text;
- LLCheckBoxCtrl* check;
-
- edit = getChild<LLLineEditor>("desc");
- edit->setKeystrokeCallback(onKeystrokeCommit, this);
-
- edit = getChild<LLLineEditor>("trigger_editor");
- edit->setKeystrokeCallback(onKeystrokeCommit, this);
- edit->setCommitCallback(onCommitSetDirty, this);
- edit->setCommitOnFocusLost(true);
- edit->setIgnoreTab(true);
- mTriggerEditor = edit;
-
- text = getChild<LLTextBox>("replace_text");
- text->setEnabled(false);
- mReplaceText = text;
-
- edit = getChild<LLLineEditor>("replace_editor");
- edit->setEnabled(false);
- edit->setKeystrokeCallback(onKeystrokeCommit, this);
- edit->setCommitCallback(onCommitSetDirty, this);
- edit->setCommitOnFocusLost(true);
- edit->setIgnoreTab(true);
- mReplaceEditor = edit;
-
- combo = getChild<LLComboBox>( "modifier_combo");
- combo->setCommitCallback(boost::bind(&LLPreviewGesture::onCommitKeyorModifier, this));
- mModifierCombo = combo;
-
- combo = getChild<LLComboBox>( "key_combo");
- combo->setCommitCallback(boost::bind(&LLPreviewGesture::onCommitKeyorModifier, this));
- mKeyCombo = combo;
-
- list = getChild<LLScrollListCtrl>("library_list");
- list->setCommitCallback(onCommitLibrary, this);
- list->setDoubleClickCallback(onClickAdd, this);
- mLibraryList = list;
-
- btn = getChild<LLButton>( "add_btn");
- btn->setClickedCallback(onClickAdd, this);
- btn->setEnabled(false);
- mAddBtn = btn;
-
- btn = getChild<LLButton>( "up_btn");
- btn->setClickedCallback(onClickUp, this);
- btn->setEnabled(false);
- mUpBtn = btn;
-
- btn = getChild<LLButton>( "down_btn");
- btn->setClickedCallback(onClickDown, this);
- btn->setEnabled(false);
- mDownBtn = btn;
-
- btn = getChild<LLButton>( "delete_btn");
- btn->setClickedCallback(onClickDelete, this);
- btn->setEnabled(false);
- mDeleteBtn = btn;
-
- list = getChild<LLScrollListCtrl>("step_list");
- list->setCommitCallback(onCommitStep, this);
- mStepList = list;
-
- // Options
- mOptionsText = getChild<LLTextBox>("options_text");
-
- combo = getChild<LLComboBox>( "animation_list");
- combo->setVisible(false);
- combo->setCommitCallback(onCommitAnimation, this);
- mAnimationCombo = combo;
-
- LLRadioGroup* group;
- group = getChild<LLRadioGroup>("animation_trigger_type");
- group->setVisible(false);
- group->setCommitCallback(onCommitAnimationTrigger, this);
- mAnimationRadio = group;
-
- combo = getChild<LLComboBox>( "sound_list");
- combo->setVisible(false);
- combo->setCommitCallback(onCommitSound, this);
- mSoundCombo = combo;
-
- edit = getChild<LLLineEditor>("chat_editor");
- edit->setVisible(false);
- edit->setCommitCallback(onCommitChat, this);
- //edit->setKeystrokeCallback(onKeystrokeCommit, this);
- edit->setCommitOnFocusLost(true);
- edit->setIgnoreTab(true);
- mChatEditor = edit;
-
- check = getChild<LLCheckBoxCtrl>( "wait_key_release_check");
- check->setVisible(false);
- check->setCommitCallback(onCommitWait, this);
- mWaitKeyReleaseCheck = check;
-
- check = getChild<LLCheckBoxCtrl>( "wait_anim_check");
- check->setVisible(false);
- check->setCommitCallback(onCommitWait, this);
- mWaitAnimCheck = check;
-
- check = getChild<LLCheckBoxCtrl>( "wait_time_check");
- check->setVisible(false);
- check->setCommitCallback(onCommitWait, this);
- mWaitTimeCheck = check;
-
- edit = getChild<LLLineEditor>("wait_time_editor");
- edit->setEnabled(false);
- edit->setVisible(false);
- edit->setPrevalidate(LLTextValidate::validateFloat);
-// edit->setKeystrokeCallback(onKeystrokeCommit, this);
- edit->setCommitOnFocusLost(true);
- edit->setCommitCallback(onCommitWaitTime, this);
- edit->setIgnoreTab(true);
- mWaitTimeEditor = edit;
-
- // Buttons at the bottom
- check = getChild<LLCheckBoxCtrl>( "active_check");
- check->setCommitCallback(onCommitActive, this);
- mActiveCheck = check;
-
- btn = getChild<LLButton>( "save_btn");
- btn->setClickedCallback(onClickSave, this);
- mSaveBtn = btn;
-
- btn = getChild<LLButton>( "preview_btn");
- btn->setClickedCallback(onClickPreview, this);
- mPreviewBtn = btn;
-
-
- // Populate the comboboxes
- addModifiers();
- addKeys();
- addAnimations();
- addSounds();
-
- const LLInventoryItem* item = getItem();
-
- if (item)
- {
- getChild<LLUICtrl>("desc")->setValue(item->getDescription());
- getChild<LLLineEditor>("desc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
- }
-
- return LLPreview::postBuild();
-}
-
-
-void LLPreviewGesture::addModifiers()
-{
- LLComboBox* combo = mModifierCombo;
-
- combo->add( NONE_LABEL, ADD_BOTTOM );
- combo->add( SHIFT_LABEL, ADD_BOTTOM );
- combo->add( CTRL_LABEL, ADD_BOTTOM );
- combo->setCurrentByIndex(0);
-}
-
-void LLPreviewGesture::addKeys()
-{
- LLComboBox* combo = mKeyCombo;
-
- combo->add( NONE_LABEL );
- for (KEY key = KEY_F2; key <= KEY_F12; key++)
- {
- combo->add( LLKeyboard::stringFromKey(key), ADD_BOTTOM );
- }
- combo->setCurrentByIndex(0);
-}
-
-
-// TODO: Sort the legacy and non-legacy together?
-void LLPreviewGesture::addAnimations()
-{
- LLComboBox* combo = mAnimationCombo;
-
- combo->removeall();
-
- std::string none_text = getString("none_text");
-
- combo->add(none_text, LLUUID::null);
-
- // Add all the default (legacy) animations
- S32 i;
- for (i = 0; i < gUserAnimStatesCount; ++i)
- {
- // Use the user-readable name
- std::string label = LLAnimStateLabels::getStateLabel( gUserAnimStates[i].mName );
- const LLUUID& id = gUserAnimStates[i].mID;
- combo->add(label, id);
- }
-
- // Get all inventory items that are animations
- LLViewerInventoryCategory::cat_array_t cats;
- LLViewerInventoryItem::item_array_t items;
- LLIsTypeWithPermissions is_copyable_animation(LLAssetType::AT_ANIMATION,
- PERM_ITEM_UNRESTRICTED,
- gAgent.getID(),
- gAgent.getGroupID());
- gInventory.collectDescendentsIf(gInventory.getRootFolderID(),
- cats,
- items,
- LLInventoryModel::EXCLUDE_TRASH,
- is_copyable_animation);
-
- // Copy into something we can sort
- std::vector<LLInventoryItem*> animations;
-
- S32 count = items.size();
- for(i = 0; i < count; ++i)
- {
- animations.push_back( items.at(i) );
- }
-
- // Do the sort
- std::sort(animations.begin(), animations.end(), SortItemPtrsByName());
-
- // And load up the combobox
- std::vector<LLInventoryItem*>::iterator it;
- for (it = animations.begin(); it != animations.end(); ++it)
- {
- LLInventoryItem* item = *it;
-
- combo->add(item->getName(), item->getAssetUUID(), ADD_BOTTOM);
- }
-}
-
-
-void LLPreviewGesture::addSounds()
-{
- LLComboBox* combo = mSoundCombo;
- combo->removeall();
-
- std::string none_text = getString("none_text");
-
- combo->add(none_text, LLUUID::null);
-
- // Get all inventory items that are sounds
- LLViewerInventoryCategory::cat_array_t cats;
- LLViewerInventoryItem::item_array_t items;
- LLIsTypeWithPermissions is_copyable_sound(LLAssetType::AT_SOUND,
- PERM_ITEM_UNRESTRICTED,
- gAgent.getID(),
- gAgent.getGroupID());
- gInventory.collectDescendentsIf(gInventory.getRootFolderID(),
- cats,
- items,
- LLInventoryModel::EXCLUDE_TRASH,
- is_copyable_sound);
-
- // Copy sounds into something we can sort
- std::vector<LLInventoryItem*> sounds;
-
- S32 i;
- S32 count = items.size();
- for(i = 0; i < count; ++i)
- {
- sounds.push_back( items.at(i) );
- }
-
- // Do the sort
- std::sort(sounds.begin(), sounds.end(), SortItemPtrsByName());
-
- // And load up the combobox
- std::vector<LLInventoryItem*>::iterator it;
- for (it = sounds.begin(); it != sounds.end(); ++it)
- {
- LLInventoryItem* item = *it;
-
- combo->add(item->getName(), item->getAssetUUID(), ADD_BOTTOM);
- }
-}
-
-
-void LLPreviewGesture::refresh()
-{
- LLPreview::refresh();
- // If previewing or item is incomplete, all controls are disabled
- LLViewerInventoryItem* item = (LLViewerInventoryItem*)getItem();
- bool is_complete = item && item->isFinished();
- if (mPreviewGesture || !is_complete)
- {
-
- getChildView("desc")->setEnabled(false);
- //mDescEditor->setEnabled(false);
- mTriggerEditor->setEnabled(false);
- mReplaceText->setEnabled(false);
- mReplaceEditor->setEnabled(false);
- mModifierCombo->setEnabled(false);
- mKeyCombo->setEnabled(false);
- mLibraryList->setEnabled(false);
- mAddBtn->setEnabled(false);
- mUpBtn->setEnabled(false);
- mDownBtn->setEnabled(false);
- mDeleteBtn->setEnabled(false);
- mStepList->setEnabled(false);
- mOptionsText->setEnabled(false);
- mAnimationCombo->setEnabled(false);
- mAnimationRadio->setEnabled(false);
- mSoundCombo->setEnabled(false);
- mChatEditor->setEnabled(false);
- mWaitKeyReleaseCheck->setEnabled(false);
- mWaitAnimCheck->setEnabled(false);
- mWaitTimeCheck->setEnabled(false);
- mWaitTimeEditor->setEnabled(false);
- mActiveCheck->setEnabled(false);
- mSaveBtn->setEnabled(false);
-
- // Make sure preview button is enabled, so we can stop it
- mPreviewBtn->setEnabled(true);
- return;
- }
-
- bool modifiable = item->getPermissions().allowModifyBy(gAgent.getID());
-
- getChildView("desc")->setEnabled(modifiable);
- mTriggerEditor->setEnabled(true);
- mLibraryList->setEnabled(modifiable);
- mStepList->setEnabled(modifiable);
- mOptionsText->setEnabled(modifiable);
- mAnimationCombo->setEnabled(modifiable);
- mAnimationRadio->setEnabled(modifiable);
- mSoundCombo->setEnabled(modifiable);
- mChatEditor->setEnabled(modifiable);
- mWaitKeyReleaseCheck->setEnabled(modifiable);
- mWaitAnimCheck->setEnabled(modifiable);
- mWaitTimeCheck->setEnabled(modifiable);
- mWaitTimeEditor->setEnabled(modifiable);
- mActiveCheck->setEnabled(true);
-
- const std::string& trigger = mTriggerEditor->getText();
- bool have_trigger = !trigger.empty();
-
- const std::string& replace = mReplaceEditor->getText();
- bool have_replace = !replace.empty();
-
- LLScrollListItem* library_item = mLibraryList->getFirstSelected();
- bool have_library = (library_item != NULL);
-
- LLScrollListItem* step_item = mStepList->getFirstSelected();
- S32 step_index = mStepList->getFirstSelectedIndex();
- S32 step_count = mStepList->getItemCount();
- bool have_step = (step_item != NULL);
-
- mReplaceText->setEnabled(have_trigger || have_replace);
- mReplaceEditor->setEnabled(have_trigger || have_replace);
-
- mModifierCombo->setEnabled(true);
- mKeyCombo->setEnabled(true);
-
- mAddBtn->setEnabled(modifiable && have_library);
- mUpBtn->setEnabled(modifiable && have_step && step_index > 0);
- mDownBtn->setEnabled(modifiable && have_step && step_index < step_count-1);
- mDeleteBtn->setEnabled(modifiable && have_step);
-
- // Assume all not visible
- mAnimationCombo->setVisible(false);
- mAnimationRadio->setVisible(false);
- mSoundCombo->setVisible(false);
- mChatEditor->setVisible(false);
- mWaitKeyReleaseCheck->setVisible(false);
- mWaitAnimCheck->setVisible(false);
- mWaitTimeCheck->setVisible(false);
- mWaitTimeEditor->setVisible(false);
-
- std::string optionstext;
-
- if (have_step)
- {
- // figure out the type, show proper options, update text
- LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
- EStepType type = step->getType();
-
- switch(type)
- {
- case STEP_ANIMATION:
- {
- LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
- optionstext = getString("step_anim");
- mAnimationCombo->setVisible(true);
- mAnimationRadio->setVisible(true);
- mAnimationRadio->setSelectedIndex((anim_step->mFlags & ANIM_FLAG_STOP) ? 1 : 0);
- mAnimationCombo->setCurrentByID(anim_step->mAnimAssetID);
- break;
- }
- case STEP_SOUND:
- {
- LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
- optionstext = getString("step_sound");
- mSoundCombo->setVisible(true);
- mSoundCombo->setCurrentByID(sound_step->mSoundAssetID);
- break;
- }
- case STEP_CHAT:
- {
- LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
- optionstext = getString("step_chat");
- mChatEditor->setVisible(true);
- mChatEditor->setText(chat_step->mChatText);
- break;
- }
- case STEP_WAIT:
- {
- LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
- optionstext = getString("step_wait");
- mWaitKeyReleaseCheck->setVisible(true);
- mWaitKeyReleaseCheck->set(wait_step->mFlags & WAIT_FLAG_KEY_RELEASE);
- mWaitAnimCheck->setVisible(true);
- mWaitAnimCheck->set(wait_step->mFlags & WAIT_FLAG_ALL_ANIM);
- mWaitTimeCheck->setVisible(true);
- mWaitTimeCheck->set(wait_step->mFlags & WAIT_FLAG_TIME);
- mWaitTimeEditor->setVisible(true);
- std::string buffer = llformat("%.1f", (double)wait_step->mWaitSeconds);
- mWaitTimeEditor->setText(buffer);
- break;
- }
- default:
- break;
- }
- }
-
- mOptionsText->setText(optionstext);
-
- bool active = LLGestureMgr::instance().isGestureActive(mItemUUID);
- mActiveCheck->set(active);
-
- // Can only preview if there are steps
- mPreviewBtn->setEnabled(step_count > 0);
-
- // And can only save if changes have been made
- mSaveBtn->setEnabled(mDirty);
- addAnimations();
- addSounds();
-}
-
-
-void LLPreviewGesture::initDefaultGesture()
-{
- LLScrollListItem* item;
- item = addStep( STEP_ANIMATION );
- LLGestureStepAnimation* anim = (LLGestureStepAnimation*)item->getUserdata();
- anim->mAnimAssetID = ANIM_AGENT_HELLO;
- anim->mAnimName = LLTrans::getString("Wave");
- updateLabel(item);
-
- item = addStep( STEP_WAIT );
- LLGestureStepWait* wait = (LLGestureStepWait*)item->getUserdata();
- wait->mFlags = WAIT_FLAG_ALL_ANIM;
- updateLabel(item);
-
- item = addStep( STEP_CHAT );
- LLGestureStepChat* chat_step = (LLGestureStepChat*)item->getUserdata();
- chat_step->mChatText = LLTrans::getString("HelloAvatar");
- updateLabel(item);
-
- // Start with item list selected
- mStepList->selectFirstItem();
-
- // this is *new* content, so we are dirty
- mDirty = true;
-}
-
-
-void LLPreviewGesture::loadAsset()
-{
- const LLInventoryItem* item = getItem();
- if (!item)
- {
- // Don't set asset status here; we may not have set the item id yet
- // (e.g. when this gets called initially)
- //mAssetStatus = PREVIEW_ASSET_ERROR;
- return;
- }
-
- LLUUID asset_id = item->getAssetUUID();
- if (asset_id.isNull())
- {
- // Freshly created gesture, don't need to load asset.
- // Blank gesture will be fine.
- initDefaultGesture();
- refresh();
- mAssetStatus = PREVIEW_ASSET_LOADED;
- return;
- }
-
- // TODO: Based on item->getPermissions().allow*
- // could enable/disable UI.
-
- // Copy the UUID, because the user might close the preview
- // window if the download gets stalled.
- LLUUID* item_idp = new LLUUID(mItemUUID);
-
- const bool high_priority = true;
- gAssetStorage->getAssetData(asset_id,
- LLAssetType::AT_GESTURE,
- onLoadComplete,
- (void**)item_idp,
- high_priority);
- mAssetStatus = PREVIEW_ASSET_LOADING;
-}
-
-
-// static
-void LLPreviewGesture::onLoadComplete(const LLUUID& asset_uuid,
- LLAssetType::EType type,
- void* user_data, S32 status, LLExtStat ext_status)
-{
- LLUUID* item_idp = (LLUUID*)user_data;
-
- LLPreviewGesture* self = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", *item_idp);
- if (self)
- {
- if (0 == status)
- {
- LLFileSystem file(asset_uuid, type, LLFileSystem::READ);
- S32 size = file.getSize();
-
- std::vector<char> buffer(size+1);
- file.read((U8*)&buffer[0], size);
- buffer[size] = '\0';
-
- LLMultiGesture* gesture = new LLMultiGesture();
-
- LLDataPackerAsciiBuffer dp(&buffer[0], size+1);
- bool ok = gesture->deserialize(dp);
-
- if (ok)
- {
- // Everything has been successful. Load up the UI.
- self->loadUIFromGesture(gesture);
-
- self->mStepList->selectFirstItem();
-
- self->mDirty = false;
- self->refresh();
- self->refreshFromItem(); // to update description and title
- }
- else
- {
- LL_WARNS() << "Unable to load gesture" << LL_ENDL;
- }
-
- delete gesture;
- gesture = NULL;
-
- self->mAssetStatus = PREVIEW_ASSET_LOADED;
- }
- else
- {
- if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
- LL_ERR_FILE_EMPTY == status)
- {
- LLDelayedGestureError::gestureMissing( *item_idp );
- }
- else
- {
- LLDelayedGestureError::gestureFailedToLoad( *item_idp );
- }
-
- LL_WARNS() << "Problem loading gesture: " << status << LL_ENDL;
- self->mAssetStatus = PREVIEW_ASSET_ERROR;
- }
- }
- delete item_idp;
- item_idp = NULL;
-}
-
-
-void LLPreviewGesture::loadUIFromGesture(LLMultiGesture* gesture)
-{
- /*LLInventoryItem* item = getItem();
-
-
-
- if (item)
- {
- LLLineEditor* descEditor = getChild<LLLineEditor>("desc");
- descEditor->setText(item->getDescription());
- }*/
-
- mTriggerEditor->setText(gesture->mTrigger);
-
- mReplaceEditor->setText(gesture->mReplaceText);
-
- switch (gesture->mMask)
- {
- default:
- case MASK_NONE:
- mModifierCombo->setSimple( NONE_LABEL );
- break;
- case MASK_SHIFT:
- mModifierCombo->setSimple( SHIFT_LABEL );
- break;
- case MASK_CONTROL:
- mModifierCombo->setSimple( CTRL_LABEL );
- break;
- }
-
- mModifierCombo->setEnabledByValue(CTRL_LABEL, gesture->mKey != KEY_F10);
-
- mKeyCombo->setCurrentByIndex(0);
- if (gesture->mKey != KEY_NONE)
- {
- mKeyCombo->setSimple(LLKeyboard::stringFromKey(gesture->mKey));
- }
-
- mKeyCombo->setEnabledByValue(LLKeyboard::stringFromKey(KEY_F10), gesture->mMask != MASK_CONTROL);
-
- // Make UI steps for each gesture step
- S32 i;
- S32 count = gesture->mSteps.size();
- for (i = 0; i < count; ++i)
- {
- LLGestureStep* step = gesture->mSteps[i];
-
- LLGestureStep* new_step = NULL;
-
- switch(step->getType())
- {
- case STEP_ANIMATION:
- {
- LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
- LLGestureStepAnimation* new_anim_step =
- new LLGestureStepAnimation(*anim_step);
- new_step = new_anim_step;
- break;
- }
- case STEP_SOUND:
- {
- LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
- LLGestureStepSound* new_sound_step =
- new LLGestureStepSound(*sound_step);
- new_step = new_sound_step;
- break;
- }
- case STEP_CHAT:
- {
- LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
- LLGestureStepChat* new_chat_step =
- new LLGestureStepChat(*chat_step);
- new_step = new_chat_step;
- break;
- }
- case STEP_WAIT:
- {
- LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
- LLGestureStepWait* new_wait_step =
- new LLGestureStepWait(*wait_step);
- new_step = new_wait_step;
- break;
- }
- default:
- {
- break;
- }
- }
-
- if (!new_step) continue;
-
- // Create an enabled item with this step
- LLSD row;
- row["columns"][0]["value"] = getLabel( new_step->getLabel());
- row["columns"][0]["font"] = "SANSSERIF_SMALL";
- LLScrollListItem* item = mStepList->addElement(row);
- item->setUserdata(new_step);
- }
-}
-
-// Helpful structure so we can look up the inventory item
-// after the save finishes.
-struct LLSaveInfo
-{
- LLSaveInfo(const LLUUID& item_id, const LLUUID& object_id, const std::string& desc,
- const LLTransactionID tid)
- : mItemUUID(item_id), mObjectUUID(object_id), mDesc(desc), mTransactionID(tid)
- {
- }
-
- LLUUID mItemUUID;
- LLUUID mObjectUUID;
- std::string mDesc;
- LLTransactionID mTransactionID;
-};
-
-
-void LLPreviewGesture::finishInventoryUpload(LLUUID itemId, LLUUID newAssetId)
-{
- // If this gesture is active, then we need to update the in-memory
- // active map with the new pointer.
- if (LLGestureMgr::instance().isGestureActive(itemId))
- {
- // Active gesture edited from menu.
- LLGestureMgr::instance().replaceGesture(itemId, newAssetId);
- gInventory.notifyObservers();
- }
-
- //gesture will have a new asset_id
- LLPreviewGesture* previewp = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", LLSD(itemId));
- if (previewp)
- {
- previewp->onUpdateSucceeded();
- }
-}
-
-
-void LLPreviewGesture::saveIfNeeded()
-{
- if (!gAssetStorage)
- {
- LL_WARNS() << "Can't save gesture, no asset storage system." << LL_ENDL;
- return;
- }
-
- if (!mDirty)
- {
- return;
- }
-
- // Copy the UI into a gesture
- LLMultiGesture* gesture = createGesture();
-
- // Serialize the gesture
- S32 maxSize = gesture->getMaxSerialSize();
- char* buffer = new char[maxSize];
-
- LLDataPackerAsciiBuffer dp(buffer, maxSize);
-
- bool ok = gesture->serialize(dp);
-
- if (dp.getCurrentSize() > 1000)
- {
- LLNotificationsUtil::add("GestureSaveFailedTooManySteps");
-
- delete gesture;
- gesture = NULL;
- return;
- }
- else if (!ok)
- {
- LLNotificationsUtil::add("GestureSaveFailedTryAgain");
- delete gesture;
- gesture = NULL;
- return;
- }
-
- LLAssetID assetId;
- LLPreview::onCommit();
- bool delayedUpload(false);
-
- LLViewerInventoryItem* item = (LLViewerInventoryItem*) getItem();
- if (item)
- {
- const LLViewerRegion* region = gAgent.getRegion();
- if (!region)
- {
- LL_WARNS() << "Not connected to a region, cannot save gesture." << LL_ENDL;
- return;
- }
- std::string agent_url = region->getCapability("UpdateGestureAgentInventory");
- std::string task_url = region->getCapability("UpdateGestureTaskInventory");
-
- if (!agent_url.empty() && !task_url.empty())
- {
- std::string url;
- LLResourceUploadInfo::ptr_t uploadInfo;
-
- if (mObjectUUID.isNull() && !agent_url.empty())
- {
- //need to disable the preview floater so item
- //isn't re-saved before new asset arrives
- //fake out refresh.
- item->setComplete(false);
- refresh();
- item->setComplete(true);
-
- uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(mItemUUID, LLAssetType::AT_GESTURE, buffer,
- [](LLUUID itemId, LLUUID newAssetId, LLUUID, LLSD)
- {
- LLPreviewGesture::finishInventoryUpload(itemId, newAssetId);
- },
- nullptr);
- url = agent_url;
- }
- else if (!mObjectUUID.isNull() && !task_url.empty())
- {
- uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(mObjectUUID, mItemUUID, LLAssetType::AT_GESTURE, buffer, nullptr, nullptr);
- url = task_url;
- }
-
- if (!url.empty() && uploadInfo)
- {
- delayedUpload = true;
-
- LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
- }
-
- }
- else if (gAssetStorage)
- {
- // Every save gets a new UUID. Yup.
- LLTransactionID tid;
- tid.generate();
- assetId = tid.makeAssetID(gAgent.getSecureSessionID());
-
- LLFileSystem file(assetId, LLAssetType::AT_GESTURE, LLFileSystem::APPEND);
-
- S32 size = dp.getCurrentSize();
- file.write((U8*)buffer, size);
-
- LLLineEditor* descEditor = getChild<LLLineEditor>("desc");
- LLSaveInfo* info = new LLSaveInfo(mItemUUID, mObjectUUID, descEditor->getText(), tid);
- gAssetStorage->storeAssetData(tid, LLAssetType::AT_GESTURE, onSaveComplete, info, false);
- }
-
- }
-
- // If this gesture is active, then we need to update the in-memory
- // active map with the new pointer.
- if (!delayedUpload && LLGestureMgr::instance().isGestureActive(mItemUUID))
- {
- // gesture manager now owns the pointer
- LLGestureMgr::instance().replaceGesture(mItemUUID, gesture, assetId);
-
- // replaceGesture may deactivate other gestures so let the
- // inventory know.
- gInventory.notifyObservers();
- }
- else
- {
- // we're done with this gesture
- delete gesture;
- gesture = NULL;
- }
-
- mDirty = false;
- // refresh will be called when callback
- // if triggered when delayedUpload
- if(!delayedUpload)
- {
- refresh();
- }
-
-}
-
-
-// TODO: This is very similar to LLPreviewNotecard::onSaveComplete.
-// Could merge code.
-// static
-void LLPreviewGesture::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed)
-{
- LLSaveInfo* info = (LLSaveInfo*)user_data;
- if (info && (status == 0))
- {
- if(info->mObjectUUID.isNull())
- {
- // Saving into user inventory
- LLViewerInventoryItem* item;
- item = (LLViewerInventoryItem*)gInventory.getItem(info->mItemUUID);
- if(item)
- {
- LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
- new_item->setDescription(info->mDesc);
- new_item->setTransactionID(info->mTransactionID);
- new_item->setAssetUUID(asset_uuid);
- new_item->updateServer(false);
- gInventory.updateItem(new_item);
- gInventory.notifyObservers();
- }
- else
- {
- LL_WARNS() << "Inventory item for gesture " << info->mItemUUID
- << " is no longer in agent inventory." << LL_ENDL;
- }
- }
- else
- {
- // Saving into in-world object inventory
- LLViewerObject* object = gObjectList.findObject(info->mObjectUUID);
- LLViewerInventoryItem* item = NULL;
- if(object)
- {
- item = (LLViewerInventoryItem*)object->getInventoryObject(info->mItemUUID);
- }
- if(object && item)
- {
- item->setDescription(info->mDesc);
- item->setAssetUUID(asset_uuid);
- item->setTransactionID(info->mTransactionID);
- object->updateInventory(item, TASK_INVENTORY_ITEM_KEY, false);
- dialog_refresh_all();
- }
- else
- {
- LLNotificationsUtil::add("GestureSaveFailedObjectNotFound");
- }
- }
-
- // Find our window and close it if requested.
- LLPreviewGesture* previewp = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", info->mItemUUID);
- if (previewp && previewp->mCloseAfterSave)
- {
- previewp->closeFloater();
- }
- }
- else
- {
- LL_WARNS() << "Problem saving gesture: " << status << LL_ENDL;
- LLSD args;
- args["REASON"] = std::string(LLAssetStorage::getErrorString(status));
- LLNotificationsUtil::add("GestureSaveFailedReason", args);
- }
- delete info;
- info = NULL;
-}
-
-
-LLMultiGesture* LLPreviewGesture::createGesture()
-{
- LLMultiGesture* gesture = new LLMultiGesture();
-
- gesture->mTrigger = mTriggerEditor->getText();
- gesture->mReplaceText = mReplaceEditor->getText();
-
- const std::string& modifier = mModifierCombo->getSimple();
- if (modifier == CTRL_LABEL)
- {
- gesture->mMask = MASK_CONTROL;
- }
- else if (modifier == SHIFT_LABEL)
- {
- gesture->mMask = MASK_SHIFT;
- }
- else
- {
- gesture->mMask = MASK_NONE;
- }
-
- if (mKeyCombo->getCurrentIndex() == 0)
- {
- gesture->mKey = KEY_NONE;
- }
- else
- {
- const std::string& key_string = mKeyCombo->getSimple();
- LLKeyboard::keyFromString(key_string, &(gesture->mKey));
- }
-
- std::vector<LLScrollListItem*> data_list = mStepList->getAllData();
- std::vector<LLScrollListItem*>::iterator data_itor;
- for (data_itor = data_list.begin(); data_itor != data_list.end(); ++data_itor)
- {
- LLScrollListItem* item = *data_itor;
- LLGestureStep* step = (LLGestureStep*)item->getUserdata();
-
- switch(step->getType())
- {
- case STEP_ANIMATION:
- {
- // Copy UI-generated step into actual gesture step
- LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
- LLGestureStepAnimation* new_anim_step =
- new LLGestureStepAnimation(*anim_step);
- gesture->mSteps.push_back(new_anim_step);
- break;
- }
- case STEP_SOUND:
- {
- // Copy UI-generated step into actual gesture step
- LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
- LLGestureStepSound* new_sound_step =
- new LLGestureStepSound(*sound_step);
- gesture->mSteps.push_back(new_sound_step);
- break;
- }
- case STEP_CHAT:
- {
- // Copy UI-generated step into actual gesture step
- LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
- LLGestureStepChat* new_chat_step =
- new LLGestureStepChat(*chat_step);
- gesture->mSteps.push_back(new_chat_step);
- break;
- }
- case STEP_WAIT:
- {
- // Copy UI-generated step into actual gesture step
- LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
- LLGestureStepWait* new_wait_step =
- new LLGestureStepWait(*wait_step);
- gesture->mSteps.push_back(new_wait_step);
- break;
- }
- default:
- {
- break;
- }
- }
- }
-
- return gesture;
-}
-
-
-void LLPreviewGesture::onCommitKeyorModifier()
-{
- // SL-14139: ctrl-F10 is currently used to access top menu,
- // so don't allow to bound gestures to this combination.
-
- mKeyCombo->setEnabledByValue(LLKeyboard::stringFromKey(KEY_F10), mModifierCombo->getSimple() != CTRL_LABEL);
- mModifierCombo->setEnabledByValue(CTRL_LABEL, mKeyCombo->getSimple() != LLKeyboard::stringFromKey(KEY_F10));
- mDirty = true;
- refresh();
-}
-
-// static
-void LLPreviewGesture::updateLabel(LLScrollListItem* item)
-{
- LLGestureStep* step = (LLGestureStep*)item->getUserdata();
-
- LLScrollListCell* cell = item->getColumn(0);
- LLScrollListText* text_cell = (LLScrollListText*)cell;
- std::string label = getLabel( step->getLabel());
- text_cell->setText(label);
-}
-
-// static
-void LLPreviewGesture::onCommitSetDirty(LLUICtrl* ctrl, void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
- self->mDirty = true;
- self->refresh();
-}
-
-// static
-void LLPreviewGesture::onCommitLibrary(LLUICtrl* ctrl, void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- LLScrollListItem* library_item = self->mLibraryList->getFirstSelected();
- if (library_item)
- {
- self->mStepList->deselectAllItems();
- self->refresh();
- }
-}
-
-
-// static
-void LLPreviewGesture::onCommitStep(LLUICtrl* ctrl, void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- LLScrollListItem* step_item = self->mStepList->getFirstSelected();
- if (!step_item) return;
-
- self->mLibraryList->deselectAllItems();
- self->refresh();
-}
-
-
-// static
-void LLPreviewGesture::onCommitAnimation(LLUICtrl* ctrl, void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- LLScrollListItem* step_item = self->mStepList->getFirstSelected();
- if (step_item)
- {
- LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
- if (step->getType() == STEP_ANIMATION)
- {
- // Assign the animation name
- LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
- if (self->mAnimationCombo->getCurrentIndex() == 0)
- {
- anim_step->mAnimName.clear();
- anim_step->mAnimAssetID.setNull();
- }
- else
- {
- anim_step->mAnimName = self->mAnimationCombo->getSimple();
- anim_step->mAnimAssetID = self->mAnimationCombo->getCurrentID();
- }
- //anim_step->mFlags = 0x0;
-
- // Update the UI label in the list
- updateLabel(step_item);
-
- self->mDirty = true;
- self->refresh();
- }
- }
-}
-
-// static
-void LLPreviewGesture::onCommitAnimationTrigger(LLUICtrl* ctrl, void *data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- LLScrollListItem* step_item = self->mStepList->getFirstSelected();
- if (step_item)
- {
- LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
- if (step->getType() == STEP_ANIMATION)
- {
- LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
- if (self->mAnimationRadio->getSelectedIndex() == 0)
- {
- // start
- anim_step->mFlags &= ~ANIM_FLAG_STOP;
- }
- else
- {
- // stop
- anim_step->mFlags |= ANIM_FLAG_STOP;
- }
- // Update the UI label in the list
- updateLabel(step_item);
-
- self->mDirty = true;
- self->refresh();
- }
- }
-}
-
-// static
-void LLPreviewGesture::onCommitSound(LLUICtrl* ctrl, void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- LLScrollListItem* step_item = self->mStepList->getFirstSelected();
- if (step_item)
- {
- LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
- if (step->getType() == STEP_SOUND)
- {
- // Assign the sound name
- LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
- sound_step->mSoundName = self->mSoundCombo->getSimple();
- sound_step->mSoundAssetID = self->mSoundCombo->getCurrentID();
- sound_step->mFlags = 0x0;
-
- // Update the UI label in the list
- updateLabel(step_item);
-
- self->mDirty = true;
- self->refresh();
- }
- }
-}
-
-// static
-void LLPreviewGesture::onCommitChat(LLUICtrl* ctrl, void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- LLScrollListItem* step_item = self->mStepList->getFirstSelected();
- if (!step_item) return;
-
- LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
- if (step->getType() != STEP_CHAT) return;
-
- LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
- chat_step->mChatText = self->mChatEditor->getText();
- chat_step->mFlags = 0x0;
-
- // Update the UI label in the list
- updateLabel(step_item);
-
- self->mDirty = true;
- self->refresh();
-}
-
-// static
-void LLPreviewGesture::onCommitWait(LLUICtrl* ctrl, void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- LLScrollListItem* step_item = self->mStepList->getFirstSelected();
- if (!step_item) return;
-
- LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
- if (step->getType() != STEP_WAIT) return;
-
- LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
- U32 flags = 0x0;
- if (self->mWaitKeyReleaseCheck->get()) flags |= WAIT_FLAG_KEY_RELEASE;
- if (self->mWaitAnimCheck->get()) flags |= WAIT_FLAG_ALL_ANIM;
- if (self->mWaitTimeCheck->get()) flags |= WAIT_FLAG_TIME;
- wait_step->mFlags = flags;
-
- {
- LLLocale locale(LLLocale::USER_LOCALE);
-
- F32 wait_seconds = (F32)atof(self->mWaitTimeEditor->getText().c_str());
- if (wait_seconds < 0.f) wait_seconds = 0.f;
- if (wait_seconds > 3600.f) wait_seconds = 3600.f;
- wait_step->mWaitSeconds = wait_seconds;
- }
-
- // Enable the input area if necessary
- self->mWaitTimeEditor->setEnabled(self->mWaitTimeCheck->get());
-
- // Update the UI label in the list
- updateLabel(step_item);
-
- self->mDirty = true;
- self->refresh();
-}
-
-// static
-void LLPreviewGesture::onCommitWaitTime(LLUICtrl* ctrl, void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- LLScrollListItem* step_item = self->mStepList->getFirstSelected();
- if (!step_item) return;
-
- LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
- if (step->getType() != STEP_WAIT) return;
-
- self->mWaitTimeCheck->set(true);
- onCommitWait(ctrl, data);
-}
-
-
-// static
-void LLPreviewGesture::onKeystrokeCommit(LLLineEditor* caller,
- void* data)
-{
- // Just commit every keystroke
- onCommitSetDirty(caller, data);
-}
-
-// static
-void LLPreviewGesture::onClickAdd(void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- LLScrollListItem* library_item = self->mLibraryList->getFirstSelected();
- if (!library_item) return;
-
- S32 library_item_index = self->mLibraryList->getFirstSelectedIndex();
-
- const LLScrollListCell* library_cell = library_item->getColumn(0);
- const std::string& library_text = library_cell->getValue().asString();
-
- if( library_item_index >= STEP_EOF )
- {
- LL_ERRS() << "Unknown step type: " << library_text << LL_ENDL;
- return;
- }
-
- self->addStep( (EStepType)library_item_index );
- self->mDirty = true;
- self->refresh();
-}
-
-LLScrollListItem* LLPreviewGesture::addStep( const EStepType step_type )
-{
- // Order of enum EStepType MUST match the library_list element in floater_preview_gesture.xml
-
- LLGestureStep* step = NULL;
- switch( step_type)
- {
- case STEP_ANIMATION:
- step = new LLGestureStepAnimation();
-
- break;
- case STEP_SOUND:
- step = new LLGestureStepSound();
- break;
- case STEP_CHAT:
- step = new LLGestureStepChat();
- break;
- case STEP_WAIT:
- step = new LLGestureStepWait();
- break;
- default:
- LL_ERRS() << "Unknown step type: " << (S32)step_type << LL_ENDL;
- return NULL;
- }
-
-
- // Create an enabled item with this step
- LLSD row;
- row["columns"][0]["value"] = getLabel(step->getLabel());
- row["columns"][0]["font"] = "SANSSERIF_SMALL";
- LLScrollListItem* step_item = mStepList->addElement(row);
- step_item->setUserdata(step);
-
- // And move selection to the list on the right
- mLibraryList->deselectAllItems();
- mStepList->deselectAllItems();
-
- step_item->setSelected(true);
-
- return step_item;
-}
-
-// static
-std::string LLPreviewGesture::getLabel(std::vector<std::string> labels)
-{
- std::vector<std::string> v_labels = labels ;
- std::string result("");
-
- if( v_labels.size() != 2)
- {
- return result;
- }
-
- if(v_labels[0]=="Chat")
- {
- result=LLTrans::getString("Chat Message");
- }
- else if(v_labels[0]=="Sound")
- {
- result=LLTrans::getString("Sound");
- }
- else if(v_labels[0]=="Wait")
- {
- result=LLTrans::getString("Wait");
- }
- else if(v_labels[0]=="AnimFlagStop")
- {
- result=LLTrans::getString("AnimFlagStop");
- }
- else if(v_labels[0]=="AnimFlagStart")
- {
- result=LLTrans::getString("AnimFlagStart");
- }
-
- // lets localize action value
- std::string action = v_labels[1];
- if ("None" == action)
- {
- action = LLTrans::getString("GestureActionNone");
- }
- else if ("until animations are done" == action)
- {
- action = LLFloaterReg::getInstance("preview_gesture")->getChild<LLCheckBoxCtrl>("wait_anim_check")->getLabel();
- }
- result.append(action);
- return result;
-
-}
-// static
-void LLPreviewGesture::onClickUp(void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- S32 selected_index = self->mStepList->getFirstSelectedIndex();
- if (selected_index > 0)
- {
- self->mStepList->swapWithPrevious(selected_index);
- self->mDirty = true;
- self->refresh();
- }
-}
-
-// static
-void LLPreviewGesture::onClickDown(void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- S32 selected_index = self->mStepList->getFirstSelectedIndex();
- if (selected_index < 0) return;
-
- S32 count = self->mStepList->getItemCount();
- if (selected_index < count-1)
- {
- self->mStepList->swapWithNext(selected_index);
- self->mDirty = true;
- self->refresh();
- }
-}
-
-// static
-void LLPreviewGesture::onClickDelete(void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- LLScrollListItem* item = self->mStepList->getFirstSelected();
- S32 selected_index = self->mStepList->getFirstSelectedIndex();
- if (item && selected_index >= 0)
- {
- LLGestureStep* step = (LLGestureStep*)item->getUserdata();
- delete step;
- step = NULL;
-
- self->mStepList->deleteSingleItem(selected_index);
-
- self->mDirty = true;
- self->refresh();
- }
-}
-
-// static
-void LLPreviewGesture::onCommitActive(LLUICtrl* ctrl, void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
- if (!LLGestureMgr::instance().isGestureActive(self->mItemUUID))
- {
- LLGestureMgr::instance().activateGesture(self->mItemUUID);
- }
- else
- {
- LLGestureMgr::instance().deactivateGesture(self->mItemUUID);
- }
-
- // Make sure the (active) label in the inventory gets updated.
- LLViewerInventoryItem* item = gInventory.getItem(self->mItemUUID);
- if (item)
- {
- gInventory.updateItem(item);
- gInventory.notifyObservers();
- }
-
- self->refresh();
-}
-
-// static
-void LLPreviewGesture::onClickSave(void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
- self->saveIfNeeded();
-}
-
-// static
-void LLPreviewGesture::onClickPreview(void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- if (!self->mPreviewGesture)
- {
- // make temporary gesture
- self->mPreviewGesture = self->createGesture();
-
- // add a callback
- self->mPreviewGesture->mDoneCallback = onDonePreview;
- self->mPreviewGesture->mCallbackData = self;
-
- // set the button title
- self->mPreviewBtn->setLabel(self->getString("stop_txt"));
-
- // play it, and delete when done
- LLGestureMgr::instance().playGesture(self->mPreviewGesture);
-
- self->refresh();
- }
- else
- {
- // Will call onDonePreview() below
- LLGestureMgr::instance().stopGesture(self->mPreviewGesture);
-
- self->refresh();
- }
-}
-
-
-// static
-void LLPreviewGesture::onDonePreview(LLMultiGesture* gesture, void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- self->mPreviewBtn->setLabel(self->getString("preview_txt"));
-
- delete self->mPreviewGesture;
- self->mPreviewGesture = NULL;
-
- self->refresh();
-}
+/**
+ * @file llpreviewgesture.cpp
+ * @brief Editing UI for inventory-based gestures.
+ *
+ * $LicenseInfo:firstyear=2004&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 "llpreviewgesture.h"
+
+#include "llagent.h"
+#include "llanimstatelabels.h"
+#include "llanimationstates.h"
+#include "llappviewer.h"
+#include "llcheckboxctrl.h"
+#include "llcombobox.h"
+#include "lldatapacker.h"
+#include "lldelayedgestureerror.h"
+#include "llfloaterreg.h"
+#include "llgesturemgr.h"
+#include "llinventorydefines.h"
+#include "llinventoryfunctions.h"
+#include "llinventorymodel.h"
+#include "llinventorymodelbackgroundfetch.h"
+#include "llkeyboard.h"
+#include "llmultigesture.h"
+#include "llnotificationsutil.h"
+#include "llradiogroup.h"
+#include "llresmgr.h"
+#include "lltrans.h"
+#include "llfilesystem.h"
+#include "llviewerobjectlist.h"
+#include "llviewerregion.h"
+#include "llviewerstats.h"
+#include "llviewerassetupload.h"
+
+std::string NONE_LABEL;
+std::string SHIFT_LABEL;
+std::string CTRL_LABEL;
+
+void dialog_refresh_all();
+
+// used for getting
+
+class LLInventoryGestureAvailable : public LLInventoryCompletionObserver
+{
+public:
+ LLInventoryGestureAvailable() {}
+
+protected:
+ virtual void done();
+};
+
+void LLInventoryGestureAvailable::done()
+{
+ for(uuid_vec_t::iterator it = mComplete.begin(); it != mComplete.end(); ++it)
+ {
+ LLPreviewGesture* preview = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", *it);
+ if(preview)
+ {
+ preview->refresh();
+ }
+ }
+ gInventory.removeObserver(this);
+ delete this;
+}
+
+// Used for sorting
+struct SortItemPtrsByName
+{
+ bool operator()(const LLInventoryItem* i1, const LLInventoryItem* i2)
+ {
+ return (LLStringUtil::compareDict(i1->getName(), i2->getName()) < 0);
+ }
+};
+
+// static
+LLPreviewGesture* LLPreviewGesture::show(const LLUUID& item_id, const LLUUID& object_id)
+{
+ LLPreviewGesture* preview = LLFloaterReg::showTypedInstance<LLPreviewGesture>("preview_gesture", LLSD(item_id), TAKE_FOCUS_YES);
+ if (!preview)
+ {
+ return NULL;
+ }
+
+ preview->setObjectID(object_id);
+
+ // Start speculative download of sounds and animations
+ const LLUUID animation_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_ANIMATION);
+ LLInventoryModelBackgroundFetch::instance().start(animation_folder_id);
+
+ const LLUUID sound_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_SOUND);
+ LLInventoryModelBackgroundFetch::instance().start(sound_folder_id);
+
+ // this will call refresh when we have everything.
+ LLViewerInventoryItem* item = (LLViewerInventoryItem*)preview->getItem();
+ if (item && !item->isFinished())
+ {
+ LLInventoryGestureAvailable* observer;
+ observer = new LLInventoryGestureAvailable();
+ observer->watchItem(item_id);
+ gInventory.addObserver(observer);
+ item->fetchFromServer();
+ }
+ else
+ {
+ // not sure this is necessary.
+ preview->refresh();
+ }
+
+ return preview;
+}
+
+void LLPreviewGesture::draw()
+{
+ // Skip LLPreview::draw() to avoid description update
+ LLFloater::draw();
+}
+
+// virtual
+bool LLPreviewGesture::handleKeyHere(KEY key, MASK mask)
+{
+ if(('S' == key) && (MASK_CONTROL == (mask & MASK_CONTROL)))
+ {
+ saveIfNeeded();
+ return true;
+ }
+
+ return LLPreview::handleKeyHere(key, mask);
+}
+
+
+// virtual
+bool LLPreviewGesture::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop,
+ EDragAndDropType cargo_type,
+ void* cargo_data,
+ EAcceptance* accept,
+ std::string& tooltip_msg)
+{
+ bool handled = true;
+ switch(cargo_type)
+ {
+ case DAD_ANIMATION:
+ case DAD_SOUND:
+ {
+ // TODO: Don't allow this if you can't transfer the sound/animation
+
+ // make a script step
+ LLInventoryItem* item = (LLInventoryItem*)cargo_data;
+ if (item
+ && gInventory.getItem(item->getUUID()))
+ {
+ LLPermissions perm = item->getPermissions();
+ if (!((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED))
+ {
+ *accept = ACCEPT_NO;
+ if (tooltip_msg.empty())
+ {
+ tooltip_msg.assign("Only animations and sounds\n"
+ "with unrestricted permissions\n"
+ "can be added to a gesture.");
+ }
+ break;
+ }
+ else if (drop)
+ {
+ LLScrollListItem* line = NULL;
+ if (cargo_type == DAD_ANIMATION)
+ {
+ line = addStep( STEP_ANIMATION );
+ LLGestureStepAnimation* anim = (LLGestureStepAnimation*)line->getUserdata();
+ anim->mAnimAssetID = item->getAssetUUID();
+ anim->mAnimName = item->getName();
+ }
+ else if (cargo_type == DAD_SOUND)
+ {
+ line = addStep( STEP_SOUND );
+ LLGestureStepSound* sound = (LLGestureStepSound*)line->getUserdata();
+ sound->mSoundAssetID = item->getAssetUUID();
+ sound->mSoundName = item->getName();
+ }
+ updateLabel(line);
+ mDirty = true;
+ refresh();
+ }
+ *accept = ACCEPT_YES_COPY_MULTI;
+ }
+ else
+ {
+ // Not in user's inventory means it was in object inventory
+ *accept = ACCEPT_NO;
+ }
+ break;
+ }
+ default:
+ *accept = ACCEPT_NO;
+ if (tooltip_msg.empty())
+ {
+ tooltip_msg.assign("Only animations and sounds\n"
+ "can be added to a gesture.");
+ }
+ break;
+ }
+ return handled;
+}
+
+
+// virtual
+bool LLPreviewGesture::canClose()
+{
+
+ if(!mDirty || mForceClose)
+ {
+ return true;
+ }
+ else
+ {
+ if(!mSaveDialogShown)
+ {
+ mSaveDialogShown = true;
+ // Bring up view-modal dialog: Save changes? Yes, No, Cancel
+ LLNotificationsUtil::add("SaveChanges", LLSD(), LLSD(),
+ boost::bind(&LLPreviewGesture::handleSaveChangesDialog, this, _1, _2) );
+ }
+ return false;
+ }
+}
+
+// virtual
+void LLPreviewGesture::onClose(bool app_quitting)
+{
+ LLGestureMgr::instance().stopGesture(mPreviewGesture);
+}
+
+// virtual
+void LLPreviewGesture::onUpdateSucceeded()
+{
+ refresh();
+}
+
+void LLPreviewGesture::onVisibilityChanged ( const LLSD& new_visibility )
+{
+ if (new_visibility.asBoolean())
+ {
+ refresh();
+ }
+}
+
+
+bool LLPreviewGesture::handleSaveChangesDialog(const LLSD& notification, const LLSD& response)
+{
+ mSaveDialogShown = false;
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ switch(option)
+ {
+ case 0: // "Yes"
+ LLGestureMgr::instance().stopGesture(mPreviewGesture);
+ mCloseAfterSave = true;
+ onClickSave(this);
+ break;
+
+ case 1: // "No"
+ LLGestureMgr::instance().stopGesture(mPreviewGesture);
+ mDirty = false; // Force the dirty flag because user has clicked NO on confirm save dialog...
+ closeFloater();
+ break;
+
+ case 2: // "Cancel"
+ default:
+ // If we were quitting, we didn't really mean it.
+ LLAppViewer::instance()->abortQuit();
+ break;
+ }
+ return false;
+}
+
+
+LLPreviewGesture::LLPreviewGesture(const LLSD& key)
+: LLPreview(key),
+ mTriggerEditor(NULL),
+ mModifierCombo(NULL),
+ mKeyCombo(NULL),
+ mLibraryList(NULL),
+ mAddBtn(NULL),
+ mUpBtn(NULL),
+ mDownBtn(NULL),
+ mDeleteBtn(NULL),
+ mStepList(NULL),
+ mOptionsText(NULL),
+ mAnimationRadio(NULL),
+ mAnimationCombo(NULL),
+ mSoundCombo(NULL),
+ mChatEditor(NULL),
+ mSaveBtn(NULL),
+ mPreviewBtn(NULL),
+ mPreviewGesture(NULL),
+ mDirty(false)
+{
+ NONE_LABEL = LLTrans::getString("---");
+ SHIFT_LABEL = LLTrans::getString("KBShift");
+ CTRL_LABEL = LLTrans::getString("KBCtrl");
+}
+
+
+LLPreviewGesture::~LLPreviewGesture()
+{
+ // Userdata for all steps is a LLGestureStep we need to clean up
+ std::vector<LLScrollListItem*> data_list = mStepList->getAllData();
+ std::vector<LLScrollListItem*>::iterator data_itor;
+ for (data_itor = data_list.begin(); data_itor != data_list.end(); ++data_itor)
+ {
+ LLScrollListItem* item = *data_itor;
+ LLGestureStep* step = (LLGestureStep*)item->getUserdata();
+ delete step;
+ step = NULL;
+ }
+}
+
+
+bool LLPreviewGesture::postBuild()
+{
+ setVisibleCallback(boost::bind(&LLPreviewGesture::onVisibilityChanged, this, _2));
+
+ LLLineEditor* edit;
+ LLComboBox* combo;
+ LLButton* btn;
+ LLScrollListCtrl* list;
+ LLTextBox* text;
+ LLCheckBoxCtrl* check;
+
+ edit = getChild<LLLineEditor>("desc");
+ edit->setKeystrokeCallback(onKeystrokeCommit, this);
+
+ edit = getChild<LLLineEditor>("trigger_editor");
+ edit->setKeystrokeCallback(onKeystrokeCommit, this);
+ edit->setCommitCallback(onCommitSetDirty, this);
+ edit->setCommitOnFocusLost(true);
+ edit->setIgnoreTab(true);
+ mTriggerEditor = edit;
+
+ text = getChild<LLTextBox>("replace_text");
+ text->setEnabled(false);
+ mReplaceText = text;
+
+ edit = getChild<LLLineEditor>("replace_editor");
+ edit->setEnabled(false);
+ edit->setKeystrokeCallback(onKeystrokeCommit, this);
+ edit->setCommitCallback(onCommitSetDirty, this);
+ edit->setCommitOnFocusLost(true);
+ edit->setIgnoreTab(true);
+ mReplaceEditor = edit;
+
+ combo = getChild<LLComboBox>( "modifier_combo");
+ combo->setCommitCallback(boost::bind(&LLPreviewGesture::onCommitKeyorModifier, this));
+ mModifierCombo = combo;
+
+ combo = getChild<LLComboBox>( "key_combo");
+ combo->setCommitCallback(boost::bind(&LLPreviewGesture::onCommitKeyorModifier, this));
+ mKeyCombo = combo;
+
+ list = getChild<LLScrollListCtrl>("library_list");
+ list->setCommitCallback(onCommitLibrary, this);
+ list->setDoubleClickCallback(onClickAdd, this);
+ mLibraryList = list;
+
+ btn = getChild<LLButton>( "add_btn");
+ btn->setClickedCallback(onClickAdd, this);
+ btn->setEnabled(false);
+ mAddBtn = btn;
+
+ btn = getChild<LLButton>( "up_btn");
+ btn->setClickedCallback(onClickUp, this);
+ btn->setEnabled(false);
+ mUpBtn = btn;
+
+ btn = getChild<LLButton>( "down_btn");
+ btn->setClickedCallback(onClickDown, this);
+ btn->setEnabled(false);
+ mDownBtn = btn;
+
+ btn = getChild<LLButton>( "delete_btn");
+ btn->setClickedCallback(onClickDelete, this);
+ btn->setEnabled(false);
+ mDeleteBtn = btn;
+
+ list = getChild<LLScrollListCtrl>("step_list");
+ list->setCommitCallback(onCommitStep, this);
+ mStepList = list;
+
+ // Options
+ mOptionsText = getChild<LLTextBox>("options_text");
+
+ combo = getChild<LLComboBox>( "animation_list");
+ combo->setVisible(false);
+ combo->setCommitCallback(onCommitAnimation, this);
+ mAnimationCombo = combo;
+
+ LLRadioGroup* group;
+ group = getChild<LLRadioGroup>("animation_trigger_type");
+ group->setVisible(false);
+ group->setCommitCallback(onCommitAnimationTrigger, this);
+ mAnimationRadio = group;
+
+ combo = getChild<LLComboBox>( "sound_list");
+ combo->setVisible(false);
+ combo->setCommitCallback(onCommitSound, this);
+ mSoundCombo = combo;
+
+ edit = getChild<LLLineEditor>("chat_editor");
+ edit->setVisible(false);
+ edit->setCommitCallback(onCommitChat, this);
+ //edit->setKeystrokeCallback(onKeystrokeCommit, this);
+ edit->setCommitOnFocusLost(true);
+ edit->setIgnoreTab(true);
+ mChatEditor = edit;
+
+ check = getChild<LLCheckBoxCtrl>( "wait_key_release_check");
+ check->setVisible(false);
+ check->setCommitCallback(onCommitWait, this);
+ mWaitKeyReleaseCheck = check;
+
+ check = getChild<LLCheckBoxCtrl>( "wait_anim_check");
+ check->setVisible(false);
+ check->setCommitCallback(onCommitWait, this);
+ mWaitAnimCheck = check;
+
+ check = getChild<LLCheckBoxCtrl>( "wait_time_check");
+ check->setVisible(false);
+ check->setCommitCallback(onCommitWait, this);
+ mWaitTimeCheck = check;
+
+ edit = getChild<LLLineEditor>("wait_time_editor");
+ edit->setEnabled(false);
+ edit->setVisible(false);
+ edit->setPrevalidate(LLTextValidate::validateFloat);
+// edit->setKeystrokeCallback(onKeystrokeCommit, this);
+ edit->setCommitOnFocusLost(true);
+ edit->setCommitCallback(onCommitWaitTime, this);
+ edit->setIgnoreTab(true);
+ mWaitTimeEditor = edit;
+
+ // Buttons at the bottom
+ check = getChild<LLCheckBoxCtrl>( "active_check");
+ check->setCommitCallback(onCommitActive, this);
+ mActiveCheck = check;
+
+ btn = getChild<LLButton>( "save_btn");
+ btn->setClickedCallback(onClickSave, this);
+ mSaveBtn = btn;
+
+ btn = getChild<LLButton>( "preview_btn");
+ btn->setClickedCallback(onClickPreview, this);
+ mPreviewBtn = btn;
+
+
+ // Populate the comboboxes
+ addModifiers();
+ addKeys();
+ addAnimations();
+ addSounds();
+
+ const LLInventoryItem* item = getItem();
+
+ if (item)
+ {
+ getChild<LLUICtrl>("desc")->setValue(item->getDescription());
+ getChild<LLLineEditor>("desc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
+ }
+
+ return LLPreview::postBuild();
+}
+
+
+void LLPreviewGesture::addModifiers()
+{
+ LLComboBox* combo = mModifierCombo;
+
+ combo->add( NONE_LABEL, ADD_BOTTOM );
+ combo->add( SHIFT_LABEL, ADD_BOTTOM );
+ combo->add( CTRL_LABEL, ADD_BOTTOM );
+ combo->setCurrentByIndex(0);
+}
+
+void LLPreviewGesture::addKeys()
+{
+ LLComboBox* combo = mKeyCombo;
+
+ combo->add( NONE_LABEL );
+ for (KEY key = KEY_F2; key <= KEY_F12; key++)
+ {
+ combo->add( LLKeyboard::stringFromKey(key), ADD_BOTTOM );
+ }
+ combo->setCurrentByIndex(0);
+}
+
+
+// TODO: Sort the legacy and non-legacy together?
+void LLPreviewGesture::addAnimations()
+{
+ LLComboBox* combo = mAnimationCombo;
+
+ combo->removeall();
+
+ std::string none_text = getString("none_text");
+
+ combo->add(none_text, LLUUID::null);
+
+ // Add all the default (legacy) animations
+ S32 i;
+ for (i = 0; i < gUserAnimStatesCount; ++i)
+ {
+ // Use the user-readable name
+ std::string label = LLAnimStateLabels::getStateLabel( gUserAnimStates[i].mName );
+ const LLUUID& id = gUserAnimStates[i].mID;
+ combo->add(label, id);
+ }
+
+ // Get all inventory items that are animations
+ LLViewerInventoryCategory::cat_array_t cats;
+ LLViewerInventoryItem::item_array_t items;
+ LLIsTypeWithPermissions is_copyable_animation(LLAssetType::AT_ANIMATION,
+ PERM_ITEM_UNRESTRICTED,
+ gAgent.getID(),
+ gAgent.getGroupID());
+ gInventory.collectDescendentsIf(gInventory.getRootFolderID(),
+ cats,
+ items,
+ LLInventoryModel::EXCLUDE_TRASH,
+ is_copyable_animation);
+
+ // Copy into something we can sort
+ std::vector<LLInventoryItem*> animations;
+
+ S32 count = items.size();
+ for(i = 0; i < count; ++i)
+ {
+ animations.push_back( items.at(i) );
+ }
+
+ // Do the sort
+ std::sort(animations.begin(), animations.end(), SortItemPtrsByName());
+
+ // And load up the combobox
+ std::vector<LLInventoryItem*>::iterator it;
+ for (it = animations.begin(); it != animations.end(); ++it)
+ {
+ LLInventoryItem* item = *it;
+
+ combo->add(item->getName(), item->getAssetUUID(), ADD_BOTTOM);
+ }
+}
+
+
+void LLPreviewGesture::addSounds()
+{
+ LLComboBox* combo = mSoundCombo;
+ combo->removeall();
+
+ std::string none_text = getString("none_text");
+
+ combo->add(none_text, LLUUID::null);
+
+ // Get all inventory items that are sounds
+ LLViewerInventoryCategory::cat_array_t cats;
+ LLViewerInventoryItem::item_array_t items;
+ LLIsTypeWithPermissions is_copyable_sound(LLAssetType::AT_SOUND,
+ PERM_ITEM_UNRESTRICTED,
+ gAgent.getID(),
+ gAgent.getGroupID());
+ gInventory.collectDescendentsIf(gInventory.getRootFolderID(),
+ cats,
+ items,
+ LLInventoryModel::EXCLUDE_TRASH,
+ is_copyable_sound);
+
+ // Copy sounds into something we can sort
+ std::vector<LLInventoryItem*> sounds;
+
+ S32 i;
+ S32 count = items.size();
+ for(i = 0; i < count; ++i)
+ {
+ sounds.push_back( items.at(i) );
+ }
+
+ // Do the sort
+ std::sort(sounds.begin(), sounds.end(), SortItemPtrsByName());
+
+ // And load up the combobox
+ std::vector<LLInventoryItem*>::iterator it;
+ for (it = sounds.begin(); it != sounds.end(); ++it)
+ {
+ LLInventoryItem* item = *it;
+
+ combo->add(item->getName(), item->getAssetUUID(), ADD_BOTTOM);
+ }
+}
+
+
+void LLPreviewGesture::refresh()
+{
+ LLPreview::refresh();
+ // If previewing or item is incomplete, all controls are disabled
+ LLViewerInventoryItem* item = (LLViewerInventoryItem*)getItem();
+ bool is_complete = item && item->isFinished();
+ if (mPreviewGesture || !is_complete)
+ {
+
+ getChildView("desc")->setEnabled(false);
+ //mDescEditor->setEnabled(false);
+ mTriggerEditor->setEnabled(false);
+ mReplaceText->setEnabled(false);
+ mReplaceEditor->setEnabled(false);
+ mModifierCombo->setEnabled(false);
+ mKeyCombo->setEnabled(false);
+ mLibraryList->setEnabled(false);
+ mAddBtn->setEnabled(false);
+ mUpBtn->setEnabled(false);
+ mDownBtn->setEnabled(false);
+ mDeleteBtn->setEnabled(false);
+ mStepList->setEnabled(false);
+ mOptionsText->setEnabled(false);
+ mAnimationCombo->setEnabled(false);
+ mAnimationRadio->setEnabled(false);
+ mSoundCombo->setEnabled(false);
+ mChatEditor->setEnabled(false);
+ mWaitKeyReleaseCheck->setEnabled(false);
+ mWaitAnimCheck->setEnabled(false);
+ mWaitTimeCheck->setEnabled(false);
+ mWaitTimeEditor->setEnabled(false);
+ mActiveCheck->setEnabled(false);
+ mSaveBtn->setEnabled(false);
+
+ // Make sure preview button is enabled, so we can stop it
+ mPreviewBtn->setEnabled(true);
+ return;
+ }
+
+ bool modifiable = item->getPermissions().allowModifyBy(gAgent.getID());
+
+ getChildView("desc")->setEnabled(modifiable);
+ mTriggerEditor->setEnabled(true);
+ mLibraryList->setEnabled(modifiable);
+ mStepList->setEnabled(modifiable);
+ mOptionsText->setEnabled(modifiable);
+ mAnimationCombo->setEnabled(modifiable);
+ mAnimationRadio->setEnabled(modifiable);
+ mSoundCombo->setEnabled(modifiable);
+ mChatEditor->setEnabled(modifiable);
+ mWaitKeyReleaseCheck->setEnabled(modifiable);
+ mWaitAnimCheck->setEnabled(modifiable);
+ mWaitTimeCheck->setEnabled(modifiable);
+ mWaitTimeEditor->setEnabled(modifiable);
+ mActiveCheck->setEnabled(true);
+
+ const std::string& trigger = mTriggerEditor->getText();
+ bool have_trigger = !trigger.empty();
+
+ const std::string& replace = mReplaceEditor->getText();
+ bool have_replace = !replace.empty();
+
+ LLScrollListItem* library_item = mLibraryList->getFirstSelected();
+ bool have_library = (library_item != NULL);
+
+ LLScrollListItem* step_item = mStepList->getFirstSelected();
+ S32 step_index = mStepList->getFirstSelectedIndex();
+ S32 step_count = mStepList->getItemCount();
+ bool have_step = (step_item != NULL);
+
+ mReplaceText->setEnabled(have_trigger || have_replace);
+ mReplaceEditor->setEnabled(have_trigger || have_replace);
+
+ mModifierCombo->setEnabled(true);
+ mKeyCombo->setEnabled(true);
+
+ mAddBtn->setEnabled(modifiable && have_library);
+ mUpBtn->setEnabled(modifiable && have_step && step_index > 0);
+ mDownBtn->setEnabled(modifiable && have_step && step_index < step_count-1);
+ mDeleteBtn->setEnabled(modifiable && have_step);
+
+ // Assume all not visible
+ mAnimationCombo->setVisible(false);
+ mAnimationRadio->setVisible(false);
+ mSoundCombo->setVisible(false);
+ mChatEditor->setVisible(false);
+ mWaitKeyReleaseCheck->setVisible(false);
+ mWaitAnimCheck->setVisible(false);
+ mWaitTimeCheck->setVisible(false);
+ mWaitTimeEditor->setVisible(false);
+
+ std::string optionstext;
+
+ if (have_step)
+ {
+ // figure out the type, show proper options, update text
+ LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
+ EStepType type = step->getType();
+
+ switch(type)
+ {
+ case STEP_ANIMATION:
+ {
+ LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
+ optionstext = getString("step_anim");
+ mAnimationCombo->setVisible(true);
+ mAnimationRadio->setVisible(true);
+ mAnimationRadio->setSelectedIndex((anim_step->mFlags & ANIM_FLAG_STOP) ? 1 : 0);
+ mAnimationCombo->setCurrentByID(anim_step->mAnimAssetID);
+ break;
+ }
+ case STEP_SOUND:
+ {
+ LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
+ optionstext = getString("step_sound");
+ mSoundCombo->setVisible(true);
+ mSoundCombo->setCurrentByID(sound_step->mSoundAssetID);
+ break;
+ }
+ case STEP_CHAT:
+ {
+ LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
+ optionstext = getString("step_chat");
+ mChatEditor->setVisible(true);
+ mChatEditor->setText(chat_step->mChatText);
+ break;
+ }
+ case STEP_WAIT:
+ {
+ LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
+ optionstext = getString("step_wait");
+ mWaitKeyReleaseCheck->setVisible(true);
+ mWaitKeyReleaseCheck->set(wait_step->mFlags & WAIT_FLAG_KEY_RELEASE);
+ mWaitAnimCheck->setVisible(true);
+ mWaitAnimCheck->set(wait_step->mFlags & WAIT_FLAG_ALL_ANIM);
+ mWaitTimeCheck->setVisible(true);
+ mWaitTimeCheck->set(wait_step->mFlags & WAIT_FLAG_TIME);
+ mWaitTimeEditor->setVisible(true);
+ std::string buffer = llformat("%.1f", (double)wait_step->mWaitSeconds);
+ mWaitTimeEditor->setText(buffer);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ mOptionsText->setText(optionstext);
+
+ bool active = LLGestureMgr::instance().isGestureActive(mItemUUID);
+ mActiveCheck->set(active);
+
+ // Can only preview if there are steps
+ mPreviewBtn->setEnabled(step_count > 0);
+
+ // And can only save if changes have been made
+ mSaveBtn->setEnabled(mDirty);
+ addAnimations();
+ addSounds();
+}
+
+
+void LLPreviewGesture::initDefaultGesture()
+{
+ LLScrollListItem* item;
+ item = addStep( STEP_ANIMATION );
+ LLGestureStepAnimation* anim = (LLGestureStepAnimation*)item->getUserdata();
+ anim->mAnimAssetID = ANIM_AGENT_HELLO;
+ anim->mAnimName = LLTrans::getString("Wave");
+ updateLabel(item);
+
+ item = addStep( STEP_WAIT );
+ LLGestureStepWait* wait = (LLGestureStepWait*)item->getUserdata();
+ wait->mFlags = WAIT_FLAG_ALL_ANIM;
+ updateLabel(item);
+
+ item = addStep( STEP_CHAT );
+ LLGestureStepChat* chat_step = (LLGestureStepChat*)item->getUserdata();
+ chat_step->mChatText = LLTrans::getString("HelloAvatar");
+ updateLabel(item);
+
+ // Start with item list selected
+ mStepList->selectFirstItem();
+
+ // this is *new* content, so we are dirty
+ mDirty = true;
+}
+
+
+void LLPreviewGesture::loadAsset()
+{
+ const LLInventoryItem* item = getItem();
+ if (!item)
+ {
+ // Don't set asset status here; we may not have set the item id yet
+ // (e.g. when this gets called initially)
+ //mAssetStatus = PREVIEW_ASSET_ERROR;
+ return;
+ }
+
+ LLUUID asset_id = item->getAssetUUID();
+ if (asset_id.isNull())
+ {
+ // Freshly created gesture, don't need to load asset.
+ // Blank gesture will be fine.
+ initDefaultGesture();
+ refresh();
+ mAssetStatus = PREVIEW_ASSET_LOADED;
+ return;
+ }
+
+ // TODO: Based on item->getPermissions().allow*
+ // could enable/disable UI.
+
+ // Copy the UUID, because the user might close the preview
+ // window if the download gets stalled.
+ LLUUID* item_idp = new LLUUID(mItemUUID);
+
+ const bool high_priority = true;
+ gAssetStorage->getAssetData(asset_id,
+ LLAssetType::AT_GESTURE,
+ onLoadComplete,
+ (void**)item_idp,
+ high_priority);
+ mAssetStatus = PREVIEW_ASSET_LOADING;
+}
+
+
+// static
+void LLPreviewGesture::onLoadComplete(const LLUUID& asset_uuid,
+ LLAssetType::EType type,
+ void* user_data, S32 status, LLExtStat ext_status)
+{
+ LLUUID* item_idp = (LLUUID*)user_data;
+
+ LLPreviewGesture* self = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", *item_idp);
+ if (self)
+ {
+ if (0 == status)
+ {
+ LLFileSystem file(asset_uuid, type, LLFileSystem::READ);
+ S32 size = file.getSize();
+
+ std::vector<char> buffer(size+1);
+ file.read((U8*)&buffer[0], size);
+ buffer[size] = '\0';
+
+ LLMultiGesture* gesture = new LLMultiGesture();
+
+ LLDataPackerAsciiBuffer dp(&buffer[0], size+1);
+ bool ok = gesture->deserialize(dp);
+
+ if (ok)
+ {
+ // Everything has been successful. Load up the UI.
+ self->loadUIFromGesture(gesture);
+
+ self->mStepList->selectFirstItem();
+
+ self->mDirty = false;
+ self->refresh();
+ self->refreshFromItem(); // to update description and title
+ }
+ else
+ {
+ LL_WARNS() << "Unable to load gesture" << LL_ENDL;
+ }
+
+ delete gesture;
+ gesture = NULL;
+
+ self->mAssetStatus = PREVIEW_ASSET_LOADED;
+ }
+ else
+ {
+ if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
+ LL_ERR_FILE_EMPTY == status)
+ {
+ LLDelayedGestureError::gestureMissing( *item_idp );
+ }
+ else
+ {
+ LLDelayedGestureError::gestureFailedToLoad( *item_idp );
+ }
+
+ LL_WARNS() << "Problem loading gesture: " << status << LL_ENDL;
+ self->mAssetStatus = PREVIEW_ASSET_ERROR;
+ }
+ }
+ delete item_idp;
+ item_idp = NULL;
+}
+
+
+void LLPreviewGesture::loadUIFromGesture(LLMultiGesture* gesture)
+{
+ /*LLInventoryItem* item = getItem();
+
+
+
+ if (item)
+ {
+ LLLineEditor* descEditor = getChild<LLLineEditor>("desc");
+ descEditor->setText(item->getDescription());
+ }*/
+
+ mTriggerEditor->setText(gesture->mTrigger);
+
+ mReplaceEditor->setText(gesture->mReplaceText);
+
+ switch (gesture->mMask)
+ {
+ default:
+ case MASK_NONE:
+ mModifierCombo->setSimple( NONE_LABEL );
+ break;
+ case MASK_SHIFT:
+ mModifierCombo->setSimple( SHIFT_LABEL );
+ break;
+ case MASK_CONTROL:
+ mModifierCombo->setSimple( CTRL_LABEL );
+ break;
+ }
+
+ mModifierCombo->setEnabledByValue(CTRL_LABEL, gesture->mKey != KEY_F10);
+
+ mKeyCombo->setCurrentByIndex(0);
+ if (gesture->mKey != KEY_NONE)
+ {
+ mKeyCombo->setSimple(LLKeyboard::stringFromKey(gesture->mKey));
+ }
+
+ mKeyCombo->setEnabledByValue(LLKeyboard::stringFromKey(KEY_F10), gesture->mMask != MASK_CONTROL);
+
+ // Make UI steps for each gesture step
+ S32 i;
+ S32 count = gesture->mSteps.size();
+ for (i = 0; i < count; ++i)
+ {
+ LLGestureStep* step = gesture->mSteps[i];
+
+ LLGestureStep* new_step = NULL;
+
+ switch(step->getType())
+ {
+ case STEP_ANIMATION:
+ {
+ LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
+ LLGestureStepAnimation* new_anim_step =
+ new LLGestureStepAnimation(*anim_step);
+ new_step = new_anim_step;
+ break;
+ }
+ case STEP_SOUND:
+ {
+ LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
+ LLGestureStepSound* new_sound_step =
+ new LLGestureStepSound(*sound_step);
+ new_step = new_sound_step;
+ break;
+ }
+ case STEP_CHAT:
+ {
+ LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
+ LLGestureStepChat* new_chat_step =
+ new LLGestureStepChat(*chat_step);
+ new_step = new_chat_step;
+ break;
+ }
+ case STEP_WAIT:
+ {
+ LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
+ LLGestureStepWait* new_wait_step =
+ new LLGestureStepWait(*wait_step);
+ new_step = new_wait_step;
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ if (!new_step) continue;
+
+ // Create an enabled item with this step
+ LLSD row;
+ row["columns"][0]["value"] = getLabel( new_step->getLabel());
+ row["columns"][0]["font"] = "SANSSERIF_SMALL";
+ LLScrollListItem* item = mStepList->addElement(row);
+ item->setUserdata(new_step);
+ }
+}
+
+// Helpful structure so we can look up the inventory item
+// after the save finishes.
+struct LLSaveInfo
+{
+ LLSaveInfo(const LLUUID& item_id, const LLUUID& object_id, const std::string& desc,
+ const LLTransactionID tid)
+ : mItemUUID(item_id), mObjectUUID(object_id), mDesc(desc), mTransactionID(tid)
+ {
+ }
+
+ LLUUID mItemUUID;
+ LLUUID mObjectUUID;
+ std::string mDesc;
+ LLTransactionID mTransactionID;
+};
+
+
+void LLPreviewGesture::finishInventoryUpload(LLUUID itemId, LLUUID newAssetId)
+{
+ // If this gesture is active, then we need to update the in-memory
+ // active map with the new pointer.
+ if (LLGestureMgr::instance().isGestureActive(itemId))
+ {
+ // Active gesture edited from menu.
+ LLGestureMgr::instance().replaceGesture(itemId, newAssetId);
+ gInventory.notifyObservers();
+ }
+
+ //gesture will have a new asset_id
+ LLPreviewGesture* previewp = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", LLSD(itemId));
+ if (previewp)
+ {
+ previewp->onUpdateSucceeded();
+ }
+}
+
+
+void LLPreviewGesture::saveIfNeeded()
+{
+ if (!gAssetStorage)
+ {
+ LL_WARNS() << "Can't save gesture, no asset storage system." << LL_ENDL;
+ return;
+ }
+
+ if (!mDirty)
+ {
+ return;
+ }
+
+ // Copy the UI into a gesture
+ LLMultiGesture* gesture = createGesture();
+
+ // Serialize the gesture
+ S32 maxSize = gesture->getMaxSerialSize();
+ char* buffer = new char[maxSize];
+
+ LLDataPackerAsciiBuffer dp(buffer, maxSize);
+
+ bool ok = gesture->serialize(dp);
+
+ if (dp.getCurrentSize() > 1000)
+ {
+ LLNotificationsUtil::add("GestureSaveFailedTooManySteps");
+
+ delete gesture;
+ gesture = NULL;
+ return;
+ }
+ else if (!ok)
+ {
+ LLNotificationsUtil::add("GestureSaveFailedTryAgain");
+ delete gesture;
+ gesture = NULL;
+ return;
+ }
+
+ LLAssetID assetId;
+ LLPreview::onCommit();
+ bool delayedUpload(false);
+
+ LLViewerInventoryItem* item = (LLViewerInventoryItem*) getItem();
+ if (item)
+ {
+ const LLViewerRegion* region = gAgent.getRegion();
+ if (!region)
+ {
+ LL_WARNS() << "Not connected to a region, cannot save gesture." << LL_ENDL;
+ return;
+ }
+ std::string agent_url = region->getCapability("UpdateGestureAgentInventory");
+ std::string task_url = region->getCapability("UpdateGestureTaskInventory");
+
+ if (!agent_url.empty() && !task_url.empty())
+ {
+ std::string url;
+ LLResourceUploadInfo::ptr_t uploadInfo;
+
+ if (mObjectUUID.isNull() && !agent_url.empty())
+ {
+ //need to disable the preview floater so item
+ //isn't re-saved before new asset arrives
+ //fake out refresh.
+ item->setComplete(false);
+ refresh();
+ item->setComplete(true);
+
+ uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(mItemUUID, LLAssetType::AT_GESTURE, buffer,
+ [](LLUUID itemId, LLUUID newAssetId, LLUUID, LLSD)
+ {
+ LLPreviewGesture::finishInventoryUpload(itemId, newAssetId);
+ },
+ nullptr);
+ url = agent_url;
+ }
+ else if (!mObjectUUID.isNull() && !task_url.empty())
+ {
+ uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(mObjectUUID, mItemUUID, LLAssetType::AT_GESTURE, buffer, nullptr, nullptr);
+ url = task_url;
+ }
+
+ if (!url.empty() && uploadInfo)
+ {
+ delayedUpload = true;
+
+ LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
+ }
+
+ }
+ else if (gAssetStorage)
+ {
+ // Every save gets a new UUID. Yup.
+ LLTransactionID tid;
+ tid.generate();
+ assetId = tid.makeAssetID(gAgent.getSecureSessionID());
+
+ LLFileSystem file(assetId, LLAssetType::AT_GESTURE, LLFileSystem::APPEND);
+
+ S32 size = dp.getCurrentSize();
+ file.write((U8*)buffer, size);
+
+ LLLineEditor* descEditor = getChild<LLLineEditor>("desc");
+ LLSaveInfo* info = new LLSaveInfo(mItemUUID, mObjectUUID, descEditor->getText(), tid);
+ gAssetStorage->storeAssetData(tid, LLAssetType::AT_GESTURE, onSaveComplete, info, false);
+ }
+
+ }
+
+ // If this gesture is active, then we need to update the in-memory
+ // active map with the new pointer.
+ if (!delayedUpload && LLGestureMgr::instance().isGestureActive(mItemUUID))
+ {
+ // gesture manager now owns the pointer
+ LLGestureMgr::instance().replaceGesture(mItemUUID, gesture, assetId);
+
+ // replaceGesture may deactivate other gestures so let the
+ // inventory know.
+ gInventory.notifyObservers();
+ }
+ else
+ {
+ // we're done with this gesture
+ delete gesture;
+ gesture = NULL;
+ }
+
+ mDirty = false;
+ // refresh will be called when callback
+ // if triggered when delayedUpload
+ if(!delayedUpload)
+ {
+ refresh();
+ }
+
+}
+
+
+// TODO: This is very similar to LLPreviewNotecard::onSaveComplete.
+// Could merge code.
+// static
+void LLPreviewGesture::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed)
+{
+ LLSaveInfo* info = (LLSaveInfo*)user_data;
+ if (info && (status == 0))
+ {
+ if(info->mObjectUUID.isNull())
+ {
+ // Saving into user inventory
+ LLViewerInventoryItem* item;
+ item = (LLViewerInventoryItem*)gInventory.getItem(info->mItemUUID);
+ if(item)
+ {
+ LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
+ new_item->setDescription(info->mDesc);
+ new_item->setTransactionID(info->mTransactionID);
+ new_item->setAssetUUID(asset_uuid);
+ new_item->updateServer(false);
+ gInventory.updateItem(new_item);
+ gInventory.notifyObservers();
+ }
+ else
+ {
+ LL_WARNS() << "Inventory item for gesture " << info->mItemUUID
+ << " is no longer in agent inventory." << LL_ENDL;
+ }
+ }
+ else
+ {
+ // Saving into in-world object inventory
+ LLViewerObject* object = gObjectList.findObject(info->mObjectUUID);
+ LLViewerInventoryItem* item = NULL;
+ if(object)
+ {
+ item = (LLViewerInventoryItem*)object->getInventoryObject(info->mItemUUID);
+ }
+ if(object && item)
+ {
+ item->setDescription(info->mDesc);
+ item->setAssetUUID(asset_uuid);
+ item->setTransactionID(info->mTransactionID);
+ object->updateInventory(item, TASK_INVENTORY_ITEM_KEY, false);
+ dialog_refresh_all();
+ }
+ else
+ {
+ LLNotificationsUtil::add("GestureSaveFailedObjectNotFound");
+ }
+ }
+
+ // Find our window and close it if requested.
+ LLPreviewGesture* previewp = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", info->mItemUUID);
+ if (previewp && previewp->mCloseAfterSave)
+ {
+ previewp->closeFloater();
+ }
+ }
+ else
+ {
+ LL_WARNS() << "Problem saving gesture: " << status << LL_ENDL;
+ LLSD args;
+ args["REASON"] = std::string(LLAssetStorage::getErrorString(status));
+ LLNotificationsUtil::add("GestureSaveFailedReason", args);
+ }
+ delete info;
+ info = NULL;
+}
+
+
+LLMultiGesture* LLPreviewGesture::createGesture()
+{
+ LLMultiGesture* gesture = new LLMultiGesture();
+
+ gesture->mTrigger = mTriggerEditor->getText();
+ gesture->mReplaceText = mReplaceEditor->getText();
+
+ const std::string& modifier = mModifierCombo->getSimple();
+ if (modifier == CTRL_LABEL)
+ {
+ gesture->mMask = MASK_CONTROL;
+ }
+ else if (modifier == SHIFT_LABEL)
+ {
+ gesture->mMask = MASK_SHIFT;
+ }
+ else
+ {
+ gesture->mMask = MASK_NONE;
+ }
+
+ if (mKeyCombo->getCurrentIndex() == 0)
+ {
+ gesture->mKey = KEY_NONE;
+ }
+ else
+ {
+ const std::string& key_string = mKeyCombo->getSimple();
+ LLKeyboard::keyFromString(key_string, &(gesture->mKey));
+ }
+
+ std::vector<LLScrollListItem*> data_list = mStepList->getAllData();
+ std::vector<LLScrollListItem*>::iterator data_itor;
+ for (data_itor = data_list.begin(); data_itor != data_list.end(); ++data_itor)
+ {
+ LLScrollListItem* item = *data_itor;
+ LLGestureStep* step = (LLGestureStep*)item->getUserdata();
+
+ switch(step->getType())
+ {
+ case STEP_ANIMATION:
+ {
+ // Copy UI-generated step into actual gesture step
+ LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
+ LLGestureStepAnimation* new_anim_step =
+ new LLGestureStepAnimation(*anim_step);
+ gesture->mSteps.push_back(new_anim_step);
+ break;
+ }
+ case STEP_SOUND:
+ {
+ // Copy UI-generated step into actual gesture step
+ LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
+ LLGestureStepSound* new_sound_step =
+ new LLGestureStepSound(*sound_step);
+ gesture->mSteps.push_back(new_sound_step);
+ break;
+ }
+ case STEP_CHAT:
+ {
+ // Copy UI-generated step into actual gesture step
+ LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
+ LLGestureStepChat* new_chat_step =
+ new LLGestureStepChat(*chat_step);
+ gesture->mSteps.push_back(new_chat_step);
+ break;
+ }
+ case STEP_WAIT:
+ {
+ // Copy UI-generated step into actual gesture step
+ LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
+ LLGestureStepWait* new_wait_step =
+ new LLGestureStepWait(*wait_step);
+ gesture->mSteps.push_back(new_wait_step);
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ return gesture;
+}
+
+
+void LLPreviewGesture::onCommitKeyorModifier()
+{
+ // SL-14139: ctrl-F10 is currently used to access top menu,
+ // so don't allow to bound gestures to this combination.
+
+ mKeyCombo->setEnabledByValue(LLKeyboard::stringFromKey(KEY_F10), mModifierCombo->getSimple() != CTRL_LABEL);
+ mModifierCombo->setEnabledByValue(CTRL_LABEL, mKeyCombo->getSimple() != LLKeyboard::stringFromKey(KEY_F10));
+ mDirty = true;
+ refresh();
+}
+
+// static
+void LLPreviewGesture::updateLabel(LLScrollListItem* item)
+{
+ LLGestureStep* step = (LLGestureStep*)item->getUserdata();
+
+ LLScrollListCell* cell = item->getColumn(0);
+ LLScrollListText* text_cell = (LLScrollListText*)cell;
+ std::string label = getLabel( step->getLabel());
+ text_cell->setText(label);
+}
+
+// static
+void LLPreviewGesture::onCommitSetDirty(LLUICtrl* ctrl, void* data)
+{
+ LLPreviewGesture* self = (LLPreviewGesture*)data;
+ self->mDirty = true;
+ self->refresh();
+}
+
+// static
+void LLPreviewGesture::onCommitLibrary(LLUICtrl* ctrl, void* data)
+{
+ LLPreviewGesture* self = (LLPreviewGesture*)data;
+
+ LLScrollListItem* library_item = self->mLibraryList->getFirstSelected();
+ if (library_item)
+ {
+ self->mStepList->deselectAllItems();
+ self->refresh();
+ }
+}
+
+
+// static
+void LLPreviewGesture::onCommitStep(LLUICtrl* ctrl, void* data)
+{
+ LLPreviewGesture* self = (LLPreviewGesture*)data;
+
+ LLScrollListItem* step_item = self->mStepList->getFirstSelected();
+ if (!step_item) return;
+
+ self->mLibraryList->deselectAllItems();
+ self->refresh();
+}
+
+
+// static
+void LLPreviewGesture::onCommitAnimation(LLUICtrl* ctrl, void* data)
+{
+ LLPreviewGesture* self = (LLPreviewGesture*)data;
+
+ LLScrollListItem* step_item = self->mStepList->getFirstSelected();
+ if (step_item)
+ {
+ LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
+ if (step->getType() == STEP_ANIMATION)
+ {
+ // Assign the animation name
+ LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
+ if (self->mAnimationCombo->getCurrentIndex() == 0)
+ {
+ anim_step->mAnimName.clear();
+ anim_step->mAnimAssetID.setNull();
+ }
+ else
+ {
+ anim_step->mAnimName = self->mAnimationCombo->getSimple();
+ anim_step->mAnimAssetID = self->mAnimationCombo->getCurrentID();
+ }
+ //anim_step->mFlags = 0x0;
+
+ // Update the UI label in the list
+ updateLabel(step_item);
+
+ self->mDirty = true;
+ self->refresh();
+ }
+ }
+}
+
+// static
+void LLPreviewGesture::onCommitAnimationTrigger(LLUICtrl* ctrl, void *data)
+{
+ LLPreviewGesture* self = (LLPreviewGesture*)data;
+
+ LLScrollListItem* step_item = self->mStepList->getFirstSelected();
+ if (step_item)
+ {
+ LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
+ if (step->getType() == STEP_ANIMATION)
+ {
+ LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
+ if (self->mAnimationRadio->getSelectedIndex() == 0)
+ {
+ // start
+ anim_step->mFlags &= ~ANIM_FLAG_STOP;
+ }
+ else
+ {
+ // stop
+ anim_step->mFlags |= ANIM_FLAG_STOP;
+ }
+ // Update the UI label in the list
+ updateLabel(step_item);
+
+ self->mDirty = true;
+ self->refresh();
+ }
+ }
+}
+
+// static
+void LLPreviewGesture::onCommitSound(LLUICtrl* ctrl, void* data)
+{
+ LLPreviewGesture* self = (LLPreviewGesture*)data;
+
+ LLScrollListItem* step_item = self->mStepList->getFirstSelected();
+ if (step_item)
+ {
+ LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
+ if (step->getType() == STEP_SOUND)
+ {
+ // Assign the sound name
+ LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
+ sound_step->mSoundName = self->mSoundCombo->getSimple();
+ sound_step->mSoundAssetID = self->mSoundCombo->getCurrentID();
+ sound_step->mFlags = 0x0;
+
+ // Update the UI label in the list
+ updateLabel(step_item);
+
+ self->mDirty = true;
+ self->refresh();
+ }
+ }
+}
+
+// static
+void LLPreviewGesture::onCommitChat(LLUICtrl* ctrl, void* data)
+{
+ LLPreviewGesture* self = (LLPreviewGesture*)data;
+
+ LLScrollListItem* step_item = self->mStepList->getFirstSelected();
+ if (!step_item) return;
+
+ LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
+ if (step->getType() != STEP_CHAT) return;
+
+ LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
+ chat_step->mChatText = self->mChatEditor->getText();
+ chat_step->mFlags = 0x0;
+
+ // Update the UI label in the list
+ updateLabel(step_item);
+
+ self->mDirty = true;
+ self->refresh();
+}
+
+// static
+void LLPreviewGesture::onCommitWait(LLUICtrl* ctrl, void* data)
+{
+ LLPreviewGesture* self = (LLPreviewGesture*)data;
+
+ LLScrollListItem* step_item = self->mStepList->getFirstSelected();
+ if (!step_item) return;
+
+ LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
+ if (step->getType() != STEP_WAIT) return;
+
+ LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
+ U32 flags = 0x0;
+ if (self->mWaitKeyReleaseCheck->get()) flags |= WAIT_FLAG_KEY_RELEASE;
+ if (self->mWaitAnimCheck->get()) flags |= WAIT_FLAG_ALL_ANIM;
+ if (self->mWaitTimeCheck->get()) flags |= WAIT_FLAG_TIME;
+ wait_step->mFlags = flags;
+
+ {
+ LLLocale locale(LLLocale::USER_LOCALE);
+
+ F32 wait_seconds = (F32)atof(self->mWaitTimeEditor->getText().c_str());
+ if (wait_seconds < 0.f) wait_seconds = 0.f;
+ if (wait_seconds > 3600.f) wait_seconds = 3600.f;
+ wait_step->mWaitSeconds = wait_seconds;
+ }
+
+ // Enable the input area if necessary
+ self->mWaitTimeEditor->setEnabled(self->mWaitTimeCheck->get());
+
+ // Update the UI label in the list
+ updateLabel(step_item);
+
+ self->mDirty = true;
+ self->refresh();
+}
+
+// static
+void LLPreviewGesture::onCommitWaitTime(LLUICtrl* ctrl, void* data)
+{
+ LLPreviewGesture* self = (LLPreviewGesture*)data;
+
+ LLScrollListItem* step_item = self->mStepList->getFirstSelected();
+ if (!step_item) return;
+
+ LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
+ if (step->getType() != STEP_WAIT) return;
+
+ self->mWaitTimeCheck->set(true);
+ onCommitWait(ctrl, data);
+}
+
+
+// static
+void LLPreviewGesture::onKeystrokeCommit(LLLineEditor* caller,
+ void* data)
+{
+ // Just commit every keystroke
+ onCommitSetDirty(caller, data);
+}
+
+// static
+void LLPreviewGesture::onClickAdd(void* data)
+{
+ LLPreviewGesture* self = (LLPreviewGesture*)data;
+
+ LLScrollListItem* library_item = self->mLibraryList->getFirstSelected();
+ if (!library_item) return;
+
+ S32 library_item_index = self->mLibraryList->getFirstSelectedIndex();
+
+ const LLScrollListCell* library_cell = library_item->getColumn(0);
+ const std::string& library_text = library_cell->getValue().asString();
+
+ if( library_item_index >= STEP_EOF )
+ {
+ LL_ERRS() << "Unknown step type: " << library_text << LL_ENDL;
+ return;
+ }
+
+ self->addStep( (EStepType)library_item_index );
+ self->mDirty = true;
+ self->refresh();
+}
+
+LLScrollListItem* LLPreviewGesture::addStep( const EStepType step_type )
+{
+ // Order of enum EStepType MUST match the library_list element in floater_preview_gesture.xml
+
+ LLGestureStep* step = NULL;
+ switch( step_type)
+ {
+ case STEP_ANIMATION:
+ step = new LLGestureStepAnimation();
+
+ break;
+ case STEP_SOUND:
+ step = new LLGestureStepSound();
+ break;
+ case STEP_CHAT:
+ step = new LLGestureStepChat();
+ break;
+ case STEP_WAIT:
+ step = new LLGestureStepWait();
+ break;
+ default:
+ LL_ERRS() << "Unknown step type: " << (S32)step_type << LL_ENDL;
+ return NULL;
+ }
+
+
+ // Create an enabled item with this step
+ LLSD row;
+ row["columns"][0]["value"] = getLabel(step->getLabel());
+ row["columns"][0]["font"] = "SANSSERIF_SMALL";
+ LLScrollListItem* step_item = mStepList->addElement(row);
+ step_item->setUserdata(step);
+
+ // And move selection to the list on the right
+ mLibraryList->deselectAllItems();
+ mStepList->deselectAllItems();
+
+ step_item->setSelected(true);
+
+ return step_item;
+}
+
+// static
+std::string LLPreviewGesture::getLabel(std::vector<std::string> labels)
+{
+ std::vector<std::string> v_labels = labels ;
+ std::string result("");
+
+ if( v_labels.size() != 2)
+ {
+ return result;
+ }
+
+ if(v_labels[0]=="Chat")
+ {
+ result=LLTrans::getString("Chat Message");
+ }
+ else if(v_labels[0]=="Sound")
+ {
+ result=LLTrans::getString("Sound");
+ }
+ else if(v_labels[0]=="Wait")
+ {
+ result=LLTrans::getString("Wait");
+ }
+ else if(v_labels[0]=="AnimFlagStop")
+ {
+ result=LLTrans::getString("AnimFlagStop");
+ }
+ else if(v_labels[0]=="AnimFlagStart")
+ {
+ result=LLTrans::getString("AnimFlagStart");
+ }
+
+ // lets localize action value
+ std::string action = v_labels[1];
+ if ("None" == action)
+ {
+ action = LLTrans::getString("GestureActionNone");
+ }
+ else if ("until animations are done" == action)
+ {
+ action = LLFloaterReg::getInstance("preview_gesture")->getChild<LLCheckBoxCtrl>("wait_anim_check")->getLabel();
+ }
+ result.append(action);
+ return result;
+
+}
+// static
+void LLPreviewGesture::onClickUp(void* data)
+{
+ LLPreviewGesture* self = (LLPreviewGesture*)data;
+
+ S32 selected_index = self->mStepList->getFirstSelectedIndex();
+ if (selected_index > 0)
+ {
+ self->mStepList->swapWithPrevious(selected_index);
+ self->mDirty = true;
+ self->refresh();
+ }
+}
+
+// static
+void LLPreviewGesture::onClickDown(void* data)
+{
+ LLPreviewGesture* self = (LLPreviewGesture*)data;
+
+ S32 selected_index = self->mStepList->getFirstSelectedIndex();
+ if (selected_index < 0) return;
+
+ S32 count = self->mStepList->getItemCount();
+ if (selected_index < count-1)
+ {
+ self->mStepList->swapWithNext(selected_index);
+ self->mDirty = true;
+ self->refresh();
+ }
+}
+
+// static
+void LLPreviewGesture::onClickDelete(void* data)
+{
+ LLPreviewGesture* self = (LLPreviewGesture*)data;
+
+ LLScrollListItem* item = self->mStepList->getFirstSelected();
+ S32 selected_index = self->mStepList->getFirstSelectedIndex();
+ if (item && selected_index >= 0)
+ {
+ LLGestureStep* step = (LLGestureStep*)item->getUserdata();
+ delete step;
+ step = NULL;
+
+ self->mStepList->deleteSingleItem(selected_index);
+
+ self->mDirty = true;
+ self->refresh();
+ }
+}
+
+// static
+void LLPreviewGesture::onCommitActive(LLUICtrl* ctrl, void* data)
+{
+ LLPreviewGesture* self = (LLPreviewGesture*)data;
+ if (!LLGestureMgr::instance().isGestureActive(self->mItemUUID))
+ {
+ LLGestureMgr::instance().activateGesture(self->mItemUUID);
+ }
+ else
+ {
+ LLGestureMgr::instance().deactivateGesture(self->mItemUUID);
+ }
+
+ // Make sure the (active) label in the inventory gets updated.
+ LLViewerInventoryItem* item = gInventory.getItem(self->mItemUUID);
+ if (item)
+ {
+ gInventory.updateItem(item);
+ gInventory.notifyObservers();
+ }
+
+ self->refresh();
+}
+
+// static
+void LLPreviewGesture::onClickSave(void* data)
+{
+ LLPreviewGesture* self = (LLPreviewGesture*)data;
+ self->saveIfNeeded();
+}
+
+// static
+void LLPreviewGesture::onClickPreview(void* data)
+{
+ LLPreviewGesture* self = (LLPreviewGesture*)data;
+
+ if (!self->mPreviewGesture)
+ {
+ // make temporary gesture
+ self->mPreviewGesture = self->createGesture();
+
+ // add a callback
+ self->mPreviewGesture->mDoneCallback = onDonePreview;
+ self->mPreviewGesture->mCallbackData = self;
+
+ // set the button title
+ self->mPreviewBtn->setLabel(self->getString("stop_txt"));
+
+ // play it, and delete when done
+ LLGestureMgr::instance().playGesture(self->mPreviewGesture);
+
+ self->refresh();
+ }
+ else
+ {
+ // Will call onDonePreview() below
+ LLGestureMgr::instance().stopGesture(self->mPreviewGesture);
+
+ self->refresh();
+ }
+}
+
+
+// static
+void LLPreviewGesture::onDonePreview(LLMultiGesture* gesture, void* data)
+{
+ LLPreviewGesture* self = (LLPreviewGesture*)data;
+
+ self->mPreviewBtn->setLabel(self->getString("preview_txt"));
+
+ delete self->mPreviewGesture;
+ self->mPreviewGesture = NULL;
+
+ self->refresh();
+}