llpreviewgesture.cpp 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800
  1. /**
  2. * @file llpreviewgesture.cpp
  3. * @brief Editing UI for inventory-based gestures.
  4. *
  5. * $LicenseInfo:firstyear=2004&license=viewergpl$
  6. *
  7. * Copyright (c) 2004-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llpreviewgesture.h"
  34. #include "llanimationstates.h"
  35. #include "llbutton.h"
  36. #include "llcheckboxctrl.h"
  37. #include "llcombobox.h"
  38. #include "lldatapacker.h"
  39. #include "lldir.h"
  40. #include "llfilesystem.h"
  41. #include "llkeyboard.h"
  42. #include "lllineeditor.h"
  43. #include "lllocale.h"
  44. #include "llmultigesture.h"
  45. #include "llnotifications.h"
  46. #include "llradiogroup.h"
  47. #include "llscrolllistctrl.h"
  48. #include "lltextbox.h"
  49. #include "lltrans.h" // LLAnimStateLabels::getStateLabel()
  50. #include "lluictrlfactory.h"
  51. #include "llagent.h"
  52. #include "llappviewer.h"
  53. #include "llfloatergesture.h" // For some label constants
  54. #include "llgesturemgr.h"
  55. #include "llinventorymodel.h"
  56. #include "llinventorymodelfetch.h"
  57. #include "llselectmgr.h" // For dialog_refresh_all()
  58. #include "llviewerassetupload.h"
  59. #include "llviewerinventory.h"
  60. #include "llviewerobjectlist.h"
  61. #include "llviewerstats.h"
  62. // *TODO: Translate ?
  63. const std::string NONE_LABEL = "---";
  64. const std::string SHIFT_LABEL = "Shift";
  65. const std::string CTRL_LABEL = "Ctrl";
  66. class LLInventoryGestureAvailable final : public LLInventoryCompletionObserver
  67. {
  68. public:
  69. LLInventoryGestureAvailable() {}
  70. protected:
  71. void done() override;
  72. };
  73. void LLInventoryGestureAvailable::done()
  74. {
  75. for (U32 i = 0, count = mComplete.size(); i < count; ++i)
  76. {
  77. LLPreview* preview = LLPreview::find(mComplete[i]);
  78. if (preview)
  79. {
  80. preview->refresh();
  81. }
  82. }
  83. gInventory.removeObserver(this);
  84. delete this;
  85. }
  86. // Used for sorting
  87. struct SortItemPtrsByName
  88. {
  89. bool operator()(const LLInventoryItem* i1, const LLInventoryItem* i2)
  90. {
  91. return (LLStringUtil::compareDict(i1->getName(), i2->getName()) < 0);
  92. }
  93. };
  94. //static
  95. LLPreviewGesture* LLPreviewGesture::show(const std::string& title,
  96. const LLUUID& item_id,
  97. const LLUUID& object_id,
  98. bool take_focus)
  99. {
  100. LLPreviewGesture* previewp = (LLPreviewGesture*)LLPreview::find(item_id);
  101. if (previewp)
  102. {
  103. previewp->open();
  104. if (take_focus)
  105. {
  106. previewp->setFocus(true);
  107. }
  108. return previewp;
  109. }
  110. LLPreviewGesture* self = new LLPreviewGesture();
  111. // Finish internal construction
  112. self->init(item_id, object_id);
  113. // Builds and adds to gFloaterViewp
  114. LLUICtrlFactory::getInstance()->buildFloater(self,
  115. "floater_preview_gesture.xml");
  116. self->setTitle(title);
  117. // Move window to top-left of screen
  118. LLMultiFloater* hostp = self->getHost();
  119. if (!hostp)
  120. {
  121. LLRect r = self->getRect();
  122. LLRect screen = gFloaterViewp->getRect();
  123. r.setLeftTopAndSize(0, screen.getHeight(), r.getWidth(), r.getHeight());
  124. self->setRect(r);
  125. }
  126. else
  127. {
  128. // re-add to host to update title
  129. hostp->addFloater(self, true);
  130. }
  131. // Start speculative download of sounds and animations
  132. const LLUUID animation_folder_id =
  133. gInventory.findCategoryUUIDForType(LLFolderType::FT_ANIMATION);
  134. LLInventoryModelFetch::getInstance()->start(animation_folder_id);
  135. const LLUUID sound_folder_id =
  136. gInventory.findCategoryUUIDForType(LLFolderType::FT_SOUND);
  137. LLInventoryModelFetch::getInstance()->start(sound_folder_id);
  138. // This will call refresh when we have everything.
  139. LLViewerInventoryItem* item = (LLViewerInventoryItem*)self->getItem();
  140. if (item && !item->isFinished())
  141. {
  142. LLInventoryGestureAvailable* observer;
  143. observer = new LLInventoryGestureAvailable();
  144. observer->watchItem(item_id);
  145. gInventory.addObserver(observer);
  146. item->fetchFromServer();
  147. }
  148. else
  149. {
  150. // not sure this is necessary.
  151. self->refresh();
  152. }
  153. if (take_focus)
  154. {
  155. self->setFocus(true);
  156. }
  157. return self;
  158. }
  159. // virtual
  160. bool LLPreviewGesture::handleKeyHere(KEY key, MASK mask)
  161. {
  162. if (key == 'S' && (mask & MASK_CONTROL))
  163. {
  164. saveIfNeeded();
  165. return true;
  166. }
  167. return LLPreview::handleKeyHere(key, mask);
  168. }
  169. // virtual
  170. bool LLPreviewGesture::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop,
  171. EDragAndDropType cargo_type,
  172. void* cargo_data,
  173. EAcceptance* accept,
  174. std::string& tooltip_msg)
  175. {
  176. switch (cargo_type)
  177. {
  178. case DAD_ANIMATION:
  179. case DAD_SOUND:
  180. {
  181. // Make a script step
  182. LLInventoryItem* itemp = (LLInventoryItem*)cargo_data;
  183. if (itemp && gInventory.getItem(itemp->getUUID()))
  184. {
  185. if (!itemp->getPermissions().unrestricted())
  186. {
  187. *accept = ACCEPT_NO;
  188. if (tooltip_msg.empty())
  189. {
  190. tooltip_msg.assign("Only animations and sounds\n"
  191. "with unrestricted permissions\n"
  192. "can be added to a gesture.");
  193. }
  194. break;
  195. }
  196. if (drop)
  197. {
  198. LLScrollListItem* linep = NULL;
  199. if (cargo_type == DAD_ANIMATION)
  200. {
  201. linep = addStep(STEP_ANIMATION);
  202. LLGestureStepAnimation* animp =
  203. (LLGestureStepAnimation*)linep->getUserdata();
  204. animp->mAnimAssetID = itemp->getAssetUUID();
  205. animp->mAnimName = itemp->getName();
  206. }
  207. else if (cargo_type == DAD_SOUND)
  208. {
  209. linep = addStep(STEP_SOUND);
  210. LLGestureStepSound* soundp =
  211. (LLGestureStepSound*)linep->getUserdata();
  212. soundp->mSoundAssetID = itemp->getAssetUUID();
  213. soundp->mSoundName = itemp->getName();
  214. }
  215. updateLabel(linep);
  216. mDirty = true;
  217. refresh();
  218. }
  219. *accept = ACCEPT_YES_COPY_MULTI;
  220. }
  221. else
  222. {
  223. // Not in user's inventory means it was in object inventory
  224. *accept = ACCEPT_NO;
  225. }
  226. break;
  227. }
  228. default:
  229. {
  230. *accept = ACCEPT_NO;
  231. if (tooltip_msg.empty())
  232. {
  233. tooltip_msg.assign("Only animations and sounds can be added to a gesture.");
  234. }
  235. break;
  236. }
  237. }
  238. return true;
  239. }
  240. // virtual
  241. bool LLPreviewGesture::canClose()
  242. {
  243. if (!mDirty || mForceClose)
  244. {
  245. return true;
  246. }
  247. else
  248. {
  249. if (!mSaveDialogShown)
  250. {
  251. mSaveDialogShown = true;
  252. // Bring up view-modal dialog: Save changes ? Yes, No, Cancel
  253. gNotifications.add("SaveChanges", LLSD(), LLSD(),
  254. boost::bind(&LLPreviewGesture::handleSaveChangesDialog,
  255. this, _1, _2));
  256. }
  257. return false;
  258. }
  259. }
  260. // virtual
  261. void LLPreviewGesture::onClose(bool app_quitting)
  262. {
  263. gGestureManager.stopGesture(mPreviewGesture);
  264. LLPreview::onClose(app_quitting);
  265. }
  266. // virtual
  267. void LLPreviewGesture::onUpdateSucceeded()
  268. {
  269. refresh();
  270. }
  271. // virtual
  272. void LLPreviewGesture::setMinimized(bool minimize)
  273. {
  274. if (minimize != isMinimized())
  275. {
  276. LLFloater::setMinimized(minimize);
  277. // We're being restored
  278. if (!minimize)
  279. {
  280. refresh();
  281. }
  282. }
  283. }
  284. bool LLPreviewGesture::handleSaveChangesDialog(const LLSD& notification,
  285. const LLSD& response)
  286. {
  287. mSaveDialogShown = false;
  288. S32 option = LLNotification::getSelectedOption(notification, response);
  289. switch (option)
  290. {
  291. case 0: // "Yes"
  292. gGestureManager.stopGesture(mPreviewGesture);
  293. mCloseAfterSave = true;
  294. onClickSave(this);
  295. break;
  296. case 1: // "No"
  297. gGestureManager.stopGesture(mPreviewGesture);
  298. // Force the dirty flag because user has clicked NO on confirm save
  299. // dialog...
  300. mDirty = false;
  301. close();
  302. break;
  303. case 2: // "Cancel"
  304. default:
  305. // If we were quitting, we didn't really mean it.
  306. gAppViewerp->abortQuit();
  307. }
  308. return false;
  309. }
  310. LLPreviewGesture::LLPreviewGesture()
  311. : LLPreview("Gesture Preview"),
  312. mTriggerEditor(NULL),
  313. mModifierCombo(NULL),
  314. mKeyCombo(NULL),
  315. mLibraryList(NULL),
  316. mAddBtn(NULL),
  317. mUpBtn(NULL),
  318. mDownBtn(NULL),
  319. mDeleteBtn(NULL),
  320. mStepList(NULL),
  321. mOptionsText(NULL),
  322. mAnimationRadio(NULL),
  323. mAnimationCombo(NULL),
  324. mSoundCombo(NULL),
  325. mChatEditor(NULL),
  326. mSaveBtn(NULL),
  327. mPreviewBtn(NULL),
  328. mPreviewGesture(NULL),
  329. mDirty(false)
  330. {
  331. }
  332. LLPreviewGesture::~LLPreviewGesture()
  333. {
  334. // Userdata for all steps is a LLGestureStep we need to clean up
  335. std::vector<LLScrollListItem*> data_list = mStepList->getAllData();
  336. for (S32 i = 0, count = data_list.size(); i < count; ++i)
  337. {
  338. LLScrollListItem* item = data_list[i];
  339. if (item) // Paranoia
  340. {
  341. LLGestureStep* step = (LLGestureStep*)item->getUserdata();
  342. if (step)
  343. {
  344. delete step;
  345. }
  346. }
  347. }
  348. }
  349. bool LLPreviewGesture::postBuild()
  350. {
  351. mTriggerEditor = getChild<LLLineEditor>("trigger_editor");
  352. mTriggerEditor->setKeystrokeCallback(onKeystrokeCommit);
  353. mTriggerEditor->setCommitCallback(onCommitSetDirty);
  354. mTriggerEditor->setCommitOnFocusLost(true);
  355. mTriggerEditor->setCallbackUserData(this);
  356. mTriggerEditor->setIgnoreTab(true);
  357. mReplaceText = getChild<LLTextBox>("replace_text");
  358. mReplaceText->setEnabled(false);
  359. mReplaceEditor = getChild<LLLineEditor>("replace_editor");
  360. mReplaceEditor->setEnabled(false);
  361. mReplaceEditor->setKeystrokeCallback(onKeystrokeCommit);
  362. mReplaceEditor->setCommitCallback(onCommitSetDirty);
  363. mReplaceEditor->setCommitOnFocusLost(true);
  364. mReplaceEditor->setCallbackUserData(this);
  365. mReplaceEditor->setIgnoreTab(true);
  366. mModifierCombo = getChild<LLComboBox>("modifier_combo");
  367. mModifierCombo->setCommitCallback(onCommitSetDirty);
  368. mModifierCombo->setCallbackUserData(this);
  369. mKeyCombo = getChild<LLComboBox>("key_combo");
  370. mKeyCombo->setCommitCallback(onCommitSetDirty);
  371. mKeyCombo->setCallbackUserData(this);
  372. mLibraryList = getChild<LLScrollListCtrl>("library_list");
  373. mLibraryList->setCommitCallback(onCommitLibrary);
  374. mLibraryList->setDoubleClickCallback(onClickAdd);
  375. mLibraryList->setCallbackUserData(this);
  376. mAddBtn = getChild<LLButton>("add_btn");
  377. mAddBtn->setClickedCallback(onClickAdd);
  378. mAddBtn->setCallbackUserData(this);
  379. mAddBtn->setEnabled(false);
  380. mUpBtn = getChild<LLButton>("up_btn");
  381. mUpBtn->setClickedCallback(onClickUp);
  382. mUpBtn->setCallbackUserData(this);
  383. mUpBtn->setEnabled(false);
  384. mDownBtn = getChild<LLButton>("down_btn");
  385. mDownBtn->setClickedCallback(onClickDown);
  386. mDownBtn->setCallbackUserData(this);
  387. mDownBtn->setEnabled(false);
  388. mDeleteBtn = getChild<LLButton>("delete_btn");
  389. mDeleteBtn->setClickedCallback(onClickDelete);
  390. mDeleteBtn->setCallbackUserData(this);
  391. mDeleteBtn->setEnabled(false);
  392. mStepList = getChild<LLScrollListCtrl>("step_list");
  393. mStepList->setCommitCallback(onCommitStep);
  394. mStepList->setCallbackUserData(this);
  395. // Options
  396. mOptionsText = getChild<LLTextBox>("options_text");
  397. mOptionsText->setBorderVisible(true);
  398. mAnimationCombo = getChild<LLComboBox>("animation_list");
  399. mAnimationCombo->setVisible(false);
  400. mAnimationCombo->setCommitCallback(onCommitAnimation);
  401. mAnimationCombo->setCallbackUserData(this);
  402. mAnimationRadio = getChild<LLRadioGroup>("animation_trigger_type");
  403. mAnimationRadio->setVisible(false);
  404. mAnimationRadio->setCommitCallback(onCommitAnimationTrigger);
  405. mAnimationRadio->setCallbackUserData(this);
  406. mSoundCombo = getChild<LLComboBox>("sound_list");
  407. mSoundCombo->setVisible(false);
  408. mSoundCombo->setCommitCallback(onCommitSound);
  409. mSoundCombo->setCallbackUserData(this);
  410. mChatEditor = getChild<LLLineEditor>("chat_editor");
  411. mChatEditor->setVisible(false);
  412. mChatEditor->setCommitCallback(onCommitChat);
  413. //mChatEditor->setKeystrokeCallback(onKeystrokeCommit);
  414. mChatEditor->setCommitOnFocusLost(true);
  415. mChatEditor->setCallbackUserData(this);
  416. mChatEditor->setIgnoreTab(true);
  417. mWaitAnimCheck = getChild<LLCheckBoxCtrl>("wait_anim_check");
  418. mWaitAnimCheck->setVisible(false);
  419. mWaitAnimCheck->setCommitCallback(onCommitWait);
  420. mWaitAnimCheck->setCallbackUserData(this);
  421. mWaitTimeCheck = getChild<LLCheckBoxCtrl>("wait_time_check");
  422. mWaitTimeCheck->setVisible(false);
  423. mWaitTimeCheck->setCommitCallback(onCommitWait);
  424. mWaitTimeCheck->setCallbackUserData(this);
  425. mWaitTimeEditor = getChild<LLLineEditor>("wait_time_editor");
  426. mWaitTimeEditor->setEnabled(false);
  427. mWaitTimeEditor->setVisible(false);
  428. mWaitTimeEditor->setPrevalidate(LLLineEditor::prevalidateFloat);
  429. //mWaitTimeEditor->setKeystrokeCallback(onKeystrokeCommit);
  430. mWaitTimeEditor->setCommitOnFocusLost(true);
  431. mWaitTimeEditor->setCommitCallback(onCommitWaitTime);
  432. mWaitTimeEditor->setCallbackUserData(this);
  433. mWaitTimeEditor->setIgnoreTab(true);
  434. // Buttons at the bottom
  435. mActiveCheck = getChild<LLCheckBoxCtrl>("active_check");
  436. mActiveCheck->setCommitCallback(onCommitActive);
  437. mActiveCheck->setCallbackUserData(this);
  438. mSaveBtn = getChild<LLButton>("save_btn");
  439. mSaveBtn->setClickedCallback(onClickSave);
  440. mSaveBtn->setCallbackUserData(this);
  441. mPreviewBtn = getChild<LLButton>("preview_btn");
  442. mPreviewBtn->setClickedCallback(onClickPreview);
  443. mPreviewBtn->setCallbackUserData(this);
  444. // Populate the combo boxes
  445. addModifiers();
  446. addKeys();
  447. addAnimations();
  448. addSounds();
  449. const LLInventoryItem* item = getItem();
  450. if (item)
  451. {
  452. childSetCommitCallback("desc", LLPreview::onText, this);
  453. childSetText("desc", item->getDescription());
  454. childSetPrevalidate("desc",
  455. &LLLineEditor::prevalidatePrintableNotPipe);
  456. }
  457. return true;
  458. }
  459. void LLPreviewGesture::addModifiers()
  460. {
  461. mModifierCombo->add(NONE_LABEL, ADD_BOTTOM);
  462. mModifierCombo->add(SHIFT_LABEL, ADD_BOTTOM);
  463. mModifierCombo->add(CTRL_LABEL, ADD_BOTTOM);
  464. mModifierCombo->setCurrentByIndex(0);
  465. }
  466. void LLPreviewGesture::addKeys()
  467. {
  468. mKeyCombo->add(NONE_LABEL);
  469. for (KEY key = KEY_F2; key <= KEY_F12; key++)
  470. {
  471. mKeyCombo->add(LLKeyboard::stringFromKey(key), ADD_BOTTOM);
  472. }
  473. mKeyCombo->setCurrentByIndex(0);
  474. }
  475. // TODO: Sort the legacy and non-legacy together?
  476. void LLPreviewGesture::addAnimations()
  477. {
  478. mAnimationCombo->removeall();
  479. std::string none_text = getString("none_text");
  480. mAnimationCombo->add(none_text, LLUUID::null);
  481. std::string label;
  482. // Add all the default (legacy) animations
  483. for (S32 i = 0; i < gUserAnimStatesCount; ++i)
  484. {
  485. // Use the user-readable name
  486. label = LLAnimStateLabels::getStateLabel(gUserAnimStates[i].mName);
  487. mAnimationCombo->add(label, gUserAnimStates[i].mID);
  488. }
  489. // Get all inventory items that are animations
  490. LLViewerInventoryCategory::cat_array_t cats;
  491. LLViewerInventoryItem::item_array_t items;
  492. LLIsTypeWithPermissions is_copyable_animation(LLAssetType::AT_ANIMATION,
  493. PERM_ITEM_UNRESTRICTED,
  494. gAgentID,
  495. gAgent.getGroupID());
  496. gInventory.collectDescendentsIf(gInventory.getRootFolderID(), cats, items,
  497. LLInventoryModel::EXCLUDE_TRASH,
  498. is_copyable_animation);
  499. // Copy into something we can sort
  500. std::vector<LLInventoryItem*> animations;
  501. for (S32 i = 0, count = items.size(); i < count; ++i)
  502. {
  503. animations.push_back(items[i]);
  504. }
  505. // Do the sort
  506. std::sort(animations.begin(), animations.end(), SortItemPtrsByName());
  507. // And load up the combobox
  508. for (S32 i = 0, count = animations.size(); i < count; ++i)
  509. {
  510. LLInventoryItem* item = animations[i];
  511. if (item) // Paranoia
  512. {
  513. mAnimationCombo->add(item->getName(), item->getAssetUUID(),
  514. ADD_BOTTOM);
  515. }
  516. }
  517. }
  518. void LLPreviewGesture::addSounds()
  519. {
  520. mSoundCombo->removeall();
  521. std::string none_text = getString("none_text");
  522. mSoundCombo->add(none_text, LLUUID::null);
  523. // Get all inventory items that are sounds
  524. LLViewerInventoryCategory::cat_array_t cats;
  525. LLViewerInventoryItem::item_array_t items;
  526. LLIsTypeWithPermissions is_copyable_sound(LLAssetType::AT_SOUND,
  527. PERM_ITEM_UNRESTRICTED,
  528. gAgentID, gAgent.getGroupID());
  529. gInventory.collectDescendentsIf(gInventory.getRootFolderID(),
  530. cats, items,
  531. LLInventoryModel::EXCLUDE_TRASH,
  532. is_copyable_sound);
  533. // Copy sounds into something we can sort
  534. std::vector<LLInventoryItem*> sounds;
  535. for (S32 i = 0, count = items.size(); i < count; ++i)
  536. {
  537. sounds.push_back(items[i]);
  538. }
  539. // Do the sort
  540. std::sort(sounds.begin(), sounds.end(), SortItemPtrsByName());
  541. // And load up the combo box
  542. for (S32 i = 0, count = sounds.size(); i < count; ++i)
  543. {
  544. LLInventoryItem* item = sounds[i];
  545. if (item) // Paranoia
  546. {
  547. mSoundCombo->add(item->getName(), item->getAssetUUID(),
  548. ADD_BOTTOM);
  549. }
  550. }
  551. }
  552. void LLPreviewGesture::init(const LLUUID& item_id, const LLUUID& object_id)
  553. {
  554. // Sets ID and adds to instance list
  555. setItemID(item_id);
  556. setObjectID(object_id);
  557. }
  558. void LLPreviewGesture::refresh()
  559. {
  560. // If previewing or item is incomplete, all controls are disabled
  561. LLViewerInventoryItem* item = (LLViewerInventoryItem*)getItem();
  562. if (mPreviewGesture || !item || !item->isFinished())
  563. {
  564. childSetEnabled("desc", false);
  565. //mDescEditor->setEnabled(false);
  566. mTriggerEditor->setEnabled(false);
  567. mReplaceText->setEnabled(false);
  568. mReplaceEditor->setEnabled(false);
  569. mModifierCombo->setEnabled(false);
  570. mKeyCombo->setEnabled(false);
  571. mLibraryList->setEnabled(false);
  572. mAddBtn->setEnabled(false);
  573. mUpBtn->setEnabled(false);
  574. mDownBtn->setEnabled(false);
  575. mDeleteBtn->setEnabled(false);
  576. mStepList->setEnabled(false);
  577. mOptionsText->setEnabled(false);
  578. mAnimationCombo->setEnabled(false);
  579. mAnimationRadio->setEnabled(false);
  580. mSoundCombo->setEnabled(false);
  581. mChatEditor->setEnabled(false);
  582. mWaitAnimCheck->setEnabled(false);
  583. mWaitTimeCheck->setEnabled(false);
  584. mWaitTimeEditor->setEnabled(false);
  585. mActiveCheck->setEnabled(false);
  586. mSaveBtn->setEnabled(false);
  587. // Make sure preview button is enabled, so we can stop it
  588. mPreviewBtn->setEnabled(true);
  589. return;
  590. }
  591. bool modifiable = item->getPermissions().allowModifyBy(gAgentID);
  592. childSetEnabled("desc", modifiable);
  593. mTriggerEditor->setEnabled(true);
  594. mLibraryList->setEnabled(modifiable);
  595. mStepList->setEnabled(modifiable);
  596. mOptionsText->setEnabled(modifiable);
  597. mAnimationCombo->setEnabled(modifiable);
  598. mAnimationRadio->setEnabled(modifiable);
  599. mSoundCombo->setEnabled(modifiable);
  600. mChatEditor->setEnabled(modifiable);
  601. mWaitAnimCheck->setEnabled(modifiable);
  602. mWaitTimeCheck->setEnabled(modifiable);
  603. mWaitTimeEditor->setEnabled(modifiable);
  604. mActiveCheck->setEnabled(true);
  605. const std::string& trigger = mTriggerEditor->getText();
  606. bool have_trigger = !trigger.empty();
  607. const std::string& replace = mReplaceEditor->getText();
  608. bool have_replace = !replace.empty();
  609. LLScrollListItem* library_item = mLibraryList->getFirstSelected();
  610. bool have_library = library_item != NULL;
  611. LLScrollListItem* step_item = mStepList->getFirstSelected();
  612. S32 step_index = mStepList->getFirstSelectedIndex();
  613. S32 step_count = mStepList->getItemCount();
  614. bool have_step = step_item != NULL;
  615. mReplaceText->setEnabled(have_trigger || have_replace);
  616. mReplaceEditor->setEnabled(have_trigger || have_replace);
  617. mModifierCombo->setEnabled(true);
  618. mKeyCombo->setEnabled(true);
  619. mAddBtn->setEnabled(modifiable && have_library);
  620. mUpBtn->setEnabled(modifiable && have_step && step_index > 0);
  621. mDownBtn->setEnabled(modifiable && have_step &&
  622. step_index < step_count - 1);
  623. mDeleteBtn->setEnabled(modifiable && have_step);
  624. // Assume all not visible
  625. mAnimationCombo->setVisible(false);
  626. mAnimationRadio->setVisible(false);
  627. mSoundCombo->setVisible(false);
  628. mChatEditor->setVisible(false);
  629. mWaitAnimCheck->setVisible(false);
  630. mWaitTimeCheck->setVisible(false);
  631. mWaitTimeEditor->setVisible(false);
  632. std::string optionstext;
  633. if (have_step)
  634. {
  635. // Figure out the type, show proper options, update text
  636. LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
  637. EStepType type = step->getType();
  638. switch (type)
  639. {
  640. case STEP_ANIMATION:
  641. {
  642. LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
  643. optionstext = getString("step_anim");
  644. mAnimationCombo->setVisible(true);
  645. mAnimationRadio->setVisible(true);
  646. mAnimationRadio->setSelectedIndex((anim_step->mFlags & ANIM_FLAG_STOP) ? 1 : 0);
  647. mAnimationCombo->setCurrentByID(anim_step->mAnimAssetID);
  648. break;
  649. }
  650. case STEP_SOUND:
  651. {
  652. LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
  653. optionstext = getString("step_sound");
  654. mSoundCombo->setVisible(true);
  655. mSoundCombo->setCurrentByID(sound_step->mSoundAssetID);
  656. break;
  657. }
  658. case STEP_CHAT:
  659. {
  660. LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
  661. optionstext = getString("step_chat");
  662. mChatEditor->setVisible(true);
  663. mChatEditor->setText(chat_step->mChatText);
  664. break;
  665. }
  666. case STEP_WAIT:
  667. {
  668. LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
  669. optionstext = getString("step_wait");
  670. mWaitAnimCheck->setVisible(true);
  671. mWaitAnimCheck->set(wait_step->mFlags & WAIT_FLAG_ALL_ANIM);
  672. mWaitTimeCheck->setVisible(true);
  673. mWaitTimeCheck->set(wait_step->mFlags & WAIT_FLAG_TIME);
  674. mWaitTimeEditor->setVisible(true);
  675. std::string buffer = llformat("%.1f",
  676. (double)wait_step->mWaitSeconds);
  677. mWaitTimeEditor->setText(buffer);
  678. break;
  679. }
  680. default:
  681. break;
  682. }
  683. }
  684. mOptionsText->setText(optionstext);
  685. bool active = gGestureManager.isGestureActive(mItemUUID);
  686. mActiveCheck->set(active);
  687. // Can only preview if there are steps
  688. mPreviewBtn->setEnabled(step_count > 0);
  689. // And can only save if changes have been made
  690. mSaveBtn->setEnabled(mDirty);
  691. addAnimations();
  692. addSounds();
  693. }
  694. void LLPreviewGesture::initDefaultGesture()
  695. {
  696. LLScrollListItem* item = addStep(STEP_ANIMATION);
  697. LLGestureStepAnimation* anim =
  698. (LLGestureStepAnimation*)item->getUserdata();
  699. anim->mAnimAssetID = ANIM_AGENT_HELLO;
  700. anim->mAnimName = "Wave";
  701. updateLabel(item);
  702. item = addStep(STEP_WAIT);
  703. LLGestureStepWait* wait = (LLGestureStepWait*)item->getUserdata();
  704. wait->mFlags = WAIT_FLAG_ALL_ANIM;
  705. updateLabel(item);
  706. item = addStep(STEP_CHAT);
  707. LLGestureStepChat* chat_step = (LLGestureStepChat*)item->getUserdata();
  708. chat_step->mChatText = "Hello, avatar!";
  709. updateLabel(item);
  710. // Start with item list selected
  711. mStepList->selectFirstItem();
  712. // This is *new* content, so we are dirty
  713. mDirty = true;
  714. }
  715. void LLPreviewGesture::loadAsset()
  716. {
  717. const LLInventoryItem* item = getItem();
  718. if (!item) return;
  719. LLUUID asset_id = item->getAssetUUID();
  720. if (asset_id.isNull())
  721. {
  722. // Freshly created gesture, don't need to load asset. Blank gesture
  723. // will be fine.
  724. initDefaultGesture();
  725. refresh();
  726. return;
  727. }
  728. // *TODO: Based on item->getPermissions().allow* could enable/disable UI.
  729. // Copy the UUID, because the user might close the preview window if the
  730. // download gets stalled.
  731. LLUUID* item_idp = new LLUUID(mItemUUID);
  732. gAssetStoragep->getAssetData(asset_id, LLAssetType::AT_GESTURE,
  733. onLoadComplete, (void**)item_idp,
  734. true); // high priority
  735. mAssetStatus = PREVIEW_ASSET_LOADING;
  736. }
  737. //static
  738. void LLPreviewGesture::onLoadComplete(const LLUUID& asset_uuid,
  739. LLAssetType::EType type, void* user_data,
  740. S32 status, LLExtStat)
  741. {
  742. LLUUID* item_idp = (LLUUID*)user_data;
  743. LLPreview* preview = LLPreview::find(*item_idp);
  744. if (preview)
  745. {
  746. LLPreviewGesture* self = (LLPreviewGesture*)preview;
  747. if (status == 0)
  748. {
  749. LLFileSystem file(asset_uuid);
  750. S32 size = file.getSize();
  751. char* buffer = new char[size + 1];
  752. file.read((U8*)buffer, size);
  753. buffer[size] = '\0';
  754. LLMultiGesture* gesture = new LLMultiGesture();
  755. LLDataPackerAsciiBuffer dp(buffer, size+1);
  756. bool ok = gesture->deserialize(dp);
  757. if (ok)
  758. {
  759. // Everything has been successful. Load up the UI.
  760. self->loadUIFromGesture(gesture);
  761. self->mStepList->selectFirstItem();
  762. self->mDirty = false;
  763. self->refresh();
  764. }
  765. else
  766. {
  767. llwarns << "Unable to load gesture" << llendl;
  768. }
  769. delete gesture;
  770. gesture = NULL;
  771. delete[] buffer;
  772. buffer = NULL;
  773. self->mAssetStatus = PREVIEW_ASSET_LOADED;
  774. }
  775. else
  776. {
  777. gViewerStats.incStat(LLViewerStats::ST_DOWNLOAD_FAILED);
  778. LLGestureManager::notifyLoadFailed(*item_idp, status);
  779. llwarns << "Problem loading gesture: " << status << llendl;
  780. self->mAssetStatus = PREVIEW_ASSET_ERROR;
  781. }
  782. }
  783. delete item_idp;
  784. item_idp = NULL;
  785. }
  786. void LLPreviewGesture::loadUIFromGesture(LLMultiGesture* gesture)
  787. {
  788. #if 0
  789. LLInventoryItem* item = getItem();
  790. if (item)
  791. {
  792. LLLineEditor* descEditor = getChild<LLLineEditor>("desc");
  793. descEditor->setText(item->getDescription());
  794. }
  795. #endif
  796. mTriggerEditor->setText(gesture->mTrigger);
  797. mReplaceEditor->setText(gesture->mReplaceText);
  798. switch (gesture->mMask)
  799. {
  800. case MASK_SHIFT:
  801. mModifierCombo->setSimple(SHIFT_LABEL);
  802. break;
  803. case MASK_CONTROL:
  804. mModifierCombo->setSimple(CTRL_LABEL);
  805. break;
  806. case MASK_NONE:
  807. default:
  808. mModifierCombo->setSimple(NONE_LABEL);
  809. }
  810. mKeyCombo->setCurrentByIndex(0);
  811. if (gesture->mKey != KEY_NONE)
  812. {
  813. mKeyCombo->setSimple(LLKeyboard::stringFromKey(gesture->mKey));
  814. }
  815. // Make UI steps for each gesture step
  816. for (S32 i = 0, count = gesture->mSteps.size(); i < count; ++i)
  817. {
  818. LLGestureStep* step = gesture->mSteps[i];
  819. if (!step) continue; // Paranoia
  820. LLGestureStep* new_step = NULL;
  821. switch (step->getType())
  822. {
  823. case STEP_ANIMATION:
  824. {
  825. LLGestureStepAnimation* anim_step =
  826. (LLGestureStepAnimation*)step;
  827. LLGestureStepAnimation* new_anim_step;
  828. new_anim_step = new LLGestureStepAnimation(*anim_step);
  829. new_step = new_anim_step;
  830. break;
  831. }
  832. case STEP_SOUND:
  833. {
  834. LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
  835. LLGestureStepSound* new_sound_step;
  836. new_sound_step = new LLGestureStepSound(*sound_step);
  837. new_step = new_sound_step;
  838. break;
  839. }
  840. case STEP_CHAT:
  841. {
  842. LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
  843. LLGestureStepChat* new_chat_step;
  844. new_chat_step = new LLGestureStepChat(*chat_step);
  845. new_step = new_chat_step;
  846. break;
  847. }
  848. case STEP_WAIT:
  849. {
  850. LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
  851. LLGestureStepWait* new_wait_step;
  852. new_wait_step = new LLGestureStepWait(*wait_step);
  853. new_step = new_wait_step;
  854. break;
  855. }
  856. default:
  857. break;
  858. }
  859. if (!new_step) continue;
  860. // Create an enabled item with this step
  861. LLSD row;
  862. row["columns"][0]["value"] = new_step->getLabel();
  863. row["columns"][0]["font"] = "SANSSERIF_SMALL";
  864. LLScrollListItem* item = mStepList->addElement(row);
  865. item->setUserdata(new_step);
  866. }
  867. }
  868. // Helpful structure so we can look up the inventory item
  869. // after the save finishes.
  870. struct LLSaveInfo
  871. {
  872. LLSaveInfo(const LLUUID& item_id, const LLUUID& object_id,
  873. const std::string& desc, const LLTransactionID tid)
  874. : mItemUUID(item_id),
  875. mObjectUUID(object_id),
  876. mDesc(desc),
  877. mTransactionID(tid)
  878. {
  879. }
  880. LLUUID mItemUUID;
  881. LLUUID mObjectUUID;
  882. LLTransactionID mTransactionID;
  883. std::string mDesc;
  884. };
  885. void LLPreviewGesture::saveIfNeeded()
  886. {
  887. if (!gAssetStoragep)
  888. {
  889. llwarns << "Cannot save gesture: no asset storage system." << llendl;
  890. return;
  891. }
  892. if (!mDirty)
  893. {
  894. return;
  895. }
  896. // Copy the UI into a gesture
  897. LLMultiGesture* gesture = createGesture();
  898. // Serialize the gesture
  899. S32 max_size = gesture->getMaxSerialSize();
  900. char* buffer = new char[max_size];
  901. LLDataPackerAsciiBuffer dp(buffer, max_size);
  902. bool ok = gesture->serialize(dp);
  903. if (dp.getCurrentSize() > 1000)
  904. {
  905. gNotifications.add("GestureSaveFailedTooManySteps");
  906. delete gesture;
  907. gesture = NULL;
  908. }
  909. else if (!ok)
  910. {
  911. gNotifications.add("GestureSaveFailedTryAgain");
  912. delete gesture;
  913. gesture = NULL;
  914. }
  915. else
  916. {
  917. LLAssetID asset_id;
  918. bool delayed_upload = false;
  919. // Upload that asset to the database
  920. LLViewerInventoryItem* item = (LLViewerInventoryItem*) getItem();
  921. if (item)
  922. {
  923. const std::string& agent_url =
  924. gAgent.getRegionCapability("UpdateGestureAgentInventory");
  925. const std::string& task_url =
  926. gAgent.getRegionCapability("UpdateGestureTaskInventory");
  927. if (!agent_url.empty() && !task_url.empty())
  928. {
  929. const std::string* url = NULL;
  930. LLResourceUploadInfo::ptr_t info;
  931. if (mObjectUUID.isNull() && !agent_url.empty())
  932. {
  933. // Saving into agent inventory. We need to disable the
  934. // preview floater so item is not re-saved before the new
  935. // asset arrives; fake out a refresh.
  936. item->setComplete(false);
  937. refresh();
  938. item->setComplete(true);
  939. info = std::make_shared<LLBufferedAssetUploadInfo>(mItemUUID,
  940. LLAssetType::AT_GESTURE,
  941. buffer,
  942. boost::bind(&LLPreviewGesture::finishInventoryUpload,
  943. _1, _2));
  944. url = &agent_url;
  945. delayed_upload = true;
  946. }
  947. else if (mObjectUUID.notNull() && !task_url.empty())
  948. {
  949. // Saving into task inventory
  950. // NOTE: what looks like a bug in std::make_shared prevents
  951. // from using it here, because of the NULL boost::function
  952. // pointer passed... And no, passing nullptr won't change a
  953. // thing. HB
  954. info = LLResourceUploadInfo::ptr_t(new LLBufferedAssetUploadInfo(mObjectUUID,
  955. mItemUUID,
  956. LLAssetType::AT_GESTURE,
  957. buffer,
  958. NULL));
  959. url = &task_url;
  960. }
  961. if (url && info)
  962. {
  963. LLViewerAssetUpload::enqueueInventoryUpload(*url, info);
  964. }
  965. }
  966. else if (gAssetStoragep)
  967. {
  968. // Every save gets a new UUID. Yup.
  969. LLTransactionID tid;
  970. tid.generate();
  971. asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
  972. LLFileSystem file(asset_id, LLFileSystem::APPEND);
  973. S32 size = dp.getCurrentSize();
  974. file.write((U8*)buffer, size);
  975. LLLineEditor* descEditor = getChild<LLLineEditor>("desc");
  976. LLSaveInfo* info = new LLSaveInfo(mItemUUID, mObjectUUID,
  977. descEditor->getText(), tid);
  978. gAssetStoragep->storeAssetData(tid, LLAssetType::AT_GESTURE,
  979. onSaveComplete, info, false);
  980. }
  981. else
  982. {
  983. llwarns << "No capability neither asset storage system. Could not save gesture: "
  984. << mItemUUID << llendl;
  985. delete[] buffer;
  986. buffer = NULL;
  987. return;
  988. }
  989. }
  990. // If this gesture is active, then we need to update the in-memory
  991. // active map with the new pointer.
  992. if (!delayed_upload && gGestureManager.isGestureActive(mItemUUID))
  993. {
  994. // Gesture manager now owns the pointer
  995. gGestureManager.replaceGesture(mItemUUID, gesture, asset_id);
  996. // replaceGesture() may deactivate other gestures so let the
  997. // inventory know.
  998. gInventory.notifyObservers();
  999. }
  1000. else
  1001. {
  1002. // We are done with this gesture
  1003. delete gesture;
  1004. gesture = NULL;
  1005. }
  1006. mDirty = false;
  1007. // Refresh will be called when the callback happens if triggered when
  1008. // delayed_upload == true
  1009. if (!delayed_upload)
  1010. {
  1011. refresh();
  1012. }
  1013. }
  1014. delete[] buffer;
  1015. buffer = NULL;
  1016. }
  1017. //static
  1018. void LLPreviewGesture::finishInventoryUpload(LLUUID item_id,
  1019. LLUUID new_asset_id)
  1020. {
  1021. if (item_id.isNull()) return;
  1022. // If this gesture is active, then we need to update the in-memory active
  1023. // map with the new pointer.
  1024. if (gGestureManager.isGestureActive(item_id) && new_asset_id.notNull())
  1025. {
  1026. gGestureManager.replaceGesture(item_id, new_asset_id);
  1027. gInventory.notifyObservers();
  1028. }
  1029. // Gesture will have a new asset_id
  1030. LLPreviewGesture* self = (LLPreviewGesture*)LLPreview::find(item_id);
  1031. if (self)
  1032. {
  1033. self->setAssetId(new_asset_id);
  1034. self->onUpdateSucceeded();
  1035. }
  1036. }
  1037. // StoreAssetData callback (fixed)
  1038. // *TODO: This is very similar to LLPreviewNotecard::onSaveComplete. Could
  1039. // merge this code.
  1040. //static
  1041. void LLPreviewGesture::onSaveComplete(const LLUUID& asset_uuid,
  1042. void* user_data, S32 status,
  1043. LLExtStat)
  1044. {
  1045. LLSaveInfo* info = (LLSaveInfo*)user_data;
  1046. if (info && status == 0)
  1047. {
  1048. if (info->mObjectUUID.isNull())
  1049. {
  1050. // Saving into user inventory
  1051. LLViewerInventoryItem* item;
  1052. item = (LLViewerInventoryItem*)gInventory.getItem(info->mItemUUID);
  1053. if (item)
  1054. {
  1055. LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
  1056. new_item->setDescription(info->mDesc);
  1057. new_item->setTransactionID(info->mTransactionID);
  1058. new_item->setAssetUUID(asset_uuid);
  1059. new_item->updateServer(false);
  1060. gInventory.updateItem(new_item);
  1061. gInventory.notifyObservers();
  1062. }
  1063. else
  1064. {
  1065. llwarns << "Inventory item for gesture " << info->mItemUUID
  1066. << " is no longer in agent inventory." << llendl;
  1067. }
  1068. }
  1069. else
  1070. {
  1071. // Saving into in-world object inventory
  1072. LLViewerObject* object = gObjectList.findObject(info->mObjectUUID);
  1073. LLViewerInventoryItem* item = NULL;
  1074. if (object)
  1075. {
  1076. item = (LLViewerInventoryItem*)object->getInventoryObject(info->mItemUUID);
  1077. }
  1078. if (object && item)
  1079. {
  1080. item->setDescription(info->mDesc);
  1081. item->setAssetUUID(asset_uuid);
  1082. item->setTransactionID(info->mTransactionID);
  1083. object->updateInventory(item);
  1084. dialog_refresh_all();
  1085. }
  1086. else
  1087. {
  1088. gNotifications.add("GestureSaveFailedObjectNotFound");
  1089. }
  1090. }
  1091. // Find our window and close it if requested.
  1092. LLPreviewGesture* previewp;
  1093. previewp = (LLPreviewGesture*)LLPreview::find(info->mItemUUID);
  1094. if (previewp && previewp->mCloseAfterSave)
  1095. {
  1096. previewp->close();
  1097. }
  1098. }
  1099. else
  1100. {
  1101. llwarns << "Problem saving gesture: " << status << llendl;
  1102. LLSD args;
  1103. args["REASON"] = std::string(LLAssetStorage::getErrorString(status));
  1104. gNotifications.add("GestureSaveFailedReason", args);
  1105. }
  1106. delete info;
  1107. info = NULL;
  1108. }
  1109. LLMultiGesture* LLPreviewGesture::createGesture()
  1110. {
  1111. LLMultiGesture* gesture = new LLMultiGesture();
  1112. gesture->mTrigger = mTriggerEditor->getText();
  1113. gesture->mReplaceText = mReplaceEditor->getText();
  1114. const std::string& modifier = mModifierCombo->getSimple();
  1115. if (modifier == CTRL_LABEL)
  1116. {
  1117. gesture->mMask = MASK_CONTROL;
  1118. }
  1119. else if (modifier == SHIFT_LABEL)
  1120. {
  1121. gesture->mMask = MASK_SHIFT;
  1122. }
  1123. else
  1124. {
  1125. gesture->mMask = MASK_NONE;
  1126. }
  1127. if (mKeyCombo->getCurrentIndex() == 0)
  1128. {
  1129. gesture->mKey = KEY_NONE;
  1130. }
  1131. else
  1132. {
  1133. const std::string& key_string = mKeyCombo->getSimple();
  1134. LLKeyboard::keyFromString(key_string.c_str(), &(gesture->mKey));
  1135. }
  1136. std::vector<LLScrollListItem*> data_list = mStepList->getAllData();
  1137. for (S32 i = 0, count = data_list.size(); i < count; ++i)
  1138. {
  1139. LLScrollListItem* item = data_list[i];
  1140. if (!item) continue; // Paranoia
  1141. LLGestureStep* step = (LLGestureStep*)item->getUserdata();
  1142. if (!step) continue; // Paranoia
  1143. switch (step->getType())
  1144. {
  1145. case STEP_ANIMATION:
  1146. {
  1147. // Copy UI-generated step into actual gesture step
  1148. LLGestureStepAnimation* anim_step =
  1149. (LLGestureStepAnimation*)step;
  1150. LLGestureStepAnimation* new_anim_step =
  1151. new LLGestureStepAnimation(*anim_step);
  1152. gesture->mSteps.push_back(new_anim_step);
  1153. break;
  1154. }
  1155. case STEP_SOUND:
  1156. {
  1157. // Copy UI-generated step into actual gesture step
  1158. LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
  1159. LLGestureStepSound* new_sound_step =
  1160. new LLGestureStepSound(*sound_step);
  1161. gesture->mSteps.push_back(new_sound_step);
  1162. break;
  1163. }
  1164. case STEP_CHAT:
  1165. {
  1166. // Copy UI-generated step into actual gesture step
  1167. LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
  1168. LLGestureStepChat* new_chat_step =
  1169. new LLGestureStepChat(*chat_step);
  1170. gesture->mSteps.push_back(new_chat_step);
  1171. break;
  1172. }
  1173. case STEP_WAIT:
  1174. {
  1175. // Copy UI-generated step into actual gesture step
  1176. LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
  1177. LLGestureStepWait* new_wait_step =
  1178. new LLGestureStepWait(*wait_step);
  1179. gesture->mSteps.push_back(new_wait_step);
  1180. break;
  1181. }
  1182. default:
  1183. break;
  1184. }
  1185. }
  1186. return gesture;
  1187. }
  1188. //static
  1189. void LLPreviewGesture::updateLabel(LLScrollListItem* item)
  1190. {
  1191. LLGestureStep* step = (LLGestureStep*)item->getUserdata();
  1192. if (!step) return; // Paranoia
  1193. LLScrollListCell* cell = item->getColumn(0);
  1194. if (!cell) return; // Paranoia
  1195. LLScrollListText* text_cell = (LLScrollListText*)cell;
  1196. std::string label = step->getLabel();
  1197. text_cell->setText(label);
  1198. }
  1199. //static
  1200. void LLPreviewGesture::onCommitSetDirty(LLUICtrl* ctrl, void* data)
  1201. {
  1202. LLPreviewGesture* self = (LLPreviewGesture*)data;
  1203. if (self)
  1204. {
  1205. self->mDirty = true;
  1206. self->refresh();
  1207. }
  1208. }
  1209. //static
  1210. void LLPreviewGesture::onCommitLibrary(LLUICtrl* ctrl, void* data)
  1211. {
  1212. LLPreviewGesture* self = (LLPreviewGesture*)data;
  1213. if (!self) return;
  1214. LLScrollListItem* library_item = self->mLibraryList->getFirstSelected();
  1215. if (library_item)
  1216. {
  1217. self->mStepList->deselectAllItems();
  1218. self->refresh();
  1219. }
  1220. }
  1221. //static
  1222. void LLPreviewGesture::onCommitStep(LLUICtrl* ctrl, void* data)
  1223. {
  1224. LLPreviewGesture* self = (LLPreviewGesture*)data;
  1225. if (!self) return;
  1226. LLScrollListItem* step_item = self->mStepList->getFirstSelected();
  1227. if (!step_item) return;
  1228. self->mLibraryList->deselectAllItems();
  1229. self->refresh();
  1230. }
  1231. //static
  1232. void LLPreviewGesture::onCommitAnimation(LLUICtrl* ctrl, void* data)
  1233. {
  1234. LLPreviewGesture* self = (LLPreviewGesture*)data;
  1235. if (!self) return;
  1236. LLScrollListItem* step_item = self->mStepList->getFirstSelected();
  1237. if (step_item)
  1238. {
  1239. LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
  1240. if (step->getType() == STEP_ANIMATION)
  1241. {
  1242. // Assign the animation name
  1243. LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
  1244. if (self->mAnimationCombo->getCurrentIndex() == 0)
  1245. {
  1246. anim_step->mAnimName.clear();
  1247. anim_step->mAnimAssetID.setNull();
  1248. }
  1249. else
  1250. {
  1251. anim_step->mAnimName = self->mAnimationCombo->getSimple();
  1252. anim_step->mAnimAssetID =
  1253. self->mAnimationCombo->getCurrentID();
  1254. }
  1255. #if 0
  1256. anim_step->mFlags = 0x0;
  1257. #endif
  1258. // Update the UI label in the list
  1259. updateLabel(step_item);
  1260. self->mDirty = true;
  1261. self->refresh();
  1262. }
  1263. }
  1264. }
  1265. //static
  1266. void LLPreviewGesture::onCommitAnimationTrigger(LLUICtrl* ctrl, void *data)
  1267. {
  1268. LLPreviewGesture* self = (LLPreviewGesture*)data;
  1269. if (!self) return;
  1270. LLScrollListItem* step_item = self->mStepList->getFirstSelected();
  1271. if (step_item)
  1272. {
  1273. LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
  1274. if (step->getType() == STEP_ANIMATION)
  1275. {
  1276. LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
  1277. if (self->mAnimationRadio->getSelectedIndex() == 0)
  1278. {
  1279. // Start
  1280. anim_step->mFlags &= ~ANIM_FLAG_STOP;
  1281. }
  1282. else
  1283. {
  1284. // Stop
  1285. anim_step->mFlags |= ANIM_FLAG_STOP;
  1286. }
  1287. // Update the UI label in the list
  1288. updateLabel(step_item);
  1289. self->mDirty = true;
  1290. self->refresh();
  1291. }
  1292. }
  1293. }
  1294. //static
  1295. void LLPreviewGesture::onCommitSound(LLUICtrl* ctrl, void* data)
  1296. {
  1297. LLPreviewGesture* self = (LLPreviewGesture*)data;
  1298. if (!self) return;
  1299. LLScrollListItem* step_item = self->mStepList->getFirstSelected();
  1300. if (step_item)
  1301. {
  1302. LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
  1303. if (step->getType() == STEP_SOUND)
  1304. {
  1305. // Assign the sound name
  1306. LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
  1307. sound_step->mSoundName = self->mSoundCombo->getSimple();
  1308. sound_step->mSoundAssetID = self->mSoundCombo->getCurrentID();
  1309. sound_step->mFlags = 0x0;
  1310. // Update the UI label in the list
  1311. updateLabel(step_item);
  1312. self->mDirty = true;
  1313. self->refresh();
  1314. }
  1315. }
  1316. }
  1317. //static
  1318. void LLPreviewGesture::onCommitChat(LLUICtrl* ctrl, void* data)
  1319. {
  1320. LLPreviewGesture* self = (LLPreviewGesture*)data;
  1321. if (!self) return;
  1322. LLScrollListItem* step_item = self->mStepList->getFirstSelected();
  1323. if (!step_item) return;
  1324. LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
  1325. if (step->getType() != STEP_CHAT) return;
  1326. LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
  1327. chat_step->mChatText = self->mChatEditor->getText();
  1328. chat_step->mFlags = 0x0;
  1329. // Update the UI label in the list
  1330. updateLabel(step_item);
  1331. self->mDirty = true;
  1332. self->refresh();
  1333. }
  1334. //static
  1335. void LLPreviewGesture::onCommitWait(LLUICtrl* ctrl, void* data)
  1336. {
  1337. LLPreviewGesture* self = (LLPreviewGesture*)data;
  1338. if (!self) return;
  1339. LLScrollListItem* step_item = self->mStepList->getFirstSelected();
  1340. if (!step_item) return;
  1341. LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
  1342. if (step->getType() != STEP_WAIT) return;
  1343. LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
  1344. U32 flags = 0x0;
  1345. if (self->mWaitAnimCheck->get()) flags |= WAIT_FLAG_ALL_ANIM;
  1346. if (self->mWaitTimeCheck->get()) flags |= WAIT_FLAG_TIME;
  1347. wait_step->mFlags = flags;
  1348. {
  1349. LLLocale locale(LLLocale::USER_LOCALE);
  1350. wait_step->mWaitSeconds =
  1351. llclamp((F32)atof(self->mWaitTimeEditor->getText().c_str()), 0.f,
  1352. 3600.f);
  1353. }
  1354. // Enable the input area if necessary
  1355. self->mWaitTimeEditor->setEnabled(self->mWaitTimeCheck->get());
  1356. // Update the UI label in the list
  1357. updateLabel(step_item);
  1358. self->mDirty = true;
  1359. self->refresh();
  1360. }
  1361. //static
  1362. void LLPreviewGesture::onCommitWaitTime(LLUICtrl* ctrl, void* data)
  1363. {
  1364. LLPreviewGesture* self = (LLPreviewGesture*)data;
  1365. if (!self) return;
  1366. LLScrollListItem* step_item = self->mStepList->getFirstSelected();
  1367. if (!step_item) return;
  1368. LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
  1369. if (step && step->getType() == STEP_WAIT)
  1370. {
  1371. self->mWaitTimeCheck->set(true);
  1372. onCommitWait(ctrl, data);
  1373. }
  1374. }
  1375. //static
  1376. void LLPreviewGesture::onKeystrokeCommit(LLLineEditor* caller,
  1377. void* data)
  1378. {
  1379. // Just commit every keystroke
  1380. onCommitSetDirty(caller, data);
  1381. }
  1382. //static
  1383. void LLPreviewGesture::onClickAdd(void* data)
  1384. {
  1385. LLPreviewGesture* self = (LLPreviewGesture*)data;
  1386. if (!self) return;
  1387. LLScrollListItem* library_item = self->mLibraryList->getFirstSelected();
  1388. if (!library_item) return;
  1389. S32 library_item_index = self->mLibraryList->getFirstSelectedIndex();
  1390. const LLScrollListCell* library_cell = library_item->getColumn(0);
  1391. const std::string& library_text = library_cell->getValue().asString();
  1392. if (library_item_index >= STEP_EOF)
  1393. {
  1394. llerrs << "Unknown step type: " << library_text << llendl;
  1395. }
  1396. self->addStep((EStepType)library_item_index);
  1397. self->mDirty = true;
  1398. self->refresh();
  1399. }
  1400. LLScrollListItem* LLPreviewGesture::addStep(const EStepType step_type)
  1401. {
  1402. // Order of enum EStepType MUST match the library_list element in
  1403. // floater_preview_gesture.xml
  1404. LLGestureStep* step = NULL;
  1405. switch (step_type)
  1406. {
  1407. case STEP_ANIMATION:
  1408. step = new LLGestureStepAnimation();
  1409. break;
  1410. case STEP_SOUND:
  1411. step = new LLGestureStepSound();
  1412. break;
  1413. case STEP_CHAT:
  1414. step = new LLGestureStepChat();
  1415. break;
  1416. case STEP_WAIT:
  1417. step = new LLGestureStepWait();
  1418. break;
  1419. default:
  1420. llerrs << "Unknown step type: " << (S32)step_type << llendl;
  1421. }
  1422. // Create an enabled item with this step
  1423. LLSD row;
  1424. row["columns"][0]["value"] = step->getLabel();
  1425. row["columns"][0]["font"] = "SANSSERIF_SMALL";
  1426. LLScrollListItem* step_item = mStepList->addElement(row);
  1427. if (step_item) // Out of memory...
  1428. {
  1429. step_item->setUserdata(step);
  1430. // And move selection to the list on the right
  1431. mLibraryList->deselectAllItems();
  1432. mStepList->deselectAllItems();
  1433. step_item->setSelected(true);
  1434. }
  1435. return step_item;
  1436. }
  1437. //static
  1438. void LLPreviewGesture::onClickUp(void* data)
  1439. {
  1440. LLPreviewGesture* self = (LLPreviewGesture*)data;
  1441. if (!self) return;
  1442. S32 selected_index = self->mStepList->getFirstSelectedIndex();
  1443. if (selected_index > 0)
  1444. {
  1445. self->mStepList->swapWithPrevious(selected_index);
  1446. self->mDirty = true;
  1447. self->refresh();
  1448. }
  1449. }
  1450. //static
  1451. void LLPreviewGesture::onClickDown(void* data)
  1452. {
  1453. LLPreviewGesture* self = (LLPreviewGesture*)data;
  1454. if (!self) return;
  1455. S32 selected_index = self->mStepList->getFirstSelectedIndex();
  1456. if (selected_index < 0) return;
  1457. S32 count = self->mStepList->getItemCount();
  1458. if (selected_index < count-1)
  1459. {
  1460. self->mStepList->swapWithNext(selected_index);
  1461. self->mDirty = true;
  1462. self->refresh();
  1463. }
  1464. }
  1465. //static
  1466. void LLPreviewGesture::onClickDelete(void* data)
  1467. {
  1468. LLPreviewGesture* self = (LLPreviewGesture*)data;
  1469. if (!self) return;
  1470. LLScrollListItem* item = self->mStepList->getFirstSelected();
  1471. S32 selected_index = self->mStepList->getFirstSelectedIndex();
  1472. if (item && selected_index >= 0)
  1473. {
  1474. LLGestureStep* step = (LLGestureStep*)item->getUserdata();
  1475. if (step)
  1476. {
  1477. delete step;
  1478. }
  1479. self->mStepList->deleteSingleItem(selected_index);
  1480. self->mDirty = true;
  1481. self->refresh();
  1482. }
  1483. }
  1484. //static
  1485. void LLPreviewGesture::onCommitActive(LLUICtrl* ctrl, void* data)
  1486. {
  1487. LLPreviewGesture* self = (LLPreviewGesture*)data;
  1488. if (!self) return;
  1489. if (!gGestureManager.isGestureActive(self->mItemUUID))
  1490. {
  1491. gGestureManager.activateGesture(self->mItemUUID);
  1492. }
  1493. else
  1494. {
  1495. gGestureManager.deactivateGesture(self->mItemUUID);
  1496. }
  1497. // Make sure the (active) label in the inventory gets updated.
  1498. LLViewerInventoryItem* item = gInventory.getItem(self->mItemUUID);
  1499. if (item)
  1500. {
  1501. gInventory.updateItem(item);
  1502. gInventory.notifyObservers();
  1503. }
  1504. self->refresh();
  1505. }
  1506. //static
  1507. void LLPreviewGesture::onClickSave(void* data)
  1508. {
  1509. LLPreviewGesture* self = (LLPreviewGesture*)data;
  1510. if (self)
  1511. {
  1512. self->saveIfNeeded();
  1513. }
  1514. }
  1515. //static
  1516. void LLPreviewGesture::onClickPreview(void* data)
  1517. {
  1518. LLPreviewGesture* self = (LLPreviewGesture*)data;
  1519. if (!self) return;
  1520. if (!self->mPreviewGesture)
  1521. {
  1522. // Make temporary gesture
  1523. self->mPreviewGesture = self->createGesture();
  1524. // Add a callback
  1525. self->mPreviewGesture->mDoneCallback = onDonePreview;
  1526. self->mPreviewGesture->mCallbackData = self;
  1527. // Set the button title
  1528. self->mPreviewBtn->setLabel(self->getString("stop_txt"));
  1529. // Play it, and delete when done
  1530. gGestureManager.playGesture(self->mPreviewGesture);
  1531. self->refresh();
  1532. }
  1533. else
  1534. {
  1535. // Will call onDonePreview() below
  1536. gGestureManager.stopGesture(self->mPreviewGesture);
  1537. self->refresh();
  1538. }
  1539. }
  1540. //static
  1541. void LLPreviewGesture::onDonePreview(LLMultiGesture* gesture, void* data)
  1542. {
  1543. LLPreviewGesture* self = (LLPreviewGesture*)data;
  1544. if (self)
  1545. {
  1546. self->mPreviewBtn->setLabel(self->getString("preview_txt"));
  1547. delete self->mPreviewGesture;
  1548. self->mPreviewGesture = NULL;
  1549. self->refresh();
  1550. }
  1551. }