PageRenderTime 174ms CodeModel.GetById 25ms app.highlight 137ms RepoModel.GetById 2ms app.codeStats 0ms

/indra/newview/llpreviewgesture.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1760 lines | 1329 code | 270 blank | 161 comment | 154 complexity | 353b1af643af857571a8c0252dc30f35 MD5 | raw file
   1/** 
   2 * @file llpreviewgesture.cpp
   3 * @brief Editing UI for inventory-based gestures.
   4 *
   5 * $LicenseInfo:firstyear=2004&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "llviewerprecompiledheaders.h"
  28#include "llpreviewgesture.h"
  29
  30#include "llagent.h"
  31#include "llanimstatelabels.h"
  32#include "llanimationstates.h"
  33#include "llappviewer.h"			// gVFS
  34#include "llassetuploadresponders.h"
  35#include "llcheckboxctrl.h"
  36#include "llcombobox.h"
  37#include "lldatapacker.h"
  38#include "lldelayedgestureerror.h"
  39#include "llfloaterreg.h"
  40#include "llgesturemgr.h"
  41#include "llinventorydefines.h"
  42#include "llinventoryfunctions.h"
  43#include "llinventorymodel.h"
  44#include "llinventorymodelbackgroundfetch.h"
  45#include "llkeyboard.h"
  46#include "llmultigesture.h"
  47#include "llnotificationsutil.h"
  48#include "llradiogroup.h"
  49#include "llresmgr.h"
  50#include "lltrans.h"
  51#include "llvfile.h"
  52#include "llviewerobjectlist.h"
  53#include "llviewerregion.h"
  54#include "llviewerstats.h"
  55
  56std::string NONE_LABEL;
  57std::string SHIFT_LABEL;
  58std::string CTRL_LABEL;
  59
  60void dialog_refresh_all();
  61
  62// used for getting
  63
  64class LLInventoryGestureAvailable : public LLInventoryCompletionObserver
  65{
  66public:
  67	LLInventoryGestureAvailable() {}
  68
  69protected:
  70	virtual void done();
  71};
  72
  73void LLInventoryGestureAvailable::done()
  74{
  75	for(uuid_vec_t::iterator it = mComplete.begin(); it != mComplete.end(); ++it)
  76	{
  77		LLPreviewGesture* preview = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", *it);
  78		if(preview)
  79		{
  80			preview->refresh();
  81		}
  82	}
  83	gInventory.removeObserver(this);
  84	delete this;
  85}
  86
  87// Used for sorting
  88struct SortItemPtrsByName
  89{
  90	bool operator()(const LLInventoryItem* i1, const LLInventoryItem* i2)
  91	{
  92		return (LLStringUtil::compareDict(i1->getName(), i2->getName()) < 0);
  93	}
  94};
  95
  96// static
  97LLPreviewGesture* LLPreviewGesture::show(const LLUUID& item_id, const LLUUID& object_id)
  98{
  99	LLPreviewGesture* preview = LLFloaterReg::showTypedInstance<LLPreviewGesture>("preview_gesture", LLSD(item_id), TAKE_FOCUS_YES);
 100	if (!preview)
 101	{
 102		return NULL;
 103	}
 104	
 105	preview->setObjectID(object_id);
 106	
 107	// Start speculative download of sounds and animations
 108	const LLUUID animation_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_ANIMATION);
 109	LLInventoryModelBackgroundFetch::instance().start(animation_folder_id);
 110
 111	const LLUUID sound_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_SOUND);
 112	LLInventoryModelBackgroundFetch::instance().start(sound_folder_id);
 113
 114	// this will call refresh when we have everything.
 115	LLViewerInventoryItem* item = (LLViewerInventoryItem*)preview->getItem();
 116	if (item && !item->isFinished())
 117	{
 118		LLInventoryGestureAvailable* observer;
 119		observer = new LLInventoryGestureAvailable();
 120		observer->watchItem(item_id);
 121		gInventory.addObserver(observer);
 122		item->fetchFromServer();
 123	}
 124	else
 125	{
 126		// not sure this is necessary.
 127		preview->refresh();
 128	}
 129
 130	return preview;
 131}
 132
 133void LLPreviewGesture::draw()
 134{
 135	// Skip LLPreview::draw() to avoid description update
 136	LLFloater::draw();
 137}
 138
 139// virtual
 140BOOL LLPreviewGesture::handleKeyHere(KEY key, MASK mask)
 141{
 142	if(('S' == key) && (MASK_CONTROL == (mask & MASK_CONTROL)))
 143	{
 144		saveIfNeeded();
 145		return TRUE;
 146	}
 147
 148	return LLPreview::handleKeyHere(key, mask);
 149}
 150
 151
 152// virtual
 153BOOL LLPreviewGesture::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 154										 EDragAndDropType cargo_type,
 155										 void* cargo_data,
 156										 EAcceptance* accept,
 157										 std::string& tooltip_msg)
 158{
 159	BOOL handled = TRUE;
 160	switch(cargo_type)
 161	{
 162	case DAD_ANIMATION:
 163	case DAD_SOUND:
 164		{
 165			// TODO: Don't allow this if you can't transfer the sound/animation
 166
 167			// make a script step
 168			LLInventoryItem* item = (LLInventoryItem*)cargo_data;
 169			if (item
 170				&& gInventory.getItem(item->getUUID()))
 171			{
 172				LLPermissions perm = item->getPermissions();
 173				if (!((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED))
 174				{
 175					*accept = ACCEPT_NO;
 176					if (tooltip_msg.empty())
 177					{
 178						tooltip_msg.assign("Only animations and sounds\n"
 179											"with unrestricted permissions\n"
 180											"can be added to a gesture.");
 181					}
 182					break;
 183				}
 184				else if (drop)
 185				{
 186					LLScrollListItem* line = NULL;
 187					if (cargo_type == DAD_ANIMATION)
 188					{
 189						line = addStep( STEP_ANIMATION );
 190						LLGestureStepAnimation* anim = (LLGestureStepAnimation*)line->getUserdata();
 191						anim->mAnimAssetID = item->getAssetUUID();
 192						anim->mAnimName = item->getName();
 193					}
 194					else if (cargo_type == DAD_SOUND)
 195					{
 196						line = addStep( STEP_SOUND );
 197						LLGestureStepSound* sound = (LLGestureStepSound*)line->getUserdata();
 198						sound->mSoundAssetID = item->getAssetUUID();
 199						sound->mSoundName = item->getName();
 200					}
 201					updateLabel(line);
 202					mDirty = TRUE;
 203					refresh();
 204				}
 205				*accept = ACCEPT_YES_COPY_MULTI;
 206			}
 207			else
 208			{
 209				// Not in user's inventory means it was in object inventory
 210				*accept = ACCEPT_NO;
 211			}
 212			break;
 213		}
 214	default:
 215		*accept = ACCEPT_NO;
 216		if (tooltip_msg.empty())
 217		{
 218			tooltip_msg.assign("Only animations and sounds\n"
 219								"can be added to a gesture.");
 220		}
 221		break;
 222	}
 223	return handled;
 224}
 225
 226
 227// virtual
 228BOOL LLPreviewGesture::canClose()
 229{
 230
 231	if(!mDirty || mForceClose)
 232	{
 233		return TRUE;
 234	}
 235	else
 236	{
 237		// Bring up view-modal dialog: Save changes? Yes, No, Cancel
 238		LLNotificationsUtil::add("SaveChanges", LLSD(), LLSD(),
 239			boost::bind(&LLPreviewGesture::handleSaveChangesDialog, this, _1, _2) );
 240		return FALSE;
 241	}
 242}
 243
 244// virtual
 245void LLPreviewGesture::onClose(bool app_quitting)
 246{
 247	LLGestureMgr::instance().stopGesture(mPreviewGesture);
 248}
 249
 250// virtual
 251void LLPreviewGesture::onUpdateSucceeded()
 252{
 253	refresh();
 254}
 255
 256void LLPreviewGesture::onVisibilityChange ( const LLSD& new_visibility )
 257{
 258	if (new_visibility.asBoolean())
 259	{
 260		refresh();
 261	}
 262}
 263
 264
 265bool LLPreviewGesture::handleSaveChangesDialog(const LLSD& notification, const LLSD& response)
 266{
 267	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
 268	switch(option)
 269	{
 270	case 0:  // "Yes"
 271		LLGestureMgr::instance().stopGesture(mPreviewGesture);
 272		mCloseAfterSave = TRUE;
 273		onClickSave(this);
 274		break;
 275
 276	case 1:  // "No"
 277		LLGestureMgr::instance().stopGesture(mPreviewGesture);
 278		mDirty = FALSE; // Force the dirty flag because user has clicked NO on confirm save dialog...
 279		closeFloater();
 280		break;
 281
 282	case 2: // "Cancel"
 283	default:
 284		// If we were quitting, we didn't really mean it.
 285		LLAppViewer::instance()->abortQuit();
 286		break;
 287	}
 288	return false;
 289}
 290
 291
 292LLPreviewGesture::LLPreviewGesture(const LLSD& key)
 293:	LLPreview(key),
 294	mTriggerEditor(NULL),
 295	mModifierCombo(NULL),
 296	mKeyCombo(NULL),
 297	mLibraryList(NULL),
 298	mAddBtn(NULL),
 299	mUpBtn(NULL),
 300	mDownBtn(NULL),
 301	mDeleteBtn(NULL),
 302	mStepList(NULL),
 303	mOptionsText(NULL),
 304	mAnimationRadio(NULL),
 305	mAnimationCombo(NULL),
 306	mSoundCombo(NULL),
 307	mChatEditor(NULL),
 308	mSaveBtn(NULL),
 309	mPreviewBtn(NULL),
 310	mPreviewGesture(NULL),
 311	mDirty(FALSE)
 312{
 313	NONE_LABEL =  LLTrans::getString("---");
 314	SHIFT_LABEL = LLTrans::getString("KBShift");
 315	CTRL_LABEL = LLTrans::getString("KBCtrl");
 316}
 317
 318
 319LLPreviewGesture::~LLPreviewGesture()
 320{
 321	// Userdata for all steps is a LLGestureStep we need to clean up
 322	std::vector<LLScrollListItem*> data_list = mStepList->getAllData();
 323	std::vector<LLScrollListItem*>::iterator data_itor;
 324	for (data_itor = data_list.begin(); data_itor != data_list.end(); ++data_itor)
 325	{
 326		LLScrollListItem* item = *data_itor;
 327		LLGestureStep* step = (LLGestureStep*)item->getUserdata();
 328		delete step;
 329		step = NULL;
 330	}
 331}
 332
 333
 334BOOL LLPreviewGesture::postBuild()
 335{
 336	setVisibleCallback(boost::bind(&LLPreviewGesture::onVisibilityChange, this, _2));
 337	
 338	LLLineEditor* edit;
 339	LLComboBox* combo;
 340	LLButton* btn;
 341	LLScrollListCtrl* list;
 342	LLTextBox* text;
 343	LLCheckBoxCtrl* check;
 344
 345	edit = getChild<LLLineEditor>("name");
 346	edit->setKeystrokeCallback(onKeystrokeCommit, this);
 347
 348	edit = getChild<LLLineEditor>("desc");
 349	edit->setKeystrokeCallback(onKeystrokeCommit, this);
 350
 351	edit = getChild<LLLineEditor>("trigger_editor");
 352	edit->setKeystrokeCallback(onKeystrokeCommit, this);
 353	edit->setCommitCallback(onCommitSetDirty, this);
 354	edit->setCommitOnFocusLost(TRUE);
 355	edit->setIgnoreTab(TRUE);
 356	mTriggerEditor = edit;
 357
 358	text = getChild<LLTextBox>("replace_text");
 359	text->setEnabled(FALSE);
 360	mReplaceText = text;
 361
 362	edit = getChild<LLLineEditor>("replace_editor");
 363	edit->setEnabled(FALSE);
 364	edit->setKeystrokeCallback(onKeystrokeCommit, this);
 365	edit->setCommitCallback(onCommitSetDirty, this);
 366	edit->setCommitOnFocusLost(TRUE);
 367	edit->setIgnoreTab(TRUE);
 368	mReplaceEditor = edit;
 369
 370	combo = getChild<LLComboBox>( "modifier_combo");
 371	combo->setCommitCallback(onCommitSetDirty, this);
 372	mModifierCombo = combo;
 373
 374	combo = getChild<LLComboBox>( "key_combo");
 375	combo->setCommitCallback(onCommitSetDirty, this);
 376	mKeyCombo = combo;
 377
 378	list = getChild<LLScrollListCtrl>("library_list");
 379	list->setCommitCallback(onCommitLibrary, this);
 380	list->setDoubleClickCallback(onClickAdd, this);
 381	mLibraryList = list;
 382
 383	btn = getChild<LLButton>( "add_btn");
 384	btn->setClickedCallback(onClickAdd, this);
 385	btn->setEnabled(FALSE);
 386	mAddBtn = btn;
 387
 388	btn = getChild<LLButton>( "up_btn");
 389	btn->setClickedCallback(onClickUp, this);
 390	btn->setEnabled(FALSE);
 391	mUpBtn = btn;
 392
 393	btn = getChild<LLButton>( "down_btn");
 394	btn->setClickedCallback(onClickDown, this);
 395	btn->setEnabled(FALSE);
 396	mDownBtn = btn;
 397
 398	btn = getChild<LLButton>( "delete_btn");
 399	btn->setClickedCallback(onClickDelete, this);
 400	btn->setEnabled(FALSE);
 401	mDeleteBtn = btn;
 402
 403	list = getChild<LLScrollListCtrl>("step_list");
 404	list->setCommitCallback(onCommitStep, this);
 405	mStepList = list;
 406
 407	// Options
 408	mOptionsText = getChild<LLTextBox>("options_text");
 409
 410	combo = getChild<LLComboBox>( "animation_list");
 411	combo->setVisible(FALSE);
 412	combo->setCommitCallback(onCommitAnimation, this);
 413	mAnimationCombo = combo;
 414
 415	LLRadioGroup* group;
 416	group = getChild<LLRadioGroup>("animation_trigger_type");
 417	group->setVisible(FALSE);
 418	group->setCommitCallback(onCommitAnimationTrigger, this);
 419	mAnimationRadio = group;
 420
 421	combo = getChild<LLComboBox>( "sound_list");
 422	combo->setVisible(FALSE);
 423	combo->setCommitCallback(onCommitSound, this);
 424	mSoundCombo = combo;
 425
 426	edit = getChild<LLLineEditor>("chat_editor");
 427	edit->setVisible(FALSE);
 428	edit->setCommitCallback(onCommitChat, this);
 429	//edit->setKeystrokeCallback(onKeystrokeCommit, this);
 430	edit->setCommitOnFocusLost(TRUE);
 431	edit->setIgnoreTab(TRUE);
 432	mChatEditor = edit;
 433
 434	check = getChild<LLCheckBoxCtrl>( "wait_anim_check");
 435	check->setVisible(FALSE);
 436	check->setCommitCallback(onCommitWait, this);
 437	mWaitAnimCheck = check;
 438
 439	check = getChild<LLCheckBoxCtrl>( "wait_time_check");
 440	check->setVisible(FALSE);
 441	check->setCommitCallback(onCommitWait, this);
 442	mWaitTimeCheck = check;
 443
 444	edit = getChild<LLLineEditor>("wait_time_editor");
 445	edit->setEnabled(FALSE);
 446	edit->setVisible(FALSE);
 447	edit->setPrevalidate(LLTextValidate::validateFloat);
 448//	edit->setKeystrokeCallback(onKeystrokeCommit, this);
 449	edit->setCommitOnFocusLost(TRUE);
 450	edit->setCommitCallback(onCommitWaitTime, this);
 451	edit->setIgnoreTab(TRUE);
 452	mWaitTimeEditor = edit;
 453
 454	// Buttons at the bottom
 455	check = getChild<LLCheckBoxCtrl>( "active_check");
 456	check->setCommitCallback(onCommitActive, this);
 457	mActiveCheck = check;
 458
 459	btn = getChild<LLButton>( "save_btn");
 460	btn->setClickedCallback(onClickSave, this);
 461	mSaveBtn = btn;
 462
 463	btn = getChild<LLButton>( "preview_btn");
 464	btn->setClickedCallback(onClickPreview, this);
 465	mPreviewBtn = btn;
 466
 467
 468	// Populate the comboboxes
 469	addModifiers();
 470	addKeys();
 471	addAnimations();
 472	addSounds();
 473
 474	const LLInventoryItem* item = getItem();
 475
 476	if (item) 
 477	{
 478		getChild<LLUICtrl>("desc")->setValue(item->getDescription());
 479		getChild<LLLineEditor>("desc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
 480		
 481		getChild<LLUICtrl>("name")->setValue(item->getName());
 482		getChild<LLLineEditor>("name")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
 483	}
 484
 485	return LLPreview::postBuild();
 486}
 487
 488
 489void LLPreviewGesture::addModifiers()
 490{
 491	LLComboBox* combo = mModifierCombo;
 492
 493	combo->add( NONE_LABEL,  ADD_BOTTOM );
 494	combo->add( SHIFT_LABEL, ADD_BOTTOM );
 495	combo->add( CTRL_LABEL,  ADD_BOTTOM );
 496	combo->setCurrentByIndex(0);
 497}
 498
 499void LLPreviewGesture::addKeys()
 500{
 501	LLComboBox* combo = mKeyCombo;
 502
 503	combo->add( NONE_LABEL );
 504	for (KEY key = KEY_F2; key <= KEY_F12; key++)
 505	{
 506		combo->add( LLKeyboard::stringFromKey(key), ADD_BOTTOM );
 507	}
 508	combo->setCurrentByIndex(0);
 509}
 510
 511
 512// TODO: Sort the legacy and non-legacy together?
 513void LLPreviewGesture::addAnimations()
 514{
 515	LLComboBox* combo = mAnimationCombo;
 516
 517	combo->removeall();
 518	
 519	std::string none_text = getString("none_text");
 520
 521	combo->add(none_text, LLUUID::null);
 522
 523	// Add all the default (legacy) animations
 524	S32 i;
 525	for (i = 0; i < gUserAnimStatesCount; ++i)
 526	{
 527		// Use the user-readable name
 528		std::string label = LLAnimStateLabels::getStateLabel( gUserAnimStates[i].mName );
 529		const LLUUID& id = gUserAnimStates[i].mID;
 530		combo->add(label, id);
 531	}
 532
 533	// Get all inventory items that are animations
 534	LLViewerInventoryCategory::cat_array_t cats;
 535	LLViewerInventoryItem::item_array_t items;
 536	LLIsTypeWithPermissions is_copyable_animation(LLAssetType::AT_ANIMATION,
 537													PERM_ITEM_UNRESTRICTED,
 538													gAgent.getID(),
 539													gAgent.getGroupID());
 540	gInventory.collectDescendentsIf(gInventory.getRootFolderID(),
 541									cats,
 542									items,
 543									LLInventoryModel::EXCLUDE_TRASH,
 544									is_copyable_animation);
 545
 546	// Copy into something we can sort
 547	std::vector<LLInventoryItem*> animations;
 548
 549	S32 count = items.count();
 550	for(i = 0; i < count; ++i)
 551	{
 552		animations.push_back( items.get(i) );
 553	}
 554
 555	// Do the sort
 556	std::sort(animations.begin(), animations.end(), SortItemPtrsByName());
 557
 558	// And load up the combobox
 559	std::vector<LLInventoryItem*>::iterator it;
 560	for (it = animations.begin(); it != animations.end(); ++it)
 561	{
 562		LLInventoryItem* item = *it;
 563
 564		combo->add(item->getName(), item->getAssetUUID(), ADD_BOTTOM);
 565	}
 566}
 567
 568
 569void LLPreviewGesture::addSounds()
 570{
 571	LLComboBox* combo = mSoundCombo;
 572	combo->removeall();
 573	
 574	std::string none_text = getString("none_text");
 575
 576	combo->add(none_text, LLUUID::null);
 577
 578	// Get all inventory items that are sounds
 579	LLViewerInventoryCategory::cat_array_t cats;
 580	LLViewerInventoryItem::item_array_t items;
 581	LLIsTypeWithPermissions is_copyable_sound(LLAssetType::AT_SOUND,
 582													PERM_ITEM_UNRESTRICTED,
 583													gAgent.getID(),
 584													gAgent.getGroupID());
 585	gInventory.collectDescendentsIf(gInventory.getRootFolderID(),
 586									cats,
 587									items,
 588									LLInventoryModel::EXCLUDE_TRASH,
 589									is_copyable_sound);
 590
 591	// Copy sounds into something we can sort
 592	std::vector<LLInventoryItem*> sounds;
 593
 594	S32 i;
 595	S32 count = items.count();
 596	for(i = 0; i < count; ++i)
 597	{
 598		sounds.push_back( items.get(i) );
 599	}
 600
 601	// Do the sort
 602	std::sort(sounds.begin(), sounds.end(), SortItemPtrsByName());
 603
 604	// And load up the combobox
 605	std::vector<LLInventoryItem*>::iterator it;
 606	for (it = sounds.begin(); it != sounds.end(); ++it)
 607	{
 608		LLInventoryItem* item = *it;
 609
 610		combo->add(item->getName(), item->getAssetUUID(), ADD_BOTTOM);
 611	}
 612}
 613
 614
 615void LLPreviewGesture::refresh()
 616{
 617	LLPreview::refresh();
 618	// If previewing or item is incomplete, all controls are disabled
 619	LLViewerInventoryItem* item = (LLViewerInventoryItem*)getItem();
 620	bool is_complete = (item && item->isFinished()) ? true : false;
 621	if (mPreviewGesture || !is_complete)
 622	{
 623		
 624		getChildView("desc")->setEnabled(FALSE);
 625		//mDescEditor->setEnabled(FALSE);
 626		mTriggerEditor->setEnabled(FALSE);
 627		mReplaceText->setEnabled(FALSE);
 628		mReplaceEditor->setEnabled(FALSE);
 629		mModifierCombo->setEnabled(FALSE);
 630		mKeyCombo->setEnabled(FALSE);
 631		mLibraryList->setEnabled(FALSE);
 632		mAddBtn->setEnabled(FALSE);
 633		mUpBtn->setEnabled(FALSE);
 634		mDownBtn->setEnabled(FALSE);
 635		mDeleteBtn->setEnabled(FALSE);
 636		mStepList->setEnabled(FALSE);
 637		mOptionsText->setEnabled(FALSE);
 638		mAnimationCombo->setEnabled(FALSE);
 639		mAnimationRadio->setEnabled(FALSE);
 640		mSoundCombo->setEnabled(FALSE);
 641		mChatEditor->setEnabled(FALSE);
 642		mWaitAnimCheck->setEnabled(FALSE);
 643		mWaitTimeCheck->setEnabled(FALSE);
 644		mWaitTimeEditor->setEnabled(FALSE);
 645		mActiveCheck->setEnabled(FALSE);
 646		mSaveBtn->setEnabled(FALSE);
 647
 648		// Make sure preview button is enabled, so we can stop it
 649		mPreviewBtn->setEnabled(TRUE);
 650		return;
 651	}
 652
 653	BOOL modifiable = item->getPermissions().allowModifyBy(gAgent.getID());
 654
 655	getChildView("desc")->setEnabled(modifiable);
 656	mTriggerEditor->setEnabled(TRUE);
 657	mLibraryList->setEnabled(modifiable);
 658	mStepList->setEnabled(modifiable);
 659	mOptionsText->setEnabled(modifiable);
 660	mAnimationCombo->setEnabled(modifiable);
 661	mAnimationRadio->setEnabled(modifiable);
 662	mSoundCombo->setEnabled(modifiable);
 663	mChatEditor->setEnabled(modifiable);
 664	mWaitAnimCheck->setEnabled(modifiable);
 665	mWaitTimeCheck->setEnabled(modifiable);
 666	mWaitTimeEditor->setEnabled(modifiable);
 667	mActiveCheck->setEnabled(TRUE);
 668
 669	const std::string& trigger = mTriggerEditor->getText();
 670	BOOL have_trigger = !trigger.empty();
 671
 672	const std::string& replace = mReplaceEditor->getText();
 673	BOOL have_replace = !replace.empty();
 674
 675	LLScrollListItem* library_item = mLibraryList->getFirstSelected();
 676	BOOL have_library = (library_item != NULL);
 677
 678	LLScrollListItem* step_item = mStepList->getFirstSelected();
 679	S32 step_index = mStepList->getFirstSelectedIndex();
 680	S32 step_count = mStepList->getItemCount();
 681	BOOL have_step = (step_item != NULL);
 682
 683	mReplaceText->setEnabled(have_trigger || have_replace);
 684	mReplaceEditor->setEnabled(have_trigger || have_replace);
 685
 686	mModifierCombo->setEnabled(TRUE);
 687	mKeyCombo->setEnabled(TRUE);
 688
 689	mAddBtn->setEnabled(modifiable && have_library);
 690	mUpBtn->setEnabled(modifiable && have_step && step_index > 0);
 691	mDownBtn->setEnabled(modifiable && have_step && step_index < step_count-1);
 692	mDeleteBtn->setEnabled(modifiable && have_step);
 693
 694	// Assume all not visible
 695	mAnimationCombo->setVisible(FALSE);
 696	mAnimationRadio->setVisible(FALSE);
 697	mSoundCombo->setVisible(FALSE);
 698	mChatEditor->setVisible(FALSE);
 699	mWaitAnimCheck->setVisible(FALSE);
 700	mWaitTimeCheck->setVisible(FALSE);
 701	mWaitTimeEditor->setVisible(FALSE);
 702
 703	std::string optionstext;
 704	
 705	if (have_step)
 706	{
 707		// figure out the type, show proper options, update text
 708		LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
 709		EStepType type = step->getType();
 710
 711		switch(type)
 712		{
 713		case STEP_ANIMATION:
 714			{
 715				LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
 716				optionstext = getString("step_anim");
 717				mAnimationCombo->setVisible(TRUE);
 718				mAnimationRadio->setVisible(TRUE);
 719				mAnimationRadio->setSelectedIndex((anim_step->mFlags & ANIM_FLAG_STOP) ? 1 : 0);
 720				mAnimationCombo->setCurrentByID(anim_step->mAnimAssetID);
 721				break;
 722			}
 723		case STEP_SOUND:
 724			{
 725				LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
 726				optionstext = getString("step_sound");
 727				mSoundCombo->setVisible(TRUE);
 728				mSoundCombo->setCurrentByID(sound_step->mSoundAssetID);
 729				break;
 730			}
 731		case STEP_CHAT:
 732			{
 733				LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
 734				optionstext = getString("step_chat");
 735				mChatEditor->setVisible(TRUE);
 736				mChatEditor->setText(chat_step->mChatText);
 737				break;
 738			}
 739		case STEP_WAIT:
 740			{
 741				LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
 742				optionstext = getString("step_wait");
 743				mWaitAnimCheck->setVisible(TRUE);
 744				mWaitAnimCheck->set(wait_step->mFlags & WAIT_FLAG_ALL_ANIM);
 745				mWaitTimeCheck->setVisible(TRUE);
 746				mWaitTimeCheck->set(wait_step->mFlags & WAIT_FLAG_TIME);
 747				mWaitTimeEditor->setVisible(TRUE);
 748				std::string buffer = llformat("%.1f", (double)wait_step->mWaitSeconds);
 749				mWaitTimeEditor->setText(buffer);
 750				break;
 751			}
 752		default:
 753			break;
 754		}
 755	}
 756	
 757	mOptionsText->setText(optionstext);
 758
 759	BOOL active = LLGestureMgr::instance().isGestureActive(mItemUUID);
 760	mActiveCheck->set(active);
 761
 762	// Can only preview if there are steps
 763	mPreviewBtn->setEnabled(step_count > 0);
 764
 765	// And can only save if changes have been made
 766	mSaveBtn->setEnabled(mDirty);
 767	addAnimations();
 768	addSounds();
 769}
 770
 771
 772void LLPreviewGesture::initDefaultGesture()
 773{
 774	LLScrollListItem* item;
 775	item = addStep( STEP_ANIMATION );
 776	LLGestureStepAnimation* anim = (LLGestureStepAnimation*)item->getUserdata();
 777	anim->mAnimAssetID = ANIM_AGENT_HELLO;
 778	anim->mAnimName = LLTrans::getString("Wave");
 779	updateLabel(item);
 780
 781	item = addStep( STEP_WAIT );
 782	LLGestureStepWait* wait = (LLGestureStepWait*)item->getUserdata();
 783	wait->mFlags = WAIT_FLAG_ALL_ANIM;
 784	updateLabel(item);
 785
 786	item = addStep( STEP_CHAT );
 787	LLGestureStepChat* chat_step = (LLGestureStepChat*)item->getUserdata();
 788	chat_step->mChatText =  LLTrans::getString("HelloAvatar");
 789	updateLabel(item);
 790
 791	// Start with item list selected
 792	mStepList->selectFirstItem();
 793
 794	// this is *new* content, so we are dirty
 795	mDirty = TRUE;
 796}
 797
 798
 799void LLPreviewGesture::loadAsset()
 800{
 801	const LLInventoryItem* item = getItem();
 802	if (!item) 
 803	{
 804		// Don't set asset status here; we may not have set the item id yet
 805		// (e.g. when this gets called initially)
 806		//mAssetStatus = PREVIEW_ASSET_ERROR;
 807		return;
 808	}
 809
 810	LLUUID asset_id = item->getAssetUUID();
 811	if (asset_id.isNull())
 812	{
 813		// Freshly created gesture, don't need to load asset.
 814		// Blank gesture will be fine.
 815		initDefaultGesture();
 816		refresh();
 817		mAssetStatus = PREVIEW_ASSET_LOADED;
 818		return;
 819	}
 820
 821	// TODO: Based on item->getPermissions().allow*
 822	// could enable/disable UI.
 823
 824	// Copy the UUID, because the user might close the preview
 825	// window if the download gets stalled.
 826	LLUUID* item_idp = new LLUUID(mItemUUID);
 827
 828	const BOOL high_priority = TRUE;
 829	gAssetStorage->getAssetData(asset_id,
 830								LLAssetType::AT_GESTURE,
 831								onLoadComplete,
 832								(void**)item_idp,
 833								high_priority);
 834	mAssetStatus = PREVIEW_ASSET_LOADING;
 835}
 836
 837
 838// static
 839void LLPreviewGesture::onLoadComplete(LLVFS *vfs,
 840									   const LLUUID& asset_uuid,
 841									   LLAssetType::EType type,
 842									   void* user_data, S32 status, LLExtStat ext_status)
 843{
 844	LLUUID* item_idp = (LLUUID*)user_data;
 845
 846	LLPreviewGesture* self = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", *item_idp);
 847	if (self)
 848	{
 849		if (0 == status)
 850		{
 851			LLVFile file(vfs, asset_uuid, type, LLVFile::READ);
 852			S32 size = file.getSize();
 853
 854			std::vector<char> buffer(size+1);
 855			file.read((U8*)&buffer[0], size);
 856			buffer[size] = '\0';
 857
 858			LLMultiGesture* gesture = new LLMultiGesture();
 859
 860			LLDataPackerAsciiBuffer dp(&buffer[0], size+1);
 861			BOOL ok = gesture->deserialize(dp);
 862
 863			if (ok)
 864			{
 865				// Everything has been successful.  Load up the UI.
 866				self->loadUIFromGesture(gesture);
 867
 868				self->mStepList->selectFirstItem();
 869
 870				self->mDirty = FALSE;
 871				self->refresh();
 872				self->refreshFromItem(); // to update description and title
 873			}
 874			else
 875			{
 876				llwarns << "Unable to load gesture" << llendl;
 877			}
 878
 879			delete gesture;
 880			gesture = NULL;
 881
 882			self->mAssetStatus = PREVIEW_ASSET_LOADED;
 883		}
 884		else
 885		{
 886			LLViewerStats::getInstance()->incStat( LLViewerStats::ST_DOWNLOAD_FAILED );
 887
 888			if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
 889				LL_ERR_FILE_EMPTY == status)
 890			{
 891				LLDelayedGestureError::gestureMissing( *item_idp );
 892			}
 893			else
 894			{
 895				LLDelayedGestureError::gestureFailedToLoad( *item_idp );
 896			}
 897
 898			llwarns << "Problem loading gesture: " << status << llendl;
 899			self->mAssetStatus = PREVIEW_ASSET_ERROR;
 900		}
 901	}
 902	delete item_idp;
 903	item_idp = NULL;
 904}
 905
 906
 907void LLPreviewGesture::loadUIFromGesture(LLMultiGesture* gesture)
 908{
 909	/*LLInventoryItem* item = getItem();
 910
 911
 912	
 913	if (item)
 914	{
 915		LLLineEditor* descEditor = getChild<LLLineEditor>("desc");
 916		descEditor->setText(item->getDescription());
 917	}*/
 918
 919	mTriggerEditor->setText(gesture->mTrigger);
 920
 921	mReplaceEditor->setText(gesture->mReplaceText);
 922
 923	switch (gesture->mMask)
 924	{
 925	default:
 926	  case MASK_NONE:
 927		mModifierCombo->setSimple( NONE_LABEL );
 928		break;
 929	  case MASK_SHIFT:
 930		mModifierCombo->setSimple( SHIFT_LABEL );
 931		break;
 932	  case MASK_CONTROL:
 933		mModifierCombo->setSimple( CTRL_LABEL );
 934		break;
 935	}
 936
 937	mKeyCombo->setCurrentByIndex(0);
 938	if (gesture->mKey != KEY_NONE)
 939	{
 940		mKeyCombo->setSimple(LLKeyboard::stringFromKey(gesture->mKey));
 941	}
 942
 943	// Make UI steps for each gesture step
 944	S32 i;
 945	S32 count = gesture->mSteps.size();
 946	for (i = 0; i < count; ++i)
 947	{
 948		LLGestureStep* step = gesture->mSteps[i];
 949
 950		LLGestureStep* new_step = NULL;
 951		
 952		switch(step->getType())
 953		{
 954		case STEP_ANIMATION:
 955			{
 956				LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
 957				LLGestureStepAnimation* new_anim_step =
 958					new LLGestureStepAnimation(*anim_step);
 959				new_step = new_anim_step;
 960				break;
 961			}
 962		case STEP_SOUND:
 963			{
 964				LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
 965				LLGestureStepSound* new_sound_step =
 966					new LLGestureStepSound(*sound_step);
 967				new_step = new_sound_step;
 968				break;
 969			}
 970		case STEP_CHAT:
 971			{
 972				LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
 973				LLGestureStepChat* new_chat_step =
 974					new LLGestureStepChat(*chat_step);
 975				new_step = new_chat_step;
 976				break;
 977			}
 978		case STEP_WAIT:
 979			{
 980				LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
 981				LLGestureStepWait* new_wait_step =
 982					new LLGestureStepWait(*wait_step);
 983				new_step = new_wait_step;
 984				break;
 985			}
 986		default:
 987			{
 988				break;
 989			}
 990		}
 991
 992		if (!new_step) continue;
 993
 994		// Create an enabled item with this step
 995		LLSD row;
 996		row["columns"][0]["value"] = getLabel( new_step->getLabel());
 997		row["columns"][0]["font"] = "SANSSERIF_SMALL";
 998		LLScrollListItem* item = mStepList->addElement(row);
 999		item->setUserdata(new_step);
1000	}
1001}
1002
1003// Helpful structure so we can look up the inventory item
1004// after the save finishes.
1005struct LLSaveInfo
1006{
1007	LLSaveInfo(const LLUUID& item_id, const LLUUID& object_id, const std::string& desc,
1008				const LLTransactionID tid)
1009		: mItemUUID(item_id), mObjectUUID(object_id), mDesc(desc), mTransactionID(tid)
1010	{
1011	}
1012
1013	LLUUID mItemUUID;
1014	LLUUID mObjectUUID;
1015	std::string mDesc;
1016	LLTransactionID mTransactionID;
1017};
1018
1019
1020void LLPreviewGesture::saveIfNeeded()
1021{
1022	if (!gAssetStorage)
1023	{
1024		llwarns << "Can't save gesture, no asset storage system." << llendl;
1025		return;
1026	}
1027
1028	if (!mDirty)
1029	{
1030		return;
1031	}
1032
1033	// Copy the UI into a gesture
1034	LLMultiGesture* gesture = createGesture();
1035
1036	// Serialize the gesture
1037	S32 max_size = gesture->getMaxSerialSize();
1038	char* buffer = new char[max_size];
1039
1040	LLDataPackerAsciiBuffer dp(buffer, max_size);
1041
1042	BOOL ok = gesture->serialize(dp);
1043
1044	if (dp.getCurrentSize() > 1000)
1045	{
1046		LLNotificationsUtil::add("GestureSaveFailedTooManySteps");
1047
1048		delete gesture;
1049		gesture = NULL;
1050	}
1051	else if (!ok)
1052	{
1053		LLNotificationsUtil::add("GestureSaveFailedTryAgain");
1054		delete gesture;
1055		gesture = NULL;
1056	}
1057	else
1058	{
1059		LLPreview::onCommit();
1060
1061		// Every save gets a new UUID.  Yup.
1062		LLTransactionID tid;
1063		LLAssetID asset_id;
1064		tid.generate();
1065		asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
1066
1067		LLVFile file(gVFS, asset_id, LLAssetType::AT_GESTURE, LLVFile::APPEND);
1068
1069		S32 size = dp.getCurrentSize();
1070		file.setMaxSize(size);
1071		file.write((U8*)buffer, size);
1072
1073		BOOL delayedUpload = FALSE;
1074
1075		// Upload that asset to the database
1076		LLViewerInventoryItem* item = (LLViewerInventoryItem*) getItem();
1077		if (item)
1078		{
1079			std::string agent_url = gAgent.getRegion()->getCapability("UpdateGestureAgentInventory");
1080			std::string task_url = gAgent.getRegion()->getCapability("UpdateGestureTaskInventory");
1081			if (mObjectUUID.isNull() && !agent_url.empty())
1082			{
1083				//need to disable the preview floater so item
1084				//isn't re-saved before new asset arrives
1085				//fake out refresh.
1086				item->setComplete(FALSE);
1087				refresh();				
1088				item->setComplete(TRUE);
1089
1090				// Saving into agent inventory
1091				LLSD body;
1092				body["item_id"] = mItemUUID;
1093				LLHTTPClient::post(agent_url, body,
1094					new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_GESTURE));
1095				delayedUpload = TRUE;
1096			}
1097			else if (!mObjectUUID.isNull() && !task_url.empty())
1098			{
1099				// Saving into task inventory
1100				LLSD body;
1101				body["task_id"] = mObjectUUID;
1102				body["item_id"] = mItemUUID;
1103				LLHTTPClient::post(task_url, body,
1104					new LLUpdateTaskInventoryResponder(body, asset_id, LLAssetType::AT_GESTURE));
1105			}
1106			else if (gAssetStorage)
1107			{
1108				LLLineEditor* descEditor = getChild<LLLineEditor>("desc");
1109				LLSaveInfo* info = new LLSaveInfo(mItemUUID, mObjectUUID, descEditor->getText(), tid);
1110				gAssetStorage->storeAssetData(tid, LLAssetType::AT_GESTURE, onSaveComplete, info, FALSE);
1111			}
1112		}
1113
1114		// If this gesture is active, then we need to update the in-memory
1115		// active map with the new pointer.
1116		if (!delayedUpload && LLGestureMgr::instance().isGestureActive(mItemUUID))
1117		{
1118			// gesture manager now owns the pointer
1119			LLGestureMgr::instance().replaceGesture(mItemUUID, gesture, asset_id);
1120
1121			// replaceGesture may deactivate other gestures so let the
1122			// inventory know.
1123			gInventory.notifyObservers();
1124		}
1125		else
1126		{
1127			// we're done with this gesture
1128			delete gesture;
1129			gesture = NULL;
1130		}
1131
1132		mDirty = FALSE;
1133		// refresh will be called when callback
1134		// if triggered when delayedUpload
1135		if(!delayedUpload)
1136		{
1137			refresh();
1138		}
1139	}
1140
1141	delete [] buffer;
1142	buffer = NULL;
1143}
1144
1145
1146// TODO: This is very similar to LLPreviewNotecard::onSaveComplete.
1147// Could merge code.
1148// static
1149void LLPreviewGesture::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed)
1150{
1151	LLSaveInfo* info = (LLSaveInfo*)user_data;
1152	if (info && (status == 0))
1153	{
1154		if(info->mObjectUUID.isNull())
1155		{
1156			// Saving into user inventory
1157			LLViewerInventoryItem* item;
1158			item = (LLViewerInventoryItem*)gInventory.getItem(info->mItemUUID);
1159			if(item)
1160			{
1161				LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
1162				new_item->setDescription(info->mDesc);
1163				new_item->setTransactionID(info->mTransactionID);
1164				new_item->setAssetUUID(asset_uuid);
1165				new_item->updateServer(FALSE);
1166				gInventory.updateItem(new_item);
1167				gInventory.notifyObservers();
1168			}
1169			else
1170			{
1171				llwarns << "Inventory item for gesture " << info->mItemUUID
1172						<< " is no longer in agent inventory." << llendl;
1173			}
1174		}
1175		else
1176		{
1177			// Saving into in-world object inventory
1178			LLViewerObject* object = gObjectList.findObject(info->mObjectUUID);
1179			LLViewerInventoryItem* item = NULL;
1180			if(object)
1181			{
1182				item = (LLViewerInventoryItem*)object->getInventoryObject(info->mItemUUID);
1183			}
1184			if(object && item)
1185			{
1186				item->setDescription(info->mDesc);
1187				item->setAssetUUID(asset_uuid);
1188				item->setTransactionID(info->mTransactionID);
1189				object->updateInventory(item, TASK_INVENTORY_ITEM_KEY, false);
1190				dialog_refresh_all();
1191			}
1192			else
1193			{
1194				LLNotificationsUtil::add("GestureSaveFailedObjectNotFound");
1195			}
1196		}
1197
1198		// Find our window and close it if requested.
1199		LLPreviewGesture* previewp = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", info->mItemUUID);
1200		if (previewp && previewp->mCloseAfterSave)
1201		{
1202			previewp->closeFloater();
1203		}
1204	}
1205	else
1206	{
1207		llwarns << "Problem saving gesture: " << status << llendl;
1208		LLSD args;
1209		args["REASON"] = std::string(LLAssetStorage::getErrorString(status));
1210		LLNotificationsUtil::add("GestureSaveFailedReason", args);
1211	}
1212	delete info;
1213	info = NULL;
1214}
1215
1216
1217LLMultiGesture* LLPreviewGesture::createGesture()
1218{
1219	LLMultiGesture* gesture = new LLMultiGesture();
1220
1221	gesture->mTrigger = mTriggerEditor->getText();
1222	gesture->mReplaceText = mReplaceEditor->getText();
1223
1224	const std::string& modifier = mModifierCombo->getSimple();
1225	if (modifier == CTRL_LABEL)
1226	{
1227		gesture->mMask = MASK_CONTROL;
1228	}
1229	else if (modifier == SHIFT_LABEL)
1230	{
1231		gesture->mMask = MASK_SHIFT;
1232	}
1233	else
1234	{
1235		gesture->mMask = MASK_NONE;
1236	}
1237
1238	if (mKeyCombo->getCurrentIndex() == 0)
1239	{
1240		gesture->mKey = KEY_NONE;
1241	}
1242	else
1243	{
1244		const std::string& key_string = mKeyCombo->getSimple();
1245		LLKeyboard::keyFromString(key_string, &(gesture->mKey));
1246	}
1247
1248	std::vector<LLScrollListItem*> data_list = mStepList->getAllData();
1249	std::vector<LLScrollListItem*>::iterator data_itor;
1250	for (data_itor = data_list.begin(); data_itor != data_list.end(); ++data_itor)
1251	{
1252		LLScrollListItem* item = *data_itor;
1253		LLGestureStep* step = (LLGestureStep*)item->getUserdata();
1254
1255		switch(step->getType())
1256		{
1257		case STEP_ANIMATION:
1258			{
1259				// Copy UI-generated step into actual gesture step
1260				LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
1261				LLGestureStepAnimation* new_anim_step =
1262					new LLGestureStepAnimation(*anim_step);
1263				gesture->mSteps.push_back(new_anim_step);
1264				break;
1265			}
1266		case STEP_SOUND:
1267			{
1268				// Copy UI-generated step into actual gesture step
1269				LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
1270				LLGestureStepSound* new_sound_step =
1271					new LLGestureStepSound(*sound_step);
1272				gesture->mSteps.push_back(new_sound_step);
1273				break;
1274			}
1275		case STEP_CHAT:
1276			{
1277				// Copy UI-generated step into actual gesture step
1278				LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
1279				LLGestureStepChat* new_chat_step =
1280					new LLGestureStepChat(*chat_step);
1281				gesture->mSteps.push_back(new_chat_step);
1282				break;
1283			}
1284		case STEP_WAIT:
1285			{
1286				// Copy UI-generated step into actual gesture step
1287				LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
1288				LLGestureStepWait* new_wait_step =
1289					new LLGestureStepWait(*wait_step);
1290				gesture->mSteps.push_back(new_wait_step);
1291				break;
1292			}
1293		default:
1294			{
1295				break;
1296			}
1297		}
1298	}
1299
1300	return gesture;
1301}
1302
1303
1304// static
1305void LLPreviewGesture::updateLabel(LLScrollListItem* item)
1306{
1307	LLGestureStep* step = (LLGestureStep*)item->getUserdata();
1308
1309	LLScrollListCell* cell = item->getColumn(0);
1310	LLScrollListText* text_cell = (LLScrollListText*)cell;
1311	std::string label = getLabel( step->getLabel());
1312	text_cell->setText(label);
1313}
1314
1315// static
1316void LLPreviewGesture::onCommitSetDirty(LLUICtrl* ctrl, void* data)
1317{
1318	LLPreviewGesture* self = (LLPreviewGesture*)data;
1319	self->mDirty = TRUE;
1320	self->refresh();
1321}
1322
1323// static
1324void LLPreviewGesture::onCommitLibrary(LLUICtrl* ctrl, void* data)
1325{
1326	LLPreviewGesture* self = (LLPreviewGesture*)data;
1327
1328	LLScrollListItem* library_item = self->mLibraryList->getFirstSelected();
1329	if (library_item)
1330	{
1331		self->mStepList->deselectAllItems();
1332		self->refresh();
1333	}
1334}
1335
1336
1337// static
1338void LLPreviewGesture::onCommitStep(LLUICtrl* ctrl, void* data)
1339{
1340	LLPreviewGesture* self = (LLPreviewGesture*)data;
1341
1342	LLScrollListItem* step_item = self->mStepList->getFirstSelected();
1343	if (!step_item) return;
1344
1345	self->mLibraryList->deselectAllItems();
1346	self->refresh();
1347}
1348
1349
1350// static
1351void LLPreviewGesture::onCommitAnimation(LLUICtrl* ctrl, void* data)
1352{
1353	LLPreviewGesture* self = (LLPreviewGesture*)data;
1354
1355	LLScrollListItem* step_item = self->mStepList->getFirstSelected();
1356	if (step_item)
1357	{
1358		LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
1359		if (step->getType() == STEP_ANIMATION)
1360		{
1361			// Assign the animation name
1362			LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
1363			if (self->mAnimationCombo->getCurrentIndex() == 0)
1364			{
1365				anim_step->mAnimName.clear();
1366				anim_step->mAnimAssetID.setNull();
1367			}
1368			else
1369			{
1370				anim_step->mAnimName = self->mAnimationCombo->getSimple();
1371				anim_step->mAnimAssetID = self->mAnimationCombo->getCurrentID();
1372			}
1373			//anim_step->mFlags = 0x0;
1374
1375			// Update the UI label in the list
1376			updateLabel(step_item);
1377
1378			self->mDirty = TRUE;
1379			self->refresh();
1380		}
1381	}
1382}
1383
1384// static
1385void LLPreviewGesture::onCommitAnimationTrigger(LLUICtrl* ctrl, void *data)
1386{
1387	LLPreviewGesture* self = (LLPreviewGesture*)data;
1388
1389	LLScrollListItem* step_item = self->mStepList->getFirstSelected();
1390	if (step_item)
1391	{
1392		LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
1393		if (step->getType() == STEP_ANIMATION)
1394		{
1395			LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
1396			if (self->mAnimationRadio->getSelectedIndex() == 0)
1397			{
1398				// start
1399				anim_step->mFlags &= ~ANIM_FLAG_STOP;
1400			}
1401			else
1402			{
1403				// stop
1404				anim_step->mFlags |= ANIM_FLAG_STOP;
1405			}
1406			// Update the UI label in the list
1407			updateLabel(step_item);
1408
1409			self->mDirty = TRUE;
1410			self->refresh();
1411		}
1412	}
1413}
1414
1415// static
1416void LLPreviewGesture::onCommitSound(LLUICtrl* ctrl, void* data)
1417{
1418	LLPreviewGesture* self = (LLPreviewGesture*)data;
1419
1420	LLScrollListItem* step_item = self->mStepList->getFirstSelected();
1421	if (step_item)
1422	{
1423		LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
1424		if (step->getType() == STEP_SOUND)
1425		{
1426			// Assign the sound name
1427			LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
1428			sound_step->mSoundName = self->mSoundCombo->getSimple();
1429			sound_step->mSoundAssetID = self->mSoundCombo->getCurrentID();
1430			sound_step->mFlags = 0x0;
1431
1432			// Update the UI label in the list
1433			updateLabel(step_item);
1434
1435			self->mDirty = TRUE;
1436			self->refresh();
1437		}
1438	}
1439}
1440
1441// static
1442void LLPreviewGesture::onCommitChat(LLUICtrl* ctrl, void* data)
1443{
1444	LLPreviewGesture* self = (LLPreviewGesture*)data;
1445
1446	LLScrollListItem* step_item = self->mStepList->getFirstSelected();
1447	if (!step_item) return;
1448
1449	LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
1450	if (step->getType() != STEP_CHAT) return;
1451
1452	LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
1453	chat_step->mChatText = self->mChatEditor->getText();
1454	chat_step->mFlags = 0x0;
1455
1456	// Update the UI label in the list
1457	updateLabel(step_item);
1458
1459	self->mDirty = TRUE;
1460	self->refresh();
1461}
1462
1463// static
1464void LLPreviewGesture::onCommitWait(LLUICtrl* ctrl, void* data)
1465{
1466	LLPreviewGesture* self = (LLPreviewGesture*)data;
1467
1468	LLScrollListItem* step_item = self->mStepList->getFirstSelected();
1469	if (!step_item) return;
1470
1471	LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
1472	if (step->getType() != STEP_WAIT) return;
1473
1474	LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
1475	U32 flags = 0x0;
1476	if (self->mWaitAnimCheck->get()) flags |= WAIT_FLAG_ALL_ANIM;
1477	if (self->mWaitTimeCheck->get()) flags |= WAIT_FLAG_TIME;
1478	wait_step->mFlags = flags;
1479
1480	{
1481		LLLocale locale(LLLocale::USER_LOCALE);
1482
1483		F32 wait_seconds = (F32)atof(self->mWaitTimeEditor->getText().c_str());
1484		if (wait_seconds < 0.f) wait_seconds = 0.f;
1485		if (wait_seconds > 3600.f) wait_seconds = 3600.f;
1486		wait_step->mWaitSeconds = wait_seconds;
1487	}
1488
1489	// Enable the input area if necessary
1490	self->mWaitTimeEditor->setEnabled(self->mWaitTimeCheck->get());
1491
1492	// Update the UI label in the list
1493	updateLabel(step_item);
1494
1495	self->mDirty = TRUE;
1496	self->refresh();
1497}
1498
1499// static
1500void LLPreviewGesture::onCommitWaitTime(LLUICtrl* ctrl, void* data)
1501{
1502	LLPreviewGesture* self = (LLPreviewGesture*)data;
1503
1504	LLScrollListItem* step_item = self->mStepList->getFirstSelected();
1505	if (!step_item) return;
1506
1507	LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
1508	if (step->getType() != STEP_WAIT) return;
1509
1510	self->mWaitTimeCheck->set(TRUE);
1511	onCommitWait(ctrl, data);
1512}
1513
1514
1515// static
1516void LLPreviewGesture::onKeystrokeCommit(LLLineEditor* caller,
1517										 void* data)
1518{
1519	// Just commit every keystroke
1520	onCommitSetDirty(caller, data);
1521}
1522
1523// static
1524void LLPreviewGesture::onClickAdd(void* data)
1525{
1526	LLPreviewGesture* self = (LLPreviewGesture*)data;
1527
1528	LLScrollListItem* library_item = self->mLibraryList->getFirstSelected();
1529	if (!library_item) return;
1530
1531	S32 library_item_index = self->mLibraryList->getFirstSelectedIndex();
1532
1533	const LLScrollListCell* library_cell = library_item->getColumn(0);
1534	const std::string& library_text = library_cell->getValue().asString();
1535
1536	if( library_item_index >= STEP_EOF )
1537	{
1538		llerrs << "Unknown step type: " << library_text << llendl;
1539		return;
1540	}
1541
1542	self->addStep( (EStepType)library_item_index );
1543	self->mDirty = TRUE;
1544	self->refresh();
1545}
1546
1547LLScrollListItem* LLPreviewGesture::addStep( const EStepType step_type )
1548{
1549	// Order of enum EStepType MUST match the library_list element in floater_preview_gesture.xml
1550
1551	LLGestureStep* step = NULL;
1552	switch( step_type)
1553	{
1554		case STEP_ANIMATION:
1555			step = new LLGestureStepAnimation();
1556
1557			break;
1558		case STEP_SOUND:
1559			step = new LLGestureStepSound();
1560			break;
1561		case STEP_CHAT:
1562			step = new LLGestureStepChat();	
1563			break;
1564		case STEP_WAIT:
1565			step = new LLGestureStepWait();			
1566			break;
1567		default:
1568			llerrs << "Unknown step type: " << (S32)step_type << llendl;
1569			return NULL;
1570	}
1571
1572
1573	// Create an enabled item with this step
1574	LLSD row;
1575	row["columns"][0]["value"] = getLabel(step->getLabel());
1576	row["columns"][0]["font"] = "SANSSERIF_SMALL";
1577	LLScrollListItem* step_item = mStepList->addElement(row);
1578	step_item->setUserdata(step);
1579
1580	// And move selection to the list on the right
1581	mLibraryList->deselectAllItems();
1582	mStepList->deselectAllItems();
1583
1584	step_item->setSelected(TRUE);
1585
1586	return step_item;
1587}
1588
1589// static
1590std::string LLPreviewGesture::getLabel(std::vector<std::string> labels)
1591{
1592	std::vector<std::string> v_labels = labels ;
1593	std::string result("");
1594	
1595	if( v_labels.size() != 2)
1596	{
1597		return result;
1598	}
1599	
1600	if(v_labels[0]=="Chat")
1601	{
1602		result=LLTrans::getString("Chat Message");
1603	}
1604    else if(v_labels[0]=="Sound")	
1605	{
1606		result=LLTrans::getString("Sound");
1607	}
1608	else if(v_labels[0]=="Wait")
1609	{
1610		result=LLTrans::getString("Wait");
1611	}
1612	else if(v_labels[0]=="AnimFlagStop")
1613	{
1614		result=LLTrans::getString("AnimFlagStop");
1615	}
1616	else if(v_labels[0]=="AnimFlagStart")
1617	{
1618		result=LLTrans::getString("AnimFlagStart");
1619	}
1620
1621	// lets localize action value
1622	std::string action = v_labels[1];
1623	if ("None" == action)
1624	{
1625		action = LLTrans::getString("GestureActionNone");
1626	}
1627	else if ("until animations are done" == action)
1628	{
1629		action = LLFloaterReg::getInstance("preview_gesture")->getChild<LLCheckBoxCtrl>("wait_anim_check")->getLabel();
1630	}
1631	result.append(action);
1632	return result;
1633	
1634}
1635// static
1636void LLPreviewGesture::onClickUp(void* data)
1637{
1638	LLPreviewGesture* self = (LLPreviewGesture*)data;
1639
1640	S32 selected_index = self->mStepList->getFirstSelectedIndex();
1641	if (selected_index > 0)
1642	{
1643		self->mStepList->swapWithPrevious(selected_index);
1644		self->mDirty = TRUE;
1645		self->refresh();
1646	}
1647}
1648
1649// static
1650void LLPreviewGesture::onClickDown(void* data)
1651{
1652	LLPreviewGesture* self = (LLPreviewGesture*)data;
1653
1654	S32 selected_index = self->mStepList->getFirstSelectedIndex();
1655	if (selected_index < 0) return;
1656
1657	S32 count = self->mStepList->getItemCount();
1658	if (selected_index < count-1)
1659	{
1660		self->mStepList->swapWithNext(selected_index);
1661		self->mDirty = TRUE;
1662		self->refresh();
1663	}
1664}
1665
1666// static
1667void LLPreviewGesture::onClickDelete(void* data)
1668{
1669	LLPreviewGesture* self = (LLPreviewGesture*)data;
1670
1671	LLScrollListItem* item = self->mStepList->getFirstSelected();
1672	S32 selected_index = self->mStepList->getFirstSelectedIndex();
1673	if (item && selected_index >= 0)
1674	{
1675		LLGestureStep* step = (LLGestureStep*)item->getUserdata();
1676		delete step;
1677		step = NULL;
1678
1679		self->mStepList->deleteSingleItem(selected_index);
1680
1681		self->mDirty = TRUE;
1682		self->refresh();
1683	}
1684}
1685
1686// static
1687void LLPreviewGesture::onCommitActive(LLUICtrl* ctrl, void* data)
1688{
1689	LLPreviewGesture* self = (LLPreviewGesture*)data;
1690	if (!LLGestureMgr::instance().isGestureActive(self->mItemUUID))
1691	{
1692		LLGestureMgr::instance().activateGesture(self->mItemUUID);
1693	}
1694	else
1695	{
1696		LLGestureMgr::instance().deactivateGesture(self->mItemUUID);
1697	}
1698
1699	// Make sure the (active) label in the inventory gets updated.
1700	LLViewerInventoryItem* item = gInventory.getItem(self->mItemUUID);
1701	if (item)
1702	{
1703		gInventory.updateItem(item);
1704		gInventory.notifyObservers();
1705	}
1706
1707	self->refresh();
1708}
1709
1710// static
1711void LLPreviewGesture::onClickSave(void* data)
1712{
1713	LLPreviewGesture* self = (LLPreviewGesture*)data;
1714	self->saveIfNeeded();
1715}
1716
1717// static
1718void LLPreviewGesture::onClickPreview(void* data)
1719{
1720	LLPreviewGesture* self = (LLPreviewGesture*)data;
1721
1722	if (!self->mPreviewGesture)
1723	{
1724		// make temporary gesture
1725		self->mPreviewGesture = self->createGesture();
1726
1727		// add a callback
1728		self->mPreviewGesture->mDoneCallback = onDonePreview;
1729		self->mPreviewGesture->mCallbackData = self;
1730
1731		// set the button title
1732		self->mPreviewBtn->setLabel(self->getString("stop_txt"));
1733
1734		// play it, and delete when done
1735		LLGestureMgr::instance().playGesture(self->mPreviewGesture);
1736
1737		self->refresh();
1738	}
1739	else
1740	{
1741		// Will call onDonePreview() below
1742		LLGestureMgr::instance().stopGesture(self->mPreviewGesture);
1743
1744		self->refresh();
1745	}
1746}
1747
1748
1749// static
1750void LLPreviewGesture::onDonePreview(LLMultiGesture* gesture, void* data)
1751{
1752	LLPreviewGesture* self = (LLPreviewGesture*)data;
1753
1754	self->mPreviewBtn->setLabel(self->getString("preview_txt"));
1755
1756	delete self->mPreviewGesture;
1757	self->mPreviewGesture = NULL;
1758
1759	self->refresh();
1760}