llpreviewscript.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:59k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llpreviewscript.cpp
  3.  * @brief LLPreviewScript class implementation
  4.  *
  5.  * $LicenseInfo:firstyear=2002&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2002-2010, 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 "llpreviewscript.h"
  34. #include "llassetstorage.h"
  35. #include "llassetuploadresponders.h"
  36. #include "llbutton.h"
  37. #include "llcheckboxctrl.h"
  38. #include "llcombobox.h"
  39. #include "lldir.h"
  40. #include "llfloaterreg.h"
  41. #include "llinventorymodel.h"
  42. #include "llkeyboard.h"
  43. #include "lllineeditor.h"
  44. #include "llhelp.h"
  45. #include "llnotificationsutil.h"
  46. #include "llresmgr.h"
  47. #include "llscrollbar.h"
  48. #include "llscrollcontainer.h"
  49. #include "llscrolllistctrl.h"
  50. #include "llscrolllistitem.h"
  51. #include "llscrolllistcell.h"
  52. #include "llslider.h"
  53. #include "lscript_rt_interface.h"
  54. #include "lscript_library.h"
  55. #include "lscript_export.h"
  56. #include "lltextbox.h"
  57. #include "lltooldraganddrop.h"
  58. #include "llvfile.h"
  59. #include "llagent.h"
  60. #include "llmenugl.h"
  61. #include "roles_constants.h"
  62. #include "llselectmgr.h"
  63. #include "llviewerinventory.h"
  64. #include "llviewermenu.h"
  65. #include "llviewerobject.h"
  66. #include "llviewerobjectlist.h"
  67. #include "llviewerregion.h"
  68. #include "llkeyboard.h"
  69. #include "llscrollcontainer.h"
  70. #include "llcheckboxctrl.h"
  71. #include "llselectmgr.h"
  72. #include "lltooldraganddrop.h"
  73. #include "llscrolllistctrl.h"
  74. #include "lltextbox.h"
  75. #include "llslider.h"
  76. #include "lldir.h"
  77. #include "llcombobox.h"
  78. #include "llviewerstats.h"
  79. #include "llviewertexteditor.h"
  80. #include "llviewerwindow.h"
  81. #include "lluictrlfactory.h"
  82. #include "llmediactrl.h"
  83. #include "lluictrlfactory.h"
  84. #include "lltrans.h"
  85. #include "llviewercontrol.h"
  86. #include "llappviewer.h"
  87. const std::string HELLO_LSL =
  88. "defaultn"
  89. "{n"
  90. "    state_entry()n"
  91.     "    {n"
  92.     "        llSay(0, "Hello, Avatar!");n"
  93.     "    }n"
  94. "n"
  95. "    touch_start(integer total_number)n"
  96. "    {n"
  97. "        llSay(0, "Touched.");n"
  98. "    }n"
  99. "}n";
  100. const std::string HELP_LSL_PORTAL_TOPIC = "LSL_Portal";
  101. const std::string DEFAULT_SCRIPT_NAME = "New Script"; // *TODO:Translate?
  102. const std::string DEFAULT_SCRIPT_DESC = "(No Description)"; // *TODO:Translate?
  103. // Description and header information
  104. const S32 MAX_EXPORT_SIZE = 1000;
  105. const S32 MAX_HISTORY_COUNT = 10;
  106. const F32 LIVE_HELP_REFRESH_TIME = 1.f;
  107. static bool have_script_upload_cap(LLUUID& object_id)
  108. {
  109. LLViewerObject* object = gObjectList.findObject(object_id);
  110. return object && (! object->getRegion()->getCapability("UpdateScriptTask").empty());
  111. }
  112. /// ---------------------------------------------------------------------------
  113. /// LLFloaterScriptSearch
  114. /// ---------------------------------------------------------------------------
  115. class LLFloaterScriptSearch : public LLFloater
  116. {
  117. public:
  118. LLFloaterScriptSearch(LLScriptEdCore* editor_core);
  119. ~LLFloaterScriptSearch();
  120. /*virtual*/ BOOL postBuild();
  121. static void show(LLScriptEdCore* editor_core);
  122. static void onBtnSearch(void* userdata);
  123. void handleBtnSearch();
  124. static void onBtnReplace(void* userdata);
  125. void handleBtnReplace();
  126. static void onBtnReplaceAll(void* userdata);
  127. void handleBtnReplaceAll();
  128. LLScriptEdCore* getEditorCore() { return mEditorCore; }
  129. static LLFloaterScriptSearch* getInstance() { return sInstance; }
  130. private:
  131. LLScriptEdCore* mEditorCore;
  132. static LLFloaterScriptSearch* sInstance;
  133. };
  134. LLFloaterScriptSearch* LLFloaterScriptSearch::sInstance = NULL;
  135. LLFloaterScriptSearch::LLFloaterScriptSearch(LLScriptEdCore* editor_core)
  136. : LLFloater(LLSD()),
  137. mEditorCore(editor_core)
  138. {
  139. LLUICtrlFactory::getInstance()->buildFloater(this,"floater_script_search.xml", NULL);
  140. sInstance = this;
  141. // find floater in which script panel is embedded
  142. LLView* viewp = (LLView*)editor_core;
  143. while(viewp)
  144. {
  145. LLFloater* floaterp = dynamic_cast<LLFloater*>(viewp);
  146. if (floaterp)
  147. {
  148. floaterp->addDependentFloater(this);
  149. break;
  150. }
  151. viewp = viewp->getParent();
  152. }
  153. }
  154. BOOL LLFloaterScriptSearch::postBuild()
  155. {
  156. childSetAction("search_btn", onBtnSearch,this);
  157. childSetAction("replace_btn", onBtnReplace,this);
  158. childSetAction("replace_all_btn", onBtnReplaceAll,this);
  159. setDefaultBtn("search_btn");
  160. return TRUE;
  161. }
  162. //static 
  163. void LLFloaterScriptSearch::show(LLScriptEdCore* editor_core)
  164. {
  165. if (sInstance && sInstance->mEditorCore && sInstance->mEditorCore != editor_core)
  166. {
  167. sInstance->closeFloater();
  168. delete sInstance;
  169. }
  170. if (!sInstance)
  171. {
  172. // sInstance will be assigned in the constructor.
  173. new LLFloaterScriptSearch(editor_core);
  174. }
  175. sInstance->openFloater();
  176. }
  177. LLFloaterScriptSearch::~LLFloaterScriptSearch()
  178. {
  179. sInstance = NULL;
  180. }
  181. // static 
  182. void LLFloaterScriptSearch::onBtnSearch(void *userdata)
  183. {
  184. LLFloaterScriptSearch* self = (LLFloaterScriptSearch*)userdata;
  185. self->handleBtnSearch();
  186. }
  187. void LLFloaterScriptSearch::handleBtnSearch()
  188. {
  189. LLCheckBoxCtrl* caseChk = getChild<LLCheckBoxCtrl>("case_text");
  190. mEditorCore->mEditor->selectNext(childGetText("search_text"), caseChk->get());
  191. }
  192. // static 
  193. void LLFloaterScriptSearch::onBtnReplace(void *userdata)
  194. {
  195. LLFloaterScriptSearch* self = (LLFloaterScriptSearch*)userdata;
  196. self->handleBtnReplace();
  197. }
  198. void LLFloaterScriptSearch::handleBtnReplace()
  199. {
  200. LLCheckBoxCtrl* caseChk = getChild<LLCheckBoxCtrl>("case_text");
  201. mEditorCore->mEditor->replaceText(childGetText("search_text"), childGetText("replace_text"), caseChk->get());
  202. }
  203. // static 
  204. void LLFloaterScriptSearch::onBtnReplaceAll(void *userdata)
  205. {
  206. LLFloaterScriptSearch* self = (LLFloaterScriptSearch*)userdata;
  207. self->handleBtnReplaceAll();
  208. }
  209. void LLFloaterScriptSearch::handleBtnReplaceAll()
  210. {
  211. LLCheckBoxCtrl* caseChk = getChild<LLCheckBoxCtrl>("case_text");
  212. mEditorCore->mEditor->replaceTextAll(childGetText("search_text"), childGetText("replace_text"), caseChk->get());
  213. }
  214. /// ---------------------------------------------------------------------------
  215. /// LLScriptEdCore
  216. /// ---------------------------------------------------------------------------
  217. struct LLSECKeywordCompare
  218. {
  219. bool operator()(const std::string& lhs, const std::string& rhs)
  220. {
  221. return (LLStringUtil::compareDictInsensitive( lhs, rhs ) < 0 );
  222. }
  223. };
  224. LLScriptEdCore::LLScriptEdCore(
  225. const std::string& sample,
  226. const LLHandle<LLFloater>& floater_handle,
  227. void (*load_callback)(void*),
  228. void (*save_callback)(void*, BOOL),
  229. void (*search_replace_callback) (void* userdata),
  230. void* userdata,
  231. S32 bottom_pad)
  232. :
  233. LLPanel(),
  234. mSampleText(sample),
  235. mEditor( NULL ),
  236. mLoadCallback( load_callback ),
  237. mSaveCallback( save_callback ),
  238. mSearchReplaceCallback( search_replace_callback ),
  239. mUserdata( userdata ),
  240. mForceClose( FALSE ),
  241. mLastHelpToken(NULL),
  242. mLiveHelpHistorySize(0),
  243. mEnableSave(FALSE),
  244. mHasScriptData(FALSE)
  245. {
  246. setFollowsAll();
  247. setBorderVisible(FALSE);
  248. setXMLFilename("panel_script_ed.xml");
  249. }
  250. LLScriptEdCore::~LLScriptEdCore()
  251. {
  252. deleteBridges();
  253. // If the search window is up for this editor, close it.
  254. LLFloaterScriptSearch* script_search = LLFloaterScriptSearch::getInstance();
  255. if (script_search && script_search->getEditorCore() == this)
  256. {
  257. script_search->closeFloater();
  258. delete script_search;
  259. }
  260. }
  261. BOOL LLScriptEdCore::postBuild()
  262. {
  263. mErrorList = getChild<LLScrollListCtrl>("lsl errors");
  264. mFunctions = getChild<LLComboBox>( "Insert...");
  265. childSetCommitCallback("Insert...", &LLScriptEdCore::onBtnInsertFunction, this);
  266. mEditor = getChild<LLViewerTextEditor>("Script Editor");
  267. childSetCommitCallback("lsl errors", &LLScriptEdCore::onErrorList, this);
  268. childSetAction("Save_btn", boost::bind(&LLScriptEdCore::doSave,this,FALSE));
  269. initMenu();
  270. std::vector<std::string> funcs;
  271. std::vector<std::string> tooltips;
  272. for (std::vector<LLScriptLibraryFunction>::const_iterator i = gScriptLibrary.mFunctions.begin();
  273. i != gScriptLibrary.mFunctions.end(); ++i)
  274. {
  275. // Make sure this isn't a god only function, or the agent is a god.
  276. if (!i->mGodOnly || gAgent.isGodlike())
  277. {
  278. std::string name = i->mName;
  279. funcs.push_back(name);
  280. std::string desc_name = "LSLTipText_";
  281. desc_name += name;
  282. std::string desc = LLTrans::getString(desc_name);
  283. F32 sleep_time = i->mSleepTime;
  284. if( sleep_time )
  285. {
  286. desc += "n";
  287. LLStringUtil::format_map_t args;
  288. args["[SLEEP_TIME]"] = llformat("%.1f", sleep_time );
  289. desc += LLTrans::getString("LSLTipSleepTime", args);
  290. }
  291. // A n linefeed is not part of xml. Let's add one to keep all
  292. // the tips one-per-line in strings.xml
  293. LLStringUtil::replaceString( desc, "\n", "n" );
  294. tooltips.push_back(desc);
  295. }
  296. }
  297. LLColor3 color(0.5f, 0.0f, 0.15f);
  298. mEditor->loadKeywords(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"keywords.ini"), funcs, tooltips, color);
  299. std::vector<std::string> primary_keywords;
  300. std::vector<std::string> secondary_keywords;
  301. LLKeywordToken *token;
  302. LLKeywords::keyword_iterator_t token_it;
  303. for (token_it = mEditor->keywordsBegin(); token_it != mEditor->keywordsEnd(); ++token_it)
  304. {
  305. token = token_it->second;
  306. if (token->getColor() == color) // Wow, what a disgusting hack.
  307. {
  308. primary_keywords.push_back( wstring_to_utf8str(token->getToken()) );
  309. }
  310. else
  311. {
  312. secondary_keywords.push_back( wstring_to_utf8str(token->getToken()) );
  313. }
  314. }
  315. // Case-insensitive dictionary sort for primary keywords. We don't sort the secondary
  316. // keywords. They're intelligently grouped in keywords.ini.
  317. std::stable_sort( primary_keywords.begin(), primary_keywords.end(), LLSECKeywordCompare() );
  318. for (std::vector<std::string>::const_iterator iter= primary_keywords.begin();
  319. iter!= primary_keywords.end(); ++iter)
  320. {
  321. mFunctions->add(*iter);
  322. }
  323. for (std::vector<std::string>::const_iterator iter= secondary_keywords.begin();
  324. iter!= secondary_keywords.end(); ++iter)
  325. {
  326. mFunctions->add(*iter);
  327. }
  328. return TRUE;
  329. }
  330. void LLScriptEdCore::initMenu()
  331. {
  332. // *TODO: Skinning - make these callbacks data driven
  333. LLMenuItemCallGL* menuItem;
  334. menuItem = getChild<LLMenuItemCallGL>("Save");
  335. menuItem->setClickCallback(boost::bind(&LLScriptEdCore::doSave, this, FALSE));
  336. menuItem->setEnableCallback(boost::bind(&LLScriptEdCore::hasChanged, this));
  337. menuItem = getChild<LLMenuItemCallGL>("Revert All Changes");
  338. menuItem->setClickCallback(boost::bind(&LLScriptEdCore::onBtnUndoChanges, this));
  339. menuItem->setEnableCallback(boost::bind(&LLScriptEdCore::hasChanged, this));
  340. menuItem = getChild<LLMenuItemCallGL>("Undo");
  341. menuItem->setClickCallback(boost::bind(&LLTextEditor::undo, mEditor));
  342. menuItem->setEnableCallback(boost::bind(&LLTextEditor::canUndo, mEditor));
  343. menuItem = getChild<LLMenuItemCallGL>("Redo");
  344. menuItem->setClickCallback(boost::bind(&LLTextEditor::redo, mEditor));
  345. menuItem->setEnableCallback(boost::bind(&LLTextEditor::canRedo, mEditor));
  346. menuItem = getChild<LLMenuItemCallGL>("Cut");
  347. menuItem->setClickCallback(boost::bind(&LLTextEditor::cut, mEditor));
  348. menuItem->setEnableCallback(boost::bind(&LLTextEditor::canCut, mEditor));
  349. menuItem = getChild<LLMenuItemCallGL>("Copy");
  350. menuItem->setClickCallback(boost::bind(&LLTextEditor::copy, mEditor));
  351. menuItem->setEnableCallback(boost::bind(&LLTextEditor::canCopy, mEditor));
  352. menuItem = getChild<LLMenuItemCallGL>("Paste");
  353. menuItem->setClickCallback(boost::bind(&LLTextEditor::paste, mEditor));
  354. menuItem->setEnableCallback(boost::bind(&LLTextEditor::canPaste, mEditor));
  355. menuItem = getChild<LLMenuItemCallGL>("Select All");
  356. menuItem->setClickCallback(boost::bind(&LLTextEditor::selectAll, mEditor));
  357. menuItem->setEnableCallback(boost::bind(&LLTextEditor::canSelectAll, mEditor));
  358. menuItem = getChild<LLMenuItemCallGL>("Search / Replace...");
  359. menuItem->setClickCallback(boost::bind(&LLFloaterScriptSearch::show, this));
  360. menuItem = getChild<LLMenuItemCallGL>("Help...");
  361. menuItem->setClickCallback(boost::bind(&LLScriptEdCore::onBtnHelp, this));
  362. menuItem = getChild<LLMenuItemCallGL>("Keyword Help...");
  363. menuItem->setClickCallback(boost::bind(&LLScriptEdCore::onBtnDynamicHelp, this));
  364. }
  365. void LLScriptEdCore::setScriptText(const std::string& text, BOOL is_valid)
  366. {
  367. if (mEditor)
  368. {
  369. mEditor->setText(text);
  370. mHasScriptData = is_valid;
  371. }
  372. }
  373. bool LLScriptEdCore::hasChanged()
  374. {
  375. if (!mEditor) return false;
  376. return ((!mEditor->isPristine() || mEnableSave) && mHasScriptData);
  377. }
  378. void LLScriptEdCore::draw()
  379. {
  380. BOOL script_changed = hasChanged();
  381. childSetEnabled("Save_btn", script_changed);
  382. if( mEditor->hasFocus() )
  383. {
  384. S32 line = 0;
  385. S32 column = 0;
  386. mEditor->getCurrentLineAndColumn( &line, &column, FALSE );  // don't include wordwrap
  387. LLStringUtil::format_map_t args;
  388. std::string cursor_pos;
  389. args["[LINE]"] = llformat ("%d", line);
  390. args["[COLUMN]"] = llformat ("%d", column);
  391. cursor_pos = LLTrans::getString("CursorPos", args);
  392. childSetText("line_col", cursor_pos);
  393. }
  394. else
  395. {
  396. childSetText("line_col", LLStringUtil::null);
  397. }
  398. updateDynamicHelp();
  399. LLPanel::draw();
  400. }
  401. void LLScriptEdCore::updateDynamicHelp(BOOL immediate)
  402. {
  403. LLFloater* help_floater = mLiveHelpHandle.get();
  404. if (!help_floater) return;
  405. // update back and forward buttons
  406. LLButton* fwd_button = help_floater->getChild<LLButton>("fwd_btn");
  407. LLButton* back_button = help_floater->getChild<LLButton>("back_btn");
  408. LLMediaCtrl* browser = help_floater->getChild<LLMediaCtrl>("lsl_guide_html");
  409. back_button->setEnabled(browser->canNavigateBack());
  410. fwd_button->setEnabled(browser->canNavigateForward());
  411. if (!immediate && !gSavedSettings.getBOOL("ScriptHelpFollowsCursor"))
  412. {
  413. return;
  414. }
  415. LLTextSegmentPtr segment = NULL;
  416. std::vector<LLTextSegmentPtr> selected_segments;
  417. mEditor->getSelectedSegments(selected_segments);
  418. // try segments in selection range first
  419. std::vector<LLTextSegmentPtr>::iterator segment_iter;
  420. for (segment_iter = selected_segments.begin(); segment_iter != selected_segments.end(); ++segment_iter)
  421. {
  422. if((*segment_iter)->getToken() && (*segment_iter)->getToken()->getType() == LLKeywordToken::WORD)
  423. {
  424. segment = *segment_iter;
  425. break;
  426. }
  427. }
  428. // then try previous segment in case we just typed it
  429. if (!segment)
  430. {
  431. const LLTextSegmentPtr test_segment = mEditor->getPreviousSegment();
  432. if(test_segment->getToken() && test_segment->getToken()->getType() == LLKeywordToken::WORD)
  433. {
  434. segment = test_segment;
  435. }
  436. }
  437. if (segment)
  438. {
  439. if (segment->getToken() != mLastHelpToken)
  440. {
  441. mLastHelpToken = segment->getToken();
  442. mLiveHelpTimer.start();
  443. }
  444. if (immediate || (mLiveHelpTimer.getStarted() && mLiveHelpTimer.getElapsedTimeF32() > LIVE_HELP_REFRESH_TIME))
  445. {
  446. std::string help_string = mEditor->getText().substr(segment->getStart(), segment->getEnd() - segment->getStart());
  447. setHelpPage(help_string);
  448. mLiveHelpTimer.stop();
  449. }
  450. }
  451. else
  452. {
  453. if (immediate)
  454. {
  455. setHelpPage(LLStringUtil::null);
  456. }
  457. }
  458. }
  459. void LLScriptEdCore::setHelpPage(const std::string& help_string)
  460. {
  461. LLFloater* help_floater = mLiveHelpHandle.get();
  462. if (!help_floater) return;
  463. LLMediaCtrl* web_browser = help_floater->getChild<LLMediaCtrl>("lsl_guide_html");
  464. if (!web_browser) return;
  465. LLComboBox* history_combo = help_floater->getChild<LLComboBox>("history_combo");
  466. if (!history_combo) return;
  467. LLUIString url_string = gSavedSettings.getString("LSLHelpURL");
  468. url_string.setArg("[LSL_STRING]", help_string);
  469. addHelpItemToHistory(help_string);
  470. web_browser->navigateTo(url_string);
  471. }
  472. void LLScriptEdCore::addHelpItemToHistory(const std::string& help_string)
  473. {
  474. if (help_string.empty()) return;
  475. LLFloater* help_floater = mLiveHelpHandle.get();
  476. if (!help_floater) return;
  477. LLComboBox* history_combo = help_floater->getChild<LLComboBox>("history_combo");
  478. if (!history_combo) return;
  479. // separate history items from full item list
  480. if (mLiveHelpHistorySize == 0)
  481. {
  482. history_combo->addSeparator(ADD_TOP);
  483. }
  484. // delete all history items over history limit
  485. while(mLiveHelpHistorySize > MAX_HISTORY_COUNT - 1)
  486. {
  487. history_combo->remove(mLiveHelpHistorySize - 1);
  488. mLiveHelpHistorySize--;
  489. }
  490. history_combo->setSimple(help_string);
  491. S32 index = history_combo->getCurrentIndex();
  492. // if help string exists in the combo box
  493. if (index >= 0)
  494. {
  495. S32 cur_index = history_combo->getCurrentIndex();
  496. if (cur_index < mLiveHelpHistorySize)
  497. {
  498. // item found in history, bubble up to top
  499. history_combo->remove(history_combo->getCurrentIndex());
  500. mLiveHelpHistorySize--;
  501. }
  502. }
  503. history_combo->add(help_string, LLSD(help_string), ADD_TOP);
  504. history_combo->selectFirstItem();
  505. mLiveHelpHistorySize++;
  506. }
  507. BOOL LLScriptEdCore::canClose()
  508. {
  509. if(mForceClose || !hasChanged())
  510. {
  511. return TRUE;
  512. }
  513. else
  514. {
  515. // Bring up view-modal dialog: Save changes? Yes, No, Cancel
  516. LLNotificationsUtil::add("SaveChanges", LLSD(), LLSD(), boost::bind(&LLScriptEdCore::handleSaveChangesDialog, this, _1, _2));
  517. return FALSE;
  518. }
  519. }
  520. bool LLScriptEdCore::handleSaveChangesDialog(const LLSD& notification, const LLSD& response )
  521. {
  522. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  523. switch( option )
  524. {
  525. case 0:  // "Yes"
  526. // close after saving
  527. doSave( TRUE );
  528. break;
  529. case 1:  // "No"
  530. mForceClose = TRUE;
  531. // This will close immediately because mForceClose is true, so we won't
  532. // infinite loop with these dialogs. JC
  533. ((LLFloater*) getParent())->closeFloater();
  534. break;
  535. case 2: // "Cancel"
  536. default:
  537. // If we were quitting, we didn't really mean it.
  538.         LLAppViewer::instance()->abortQuit();
  539. break;
  540. }
  541. return false;
  542. }
  543. void LLScriptEdCore::onBtnHelp()
  544. {
  545. LLUI::sHelpImpl->showTopic(HELP_LSL_PORTAL_TOPIC);
  546. }
  547. void LLScriptEdCore::onBtnDynamicHelp()
  548. {
  549. LLFloater* live_help_floater = mLiveHelpHandle.get();
  550. if (!live_help_floater)
  551. {
  552. live_help_floater = new LLFloater(LLSD());
  553. LLUICtrlFactory::getInstance()->buildFloater(live_help_floater, "floater_lsl_guide.xml", NULL);
  554. LLFloater* parent = dynamic_cast<LLFloater*>(getParent());
  555. llassert(parent);
  556. if (parent)
  557. parent->addDependentFloater(live_help_floater, TRUE);
  558. live_help_floater->childSetCommitCallback("lock_check", onCheckLock, this);
  559. live_help_floater->childSetValue("lock_check", gSavedSettings.getBOOL("ScriptHelpFollowsCursor"));
  560. live_help_floater->childSetCommitCallback("history_combo", onHelpComboCommit, this);
  561. live_help_floater->childSetAction("back_btn", onClickBack, this);
  562. live_help_floater->childSetAction("fwd_btn", onClickForward, this);
  563. LLMediaCtrl* browser = live_help_floater->getChild<LLMediaCtrl>("lsl_guide_html");
  564. browser->setAlwaysRefresh(TRUE);
  565. LLComboBox* help_combo = live_help_floater->getChild<LLComboBox>("history_combo");
  566. LLKeywordToken *token;
  567. LLKeywords::keyword_iterator_t token_it;
  568. for (token_it = mEditor->keywordsBegin(); 
  569.      token_it != mEditor->keywordsEnd(); 
  570.      ++token_it)
  571. {
  572. token = token_it->second;
  573. help_combo->add(wstring_to_utf8str(token->getToken()));
  574. }
  575. help_combo->sortByName();
  576. // re-initialize help variables
  577. mLastHelpToken = NULL;
  578. mLiveHelpHandle = live_help_floater->getHandle();
  579. mLiveHelpHistorySize = 0;
  580. }
  581. BOOL visible = TRUE;
  582. BOOL take_focus = TRUE;
  583. live_help_floater->setVisible(visible);
  584. live_help_floater->setFrontmost(take_focus);
  585. updateDynamicHelp(TRUE);
  586. }
  587. //static 
  588. void LLScriptEdCore::onClickBack(void* userdata)
  589. {
  590. LLScriptEdCore* corep = (LLScriptEdCore*)userdata;
  591. LLFloater* live_help_floater = corep->mLiveHelpHandle.get();
  592. if (live_help_floater)
  593. {
  594. LLMediaCtrl* browserp = live_help_floater->getChild<LLMediaCtrl>("lsl_guide_html");
  595. if (browserp)
  596. {
  597. browserp->navigateBack();
  598. }
  599. }
  600. }
  601. //static 
  602. void LLScriptEdCore::onClickForward(void* userdata)
  603. {
  604. LLScriptEdCore* corep = (LLScriptEdCore*)userdata;
  605. LLFloater* live_help_floater = corep->mLiveHelpHandle.get();
  606. if (live_help_floater)
  607. {
  608. LLMediaCtrl* browserp = live_help_floater->getChild<LLMediaCtrl>("lsl_guide_html");
  609. if (browserp)
  610. {
  611. browserp->navigateForward();
  612. }
  613. }
  614. }
  615. // static
  616. void LLScriptEdCore::onCheckLock(LLUICtrl* ctrl, void* userdata)
  617. {
  618. LLScriptEdCore* corep = (LLScriptEdCore*)userdata;
  619. // clear out token any time we lock the frame, so we will refresh web page immediately when unlocked
  620. gSavedSettings.setBOOL("ScriptHelpFollowsCursor", ctrl->getValue().asBoolean());
  621. corep->mLastHelpToken = NULL;
  622. }
  623. // static 
  624. void LLScriptEdCore::onBtnInsertSample(void* userdata)
  625. {
  626. LLScriptEdCore* self = (LLScriptEdCore*) userdata;
  627. // Insert sample code
  628. self->mEditor->selectAll();
  629. self->mEditor->cut();
  630. self->mEditor->insertText(self->mSampleText);
  631. }
  632. // static 
  633. void LLScriptEdCore::onHelpComboCommit(LLUICtrl* ctrl, void* userdata)
  634. {
  635. LLScriptEdCore* corep = (LLScriptEdCore*)userdata;
  636. LLFloater* live_help_floater = corep->mLiveHelpHandle.get();
  637. if (live_help_floater)
  638. {
  639. std::string help_string = ctrl->getValue().asString();
  640. corep->addHelpItemToHistory(help_string);
  641. LLMediaCtrl* web_browser = live_help_floater->getChild<LLMediaCtrl>("lsl_guide_html");
  642. LLUIString url_string = gSavedSettings.getString("LSLHelpURL");
  643. url_string.setArg("[LSL_STRING]", help_string);
  644. web_browser->navigateTo(url_string);
  645. }
  646. }
  647. // static 
  648. void LLScriptEdCore::onBtnInsertFunction(LLUICtrl *ui, void* userdata)
  649. {
  650. LLScriptEdCore* self = (LLScriptEdCore*) userdata;
  651. // Insert sample code
  652. if(self->mEditor->getEnabled())
  653. {
  654. self->mEditor->insertText(self->mFunctions->getSimple());
  655. }
  656. self->mEditor->setFocus(TRUE);
  657. self->setHelpPage(self->mFunctions->getSimple());
  658. }
  659. void LLScriptEdCore::doSave( BOOL close_after_save )
  660. {
  661. LLViewerStats::getInstance()->incStat( LLViewerStats::ST_LSL_SAVE_COUNT );
  662. if( mSaveCallback )
  663. {
  664. mSaveCallback( mUserdata, close_after_save );
  665. }
  666. }
  667. void LLScriptEdCore::onBtnUndoChanges()
  668. {
  669. if( !mEditor->tryToRevertToPristineState() )
  670. {
  671. LLNotificationsUtil::add("ScriptCannotUndo", LLSD(), LLSD(), boost::bind(&LLScriptEdCore::handleReloadFromServerDialog, this, _1, _2));
  672. }
  673. }
  674. // static
  675. void LLScriptEdCore::onErrorList(LLUICtrl*, void* user_data)
  676. {
  677. LLScriptEdCore* self = (LLScriptEdCore*)user_data;
  678. LLScrollListItem* item = self->mErrorList->getFirstSelected();
  679. if(item)
  680. {
  681. // *FIX: replace with boost grep
  682. S32 row = 0;
  683. S32 column = 0;
  684. const LLScrollListCell* cell = item->getColumn(0);
  685. std::string line(cell->getValue().asString());
  686. line.erase(0, 1);
  687. LLStringUtil::replaceChar(line, ',',' ');
  688. LLStringUtil::replaceChar(line, ')',' ');
  689. sscanf(line.c_str(), "%d %d", &row, &column);
  690. //llinfos << "LLScriptEdCore::onErrorList() - " << row << ", "
  691. //<< column << llendl;
  692. self->mEditor->setCursor(row, column);
  693. self->mEditor->setFocus(TRUE);
  694. }
  695. }
  696. bool LLScriptEdCore::handleReloadFromServerDialog(const LLSD& notification, const LLSD& response )
  697. {
  698. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  699. switch( option )
  700. {
  701. case 0: // "Yes"
  702. if( mLoadCallback )
  703. {
  704. setScriptText(getString("loading"), FALSE);
  705. mLoadCallback(mUserdata);
  706. }
  707. break;
  708. case 1: // "No"
  709. break;
  710. default:
  711. llassert(0);
  712. break;
  713. }
  714. return false;
  715. }
  716. void LLScriptEdCore::selectFirstError()
  717. {
  718. // Select the first item;
  719. mErrorList->selectFirstItem();
  720. onErrorList(mErrorList, this);
  721. }
  722. struct LLEntryAndEdCore
  723. {
  724. LLScriptEdCore* mCore;
  725. LLEntryAndEdCore(LLScriptEdCore* core) :
  726. mCore(core)
  727. {}
  728. };
  729. void LLScriptEdCore::deleteBridges()
  730. {
  731. S32 count = mBridges.count();
  732. LLEntryAndEdCore* eandc;
  733. for(S32 i = 0; i < count; i++)
  734. {
  735. eandc = mBridges.get(i);
  736. delete eandc;
  737. mBridges[i] = NULL;
  738. }
  739. mBridges.reset();
  740. }
  741. // virtual
  742. BOOL LLScriptEdCore::handleKeyHere(KEY key, MASK mask)
  743. {
  744. bool just_control = MASK_CONTROL == (mask & MASK_MODIFIERS);
  745. if(('S' == key) && just_control)
  746. {
  747. if(mSaveCallback)
  748. {
  749. // don't close after saving
  750. mSaveCallback(mUserdata, FALSE);
  751. }
  752. return TRUE;
  753. }
  754. if(('F' == key) && just_control)
  755. {
  756. if(mSearchReplaceCallback)
  757. {
  758. mSearchReplaceCallback(mUserdata);
  759. }
  760. return TRUE;
  761. }
  762. return FALSE;
  763. }
  764. /// ---------------------------------------------------------------------------
  765. /// LLPreviewLSL
  766. /// ---------------------------------------------------------------------------
  767. struct LLScriptSaveInfo
  768. {
  769. LLUUID mItemUUID;
  770. std::string mDescription;
  771. LLTransactionID mTransactionID;
  772. LLScriptSaveInfo(const LLUUID& uuid, const std::string& desc, LLTransactionID tid) :
  773. mItemUUID(uuid), mDescription(desc),  mTransactionID(tid) {}
  774. };
  775. //static
  776. void* LLPreviewLSL::createScriptEdPanel(void* userdata)
  777. {
  778. LLPreviewLSL *self = (LLPreviewLSL*)userdata;
  779. self->mScriptEd =  new LLScriptEdCore(
  780.    HELLO_LSL,
  781.    self->getHandle(),
  782.    LLPreviewLSL::onLoad,
  783.    LLPreviewLSL::onSave,
  784.    LLPreviewLSL::onSearchReplace,
  785.    self,
  786.    0);
  787. return self->mScriptEd;
  788. }
  789. LLPreviewLSL::LLPreviewLSL(const LLSD& key )
  790.   : LLPreview( key ),
  791. mPendingUploads(0)
  792. {
  793. mFactoryMap["script panel"] = LLCallbackMap(LLPreviewLSL::createScriptEdPanel, this);
  794. //Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this,"floater_script_preview.xml", FALSE);
  795. }
  796. // virtual
  797. BOOL LLPreviewLSL::postBuild()
  798. {
  799. const LLInventoryItem* item = getItem();
  800. llassert(item);
  801. if (item)
  802. {
  803. childSetText("desc", item->getDescription());
  804. }
  805. childSetCommitCallback("desc", LLPreview::onText, this);
  806. childSetPrevalidate("desc", &LLTextValidate::validateASCIIPrintableNoPipe);
  807. return LLPreview::postBuild();
  808. }
  809. // virtual
  810. void LLPreviewLSL::callbackLSLCompileSucceeded()
  811. {
  812. llinfos << "LSL Bytecode saved" << llendl;
  813. mScriptEd->mErrorList->setCommentText(LLTrans::getString("CompileSuccessful"));
  814. mScriptEd->mErrorList->setCommentText(LLTrans::getString("SaveComplete"));
  815. closeIfNeeded();
  816. }
  817. // virtual
  818. void LLPreviewLSL::callbackLSLCompileFailed(const LLSD& compile_errors)
  819. {
  820. llinfos << "Compile failed!" << llendl;
  821. for(LLSD::array_const_iterator line = compile_errors.beginArray();
  822. line < compile_errors.endArray();
  823. line++)
  824. {
  825. LLSD row;
  826. std::string error_message = line->asString();
  827. LLStringUtil::stripNonprintable(error_message);
  828. row["columns"][0]["value"] = error_message;
  829. row["columns"][0]["font"] = "OCRA";
  830. mScriptEd->mErrorList->addElement(row);
  831. }
  832. mScriptEd->selectFirstError();
  833. closeIfNeeded();
  834. }
  835. void LLPreviewLSL::loadAsset()
  836. {
  837. // *HACK: we poke into inventory to see if it's there, and if so,
  838. // then it might be part of the inventory library. If it's in the
  839. // library, then you can see the script, but not modify it.
  840. const LLInventoryItem* item = gInventory.getItem(mItemUUID);
  841. BOOL is_library = item
  842. && !gInventory.isObjectDescendentOf(mItemUUID,
  843. gInventory.getRootFolderID());
  844. if(!item)
  845. {
  846. // do the more generic search.
  847. getItem();
  848. }
  849. if(item)
  850. {
  851. BOOL is_copyable = gAgent.allowOperation(PERM_COPY, 
  852. item->getPermissions(), GP_OBJECT_MANIPULATE);
  853. BOOL is_modifiable = gAgent.allowOperation(PERM_MODIFY,
  854. item->getPermissions(), GP_OBJECT_MANIPULATE);
  855. if (gAgent.isGodlike() || (is_copyable && (is_modifiable || is_library)))
  856. {
  857. LLUUID* new_uuid = new LLUUID(mItemUUID);
  858. gAssetStorage->getInvItemAsset(LLHost::invalid,
  859. gAgent.getID(),
  860. gAgent.getSessionID(),
  861. item->getPermissions().getOwner(),
  862. LLUUID::null,
  863. item->getUUID(),
  864. item->getAssetUUID(),
  865. item->getType(),
  866. &LLPreviewLSL::onLoadComplete,
  867. (void*)new_uuid,
  868. TRUE);
  869. mAssetStatus = PREVIEW_ASSET_LOADING;
  870. }
  871. else
  872. {
  873. mScriptEd->setScriptText(mScriptEd->getString("can_not_view"), FALSE);
  874. mScriptEd->mEditor->makePristine();
  875. mScriptEd->mEditor->setEnabled(FALSE);
  876. mScriptEd->mFunctions->setEnabled(FALSE);
  877. mAssetStatus = PREVIEW_ASSET_LOADED;
  878. }
  879. childSetVisible("lock", !is_modifiable);
  880. mScriptEd->childSetEnabled("Insert...", is_modifiable);
  881. }
  882. else
  883. {
  884. mScriptEd->setScriptText(std::string(HELLO_LSL), TRUE);
  885. mAssetStatus = PREVIEW_ASSET_LOADED;
  886. }
  887. }
  888. BOOL LLPreviewLSL::canClose()
  889. {
  890. return mScriptEd->canClose();
  891. }
  892. void LLPreviewLSL::closeIfNeeded()
  893. {
  894. // Find our window and close it if requested.
  895. getWindow()->decBusyCount();
  896. mPendingUploads--;
  897. if (mPendingUploads <= 0 && mCloseAfterSave)
  898. {
  899. closeFloater();
  900. }
  901. }
  902. void LLPreviewLSL::onSearchReplace(void* userdata)
  903. {
  904. LLPreviewLSL* self = (LLPreviewLSL*)userdata;
  905. LLScriptEdCore* sec = self->mScriptEd; 
  906. LLFloaterScriptSearch::show(sec);
  907. }
  908. // static
  909. void LLPreviewLSL::onLoad(void* userdata)
  910. {
  911. LLPreviewLSL* self = (LLPreviewLSL*)userdata;
  912. self->loadAsset();
  913. }
  914. // static
  915. void LLPreviewLSL::onSave(void* userdata, BOOL close_after_save)
  916. {
  917. LLPreviewLSL* self = (LLPreviewLSL*)userdata;
  918. self->mCloseAfterSave = close_after_save;
  919. self->saveIfNeeded();
  920. }
  921. // Save needs to compile the text in the buffer. If the compile
  922. // succeeds, then save both assets out to the database. If the compile
  923. // fails, go ahead and save the text anyway so that the user doesn't
  924. // get too fucked.
  925. void LLPreviewLSL::saveIfNeeded()
  926. {
  927. // llinfos << "LLPreviewLSL::saveIfNeeded()" << llendl;
  928. if(!mScriptEd->hasChanged())
  929. {
  930. return;
  931. }
  932. mPendingUploads = 0;
  933. mScriptEd->mErrorList->deleteAllItems();
  934. mScriptEd->mEditor->makePristine();
  935. // save off asset into file
  936. LLTransactionID tid;
  937. tid.generate();
  938. LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
  939. std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id.asString());
  940. std::string filename = filepath + ".lsl";
  941. LLFILE* fp = LLFile::fopen(filename, "wb");
  942. if(!fp)
  943. {
  944. llwarns << "Unable to write to " << filename << llendl;
  945. LLSD row;
  946. row["columns"][0]["value"] = "Error writing to local file. Is your hard drive full?";
  947. row["columns"][0]["font"] = "SANSSERIF_SMALL";
  948. mScriptEd->mErrorList->addElement(row);
  949. return;
  950. }
  951. std::string utf8text = mScriptEd->mEditor->getText();
  952. fputs(utf8text.c_str(), fp);
  953. fclose(fp);
  954. fp = NULL;
  955. const LLInventoryItem *inv_item = getItem();
  956. // save it out to asset server
  957. std::string url = gAgent.getRegion()->getCapability("UpdateScriptAgent");
  958. if(inv_item)
  959. {
  960. getWindow()->incBusyCount();
  961. mPendingUploads++;
  962. if (!url.empty())
  963. {
  964. uploadAssetViaCaps(url, filename, mItemUUID);
  965. }
  966. else if (gAssetStorage)
  967. {
  968. uploadAssetLegacy(filename, mItemUUID, tid);
  969. }
  970. }
  971. }
  972. void LLPreviewLSL::uploadAssetViaCaps(const std::string& url,
  973.   const std::string& filename,
  974.   const LLUUID& item_id)
  975. {
  976. llinfos << "Update Agent Inventory via capability" << llendl;
  977. LLSD body;
  978. body["item_id"] = item_id;
  979. body["target"] = "lsl2";
  980. LLHTTPClient::post(url, body, new LLUpdateAgentInventoryResponder(body, filename, LLAssetType::AT_LSL_TEXT));
  981. }
  982. void LLPreviewLSL::uploadAssetLegacy(const std::string& filename,
  983.   const LLUUID& item_id,
  984.   const LLTransactionID& tid)
  985. {
  986. LLLineEditor* descEditor = getChild<LLLineEditor>("desc");
  987. LLScriptSaveInfo* info = new LLScriptSaveInfo(item_id,
  988. descEditor->getText(),
  989. tid);
  990. gAssetStorage->storeAssetData(filename, tid,
  991.   LLAssetType::AT_LSL_TEXT,
  992.   &LLPreviewLSL::onSaveComplete,
  993.   info);
  994. LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
  995. std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id.asString());
  996. std::string dst_filename = llformat("%s.lso", filepath.c_str());
  997. std::string err_filename = llformat("%s.out", filepath.c_str());
  998. const BOOL compile_to_mono = FALSE;
  999. if(!lscript_compile(filename.c_str(),
  1000. dst_filename.c_str(),
  1001. err_filename.c_str(),
  1002. compile_to_mono,
  1003. asset_id.asString().c_str(),
  1004. gAgent.isGodlike()))
  1005. {
  1006. llinfos << "Compile failed!" << llendl;
  1007. //char command[256];
  1008. //sprintf(command, "type %sn", err_filename.c_str());
  1009. //system(command);
  1010. // load the error file into the error scrolllist
  1011. LLFILE* fp = LLFile::fopen(err_filename, "r");
  1012. if(fp)
  1013. {
  1014. char buffer[MAX_STRING]; /*Flawfinder: ignore*/
  1015. std::string line;
  1016. while(!feof(fp)) 
  1017. {
  1018. if (fgets(buffer, MAX_STRING, fp) == NULL)
  1019. {
  1020. buffer[0] = '';
  1021. }
  1022. if(feof(fp))
  1023. {
  1024. break;
  1025. }
  1026. else
  1027. {
  1028. line.assign(buffer);
  1029. LLStringUtil::stripNonprintable(line);
  1030. LLSD row;
  1031. row["columns"][0]["value"] = line;
  1032. row["columns"][0]["font"] = "OCRA";
  1033. mScriptEd->mErrorList->addElement(row);
  1034. }
  1035. }
  1036. fclose(fp);
  1037. mScriptEd->selectFirstError();
  1038. }
  1039. }
  1040. else
  1041. {
  1042. llinfos << "Compile worked!" << llendl;
  1043. if(gAssetStorage)
  1044. {
  1045. getWindow()->incBusyCount();
  1046. mPendingUploads++;
  1047. LLUUID* this_uuid = new LLUUID(mItemUUID);
  1048. gAssetStorage->storeAssetData(dst_filename,
  1049.   tid,
  1050.   LLAssetType::AT_LSL_BYTECODE,
  1051.   &LLPreviewLSL::onSaveBytecodeComplete,
  1052.   (void**)this_uuid);
  1053. }
  1054. }
  1055. // get rid of any temp files left lying around
  1056. LLFile::remove(filename);
  1057. LLFile::remove(err_filename);
  1058. LLFile::remove(dst_filename);
  1059. }
  1060. // static
  1061. void LLPreviewLSL::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed)
  1062. {
  1063. LLScriptSaveInfo* info = reinterpret_cast<LLScriptSaveInfo*>(user_data);
  1064. if(0 == status)
  1065. {
  1066. if (info)
  1067. {
  1068. const LLViewerInventoryItem* item;
  1069. item = (const LLViewerInventoryItem*)gInventory.getItem(info->mItemUUID);
  1070. if(item)
  1071. {
  1072. LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
  1073. new_item->setAssetUUID(asset_uuid);
  1074. new_item->setTransactionID(info->mTransactionID);
  1075. new_item->updateServer(FALSE);
  1076. gInventory.updateItem(new_item);
  1077. gInventory.notifyObservers();
  1078. }
  1079. else
  1080. {
  1081. llwarns << "Inventory item for script " << info->mItemUUID
  1082. << " is no longer in agent inventory." << llendl;
  1083. }
  1084. // Find our window and close it if requested.
  1085. LLPreviewLSL* self = LLFloaterReg::findTypedInstance<LLPreviewLSL>("preview_script", info->mItemUUID);
  1086. if (self)
  1087. {
  1088. getWindow()->decBusyCount();
  1089. self->mPendingUploads--;
  1090. if (self->mPendingUploads <= 0
  1091. && self->mCloseAfterSave)
  1092. {
  1093. self->closeFloater();
  1094. }
  1095. }
  1096. }
  1097. }
  1098. else
  1099. {
  1100. llwarns << "Problem saving script: " << status << llendl;
  1101. LLSD args;
  1102. args["REASON"] = std::string(LLAssetStorage::getErrorString(status));
  1103. LLNotificationsUtil::add("SaveScriptFailReason", args);
  1104. }
  1105. delete info;
  1106. }
  1107. // static
  1108. void LLPreviewLSL::onSaveBytecodeComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed)
  1109. {
  1110. LLUUID* instance_uuid = (LLUUID*)user_data;
  1111. LLPreviewLSL* self = NULL;
  1112. if(instance_uuid)
  1113. {
  1114. self = LLFloaterReg::findTypedInstance<LLPreviewLSL>("preview_script", *instance_uuid);
  1115. }
  1116. if (0 == status)
  1117. {
  1118. if (self)
  1119. {
  1120. LLSD row;
  1121. row["columns"][0]["value"] = "Compile successful!";
  1122. row["columns"][0]["font"] = "SANSSERIF_SMALL";
  1123. self->mScriptEd->mErrorList->addElement(row);
  1124. // Find our window and close it if requested.
  1125. self->getWindow()->decBusyCount();
  1126. self->mPendingUploads--;
  1127. if (self->mPendingUploads <= 0
  1128. && self->mCloseAfterSave)
  1129. {
  1130. self->closeFloater();
  1131. }
  1132. }
  1133. }
  1134. else
  1135. {
  1136. llwarns << "Problem saving LSL Bytecode (Preview)" << llendl;
  1137. LLSD args;
  1138. args["REASON"] = std::string(LLAssetStorage::getErrorString(status));
  1139. LLNotificationsUtil::add("SaveBytecodeFailReason", args);
  1140. }
  1141. delete instance_uuid;
  1142. }
  1143. // static
  1144. void LLPreviewLSL::onLoadComplete( LLVFS *vfs, const LLUUID& asset_uuid, LLAssetType::EType type,
  1145.    void* user_data, S32 status, LLExtStat ext_status)
  1146. {
  1147. lldebugs << "LLPreviewLSL::onLoadComplete: got uuid " << asset_uuid
  1148.  << llendl;
  1149. LLUUID* item_uuid = (LLUUID*)user_data;
  1150. LLPreviewLSL* preview = LLFloaterReg::findTypedInstance<LLPreviewLSL>("preview_script", *item_uuid);
  1151. if( preview )
  1152. {
  1153. if(0 == status)
  1154. {
  1155. LLVFile file(vfs, asset_uuid, type);
  1156. S32 file_length = file.getSize();
  1157. std::vector<char> buffer(file_length+1);
  1158. file.read((U8*)&buffer[0], file_length);
  1159. // put a EOS at the end
  1160. buffer[file_length] = 0;
  1161. preview->mScriptEd->setScriptText(LLStringExplicit(&buffer[0]), TRUE);
  1162. preview->mScriptEd->mEditor->makePristine();
  1163. LLInventoryItem* item = gInventory.getItem(*item_uuid);
  1164. BOOL is_modifiable = FALSE;
  1165. if(item
  1166.    && gAgent.allowOperation(PERM_MODIFY, item->getPermissions(),
  1167.     GP_OBJECT_MANIPULATE))
  1168. {
  1169. is_modifiable = TRUE;
  1170. }
  1171. preview->mScriptEd->mEditor->setEnabled(is_modifiable);
  1172. preview->mAssetStatus = PREVIEW_ASSET_LOADED;
  1173. }
  1174. else
  1175. {
  1176. LLViewerStats::getInstance()->incStat( LLViewerStats::ST_DOWNLOAD_FAILED );
  1177. if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
  1178. LL_ERR_FILE_EMPTY == status)
  1179. {
  1180. LLNotificationsUtil::add("ScriptMissing");
  1181. }
  1182. else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status)
  1183. {
  1184. LLNotificationsUtil::add("ScriptNoPermissions");
  1185. }
  1186. else
  1187. {
  1188. LLNotificationsUtil::add("UnableToLoadScript");
  1189. }
  1190. preview->mAssetStatus = PREVIEW_ASSET_ERROR;
  1191. llwarns << "Problem loading script: " << status << llendl;
  1192. }
  1193. }
  1194. delete item_uuid;
  1195. }
  1196. /// ---------------------------------------------------------------------------
  1197. /// LLLiveLSLEditor
  1198. /// ---------------------------------------------------------------------------
  1199. //static 
  1200. void* LLLiveLSLEditor::createScriptEdPanel(void* userdata)
  1201. {
  1202. LLLiveLSLEditor *self = (LLLiveLSLEditor*)userdata;
  1203. self->mScriptEd =  new LLScriptEdCore(
  1204.    HELLO_LSL,
  1205.    self->getHandle(),
  1206.    &LLLiveLSLEditor::onLoad,
  1207.    &LLLiveLSLEditor::onSave,
  1208.    &LLLiveLSLEditor::onSearchReplace,
  1209.    self,
  1210.    0);
  1211. return self->mScriptEd;
  1212. }
  1213. LLLiveLSLEditor::LLLiveLSLEditor(const LLSD& key) :
  1214. LLPreview(key),
  1215. mScriptEd(NULL),
  1216. mAskedForRunningInfo(FALSE),
  1217. mHaveRunningInfo(FALSE),
  1218. mCloseAfterSave(FALSE),
  1219. mPendingUploads(0),
  1220. mIsModifiable(FALSE),
  1221. mIsNew(false)
  1222. {
  1223. mFactoryMap["script ed panel"] = LLCallbackMap(LLLiveLSLEditor::createScriptEdPanel, this);
  1224. //Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this,"floater_live_lsleditor.xml", FALSE);
  1225. }
  1226. BOOL LLLiveLSLEditor::postBuild()
  1227. {
  1228. childSetCommitCallback("running", LLLiveLSLEditor::onRunningCheckboxClicked, this);
  1229. childSetEnabled("running", FALSE);
  1230. childSetAction("Reset",&LLLiveLSLEditor::onReset,this);
  1231. childSetEnabled("Reset", TRUE);
  1232. mMonoCheckbox = getChild<LLCheckBoxCtrl>("mono");
  1233. childSetCommitCallback("mono", &LLLiveLSLEditor::onMonoCheckboxClicked, this);
  1234. childSetEnabled("mono", FALSE);
  1235. mScriptEd->mEditor->makePristine();
  1236. mScriptEd->mEditor->setFocus(TRUE);
  1237. return LLPreview::postBuild();
  1238. }
  1239. LLLiveLSLEditor::~LLLiveLSLEditor()
  1240. {
  1241. }
  1242. // virtual
  1243. void LLLiveLSLEditor::callbackLSLCompileSucceeded(const LLUUID& task_id,
  1244.   const LLUUID& item_id,
  1245.   bool is_script_running)
  1246. {
  1247. lldebugs << "LSL Bytecode saved" << llendl;
  1248. mScriptEd->mErrorList->setCommentText(LLTrans::getString("CompileSuccessful"));
  1249. mScriptEd->mErrorList->setCommentText(LLTrans::getString("SaveComplete"));
  1250. closeIfNeeded();
  1251. }
  1252. // virtual
  1253. void LLLiveLSLEditor::callbackLSLCompileFailed(const LLSD& compile_errors)
  1254. {
  1255. lldebugs << "Compile failed!" << llendl;
  1256. for(LLSD::array_const_iterator line = compile_errors.beginArray();
  1257. line < compile_errors.endArray();
  1258. line++)
  1259. {
  1260. LLSD row;
  1261. std::string error_message = line->asString();
  1262. LLStringUtil::stripNonprintable(error_message);
  1263. row["columns"][0]["value"] = error_message;
  1264. // *TODO: change to "MONOSPACE" and change llfontgl.cpp?
  1265. row["columns"][0]["font"] = "OCRA";
  1266. mScriptEd->mErrorList->addElement(row);
  1267. }
  1268. mScriptEd->selectFirstError();
  1269. closeIfNeeded();
  1270. }
  1271. void LLLiveLSLEditor::loadAsset()
  1272. {
  1273. //llinfos << "LLLiveLSLEditor::loadAsset()" << llendl;
  1274. if(!mIsNew)
  1275. {
  1276. LLViewerObject* object = gObjectList.findObject(mObjectUUID);
  1277. if(object)
  1278. {
  1279. LLViewerInventoryItem* item = dynamic_cast<LLViewerInventoryItem*>(object->getInventoryObject(mItemUUID));
  1280. if(item 
  1281. && (gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE)
  1282.    || gAgent.isGodlike()))
  1283. {
  1284. mItem = new LLViewerInventoryItem(item);
  1285. //llinfos << "asset id " << mItem->getAssetUUID() << llendl;
  1286. }
  1287. if(!gAgent.isGodlike()
  1288.    && (item
  1289.    && (!gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE)
  1290.    || !gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE))))
  1291. {
  1292. mItem = new LLViewerInventoryItem(item);
  1293. mScriptEd->setScriptText(getString("not_allowed"), FALSE);
  1294. mScriptEd->mEditor->makePristine();
  1295. mScriptEd->mEditor->setEnabled(FALSE);
  1296. mScriptEd->enableSave(FALSE);
  1297. mAssetStatus = PREVIEW_ASSET_LOADED;
  1298. }
  1299. else if(item && mItem.notNull())
  1300. {
  1301. // request the text from the object
  1302. LLUUID* user_data = new LLUUID(mItemUUID); //  ^ mObjectUUID
  1303. gAssetStorage->getInvItemAsset(object->getRegion()->getHost(),
  1304.    gAgent.getID(),
  1305.    gAgent.getSessionID(),
  1306.    item->getPermissions().getOwner(),
  1307.    object->getID(),
  1308.    item->getUUID(),
  1309.    item->getAssetUUID(),
  1310.    item->getType(),
  1311.    &LLLiveLSLEditor::onLoadComplete,
  1312.    (void*)user_data,
  1313.    TRUE);
  1314. LLMessageSystem* msg = gMessageSystem;
  1315. msg->newMessageFast(_PREHASH_GetScriptRunning);
  1316. msg->nextBlockFast(_PREHASH_Script);
  1317. msg->addUUIDFast(_PREHASH_ObjectID, mObjectUUID);
  1318. msg->addUUIDFast(_PREHASH_ItemID, mItemUUID);
  1319. msg->sendReliable(object->getRegion()->getHost());
  1320. mAskedForRunningInfo = TRUE;
  1321. mAssetStatus = PREVIEW_ASSET_LOADING;
  1322. }
  1323. else
  1324. {
  1325. mScriptEd->setScriptText(LLStringUtil::null, FALSE);
  1326. mScriptEd->mEditor->makePristine();
  1327. mAssetStatus = PREVIEW_ASSET_LOADED;
  1328. }
  1329. mIsModifiable = item && gAgent.allowOperation(PERM_MODIFY, 
  1330. item->getPermissions(),
  1331.     GP_OBJECT_MANIPULATE);
  1332. if(!mIsModifiable)
  1333. {
  1334. mScriptEd->mEditor->setEnabled(FALSE);
  1335. }
  1336. // This is commented out, because we don't completely
  1337. // handle script exports yet.
  1338. /*
  1339. // request the exports from the object
  1340. gMessageSystem->newMessage("GetScriptExports");
  1341. gMessageSystem->nextBlock("ScriptBlock");
  1342. gMessageSystem->addUUID("AgentID", gAgent.getID());
  1343. U32 local_id = object->getLocalID();
  1344. gMessageSystem->addData("LocalID", &local_id);
  1345. gMessageSystem->addUUID("ItemID", mItemUUID);
  1346. LLHost host(object->getRegion()->getIP(),
  1347. object->getRegion()->getPort());
  1348. gMessageSystem->sendReliable(host);
  1349. */
  1350. }
  1351. }
  1352. else
  1353. {
  1354. mScriptEd->setScriptText(std::string(HELLO_LSL), TRUE);
  1355. mScriptEd->enableSave(FALSE);
  1356. LLPermissions perm;
  1357. perm.init(gAgent.getID(), gAgent.getID(), LLUUID::null, gAgent.getGroupID());
  1358. perm.initMasks(PERM_ALL, PERM_ALL, PERM_NONE, PERM_NONE, PERM_MOVE | PERM_TRANSFER);
  1359. mItem = new LLViewerInventoryItem(mItemUUID,
  1360.   mObjectUUID,
  1361.   perm,
  1362.   LLUUID::null,
  1363.   LLAssetType::AT_LSL_TEXT,
  1364.   LLInventoryType::IT_LSL,
  1365.   DEFAULT_SCRIPT_NAME,
  1366.   DEFAULT_SCRIPT_DESC,
  1367.   LLSaleInfo::DEFAULT,
  1368.   LLInventoryItem::II_FLAGS_NONE,
  1369.   time_corrected());
  1370. mAssetStatus = PREVIEW_ASSET_LOADED;
  1371. }
  1372. }
  1373. // static
  1374. void LLLiveLSLEditor::onLoadComplete(LLVFS *vfs, const LLUUID& asset_id,
  1375.  LLAssetType::EType type,
  1376.  void* user_data, S32 status, LLExtStat ext_status)
  1377. {
  1378. lldebugs << "LLLiveLSLEditor::onLoadComplete: got uuid " << asset_id
  1379.  << llendl;
  1380. LLUUID* xored_id = (LLUUID*)user_data;
  1381. LLLiveLSLEditor* instance = LLFloaterReg::findTypedInstance<LLLiveLSLEditor>("preview_scriptedit", *xored_id);
  1382. if(instance )
  1383. {
  1384. if( LL_ERR_NOERR == status )
  1385. {
  1386. instance->loadScriptText(vfs, asset_id, type);
  1387. instance->mAssetStatus = PREVIEW_ASSET_LOADED;
  1388. }
  1389. else
  1390. {
  1391. LLViewerStats::getInstance()->incStat( LLViewerStats::ST_DOWNLOAD_FAILED );
  1392. if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
  1393. LL_ERR_FILE_EMPTY == status)
  1394. {
  1395. LLNotificationsUtil::add("ScriptMissing");
  1396. }
  1397. else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status)
  1398. {
  1399. LLNotificationsUtil::add("ScriptNoPermissions");
  1400. }
  1401. else
  1402. {
  1403. LLNotificationsUtil::add("UnableToLoadScript");
  1404. }
  1405. instance->mAssetStatus = PREVIEW_ASSET_ERROR;
  1406. }
  1407. }
  1408. delete xored_id;
  1409. }
  1410. // unused
  1411. // void LLLiveLSLEditor::loadScriptText(const std::string& filename)
  1412. // {
  1413. //  if(!filename)
  1414. //  {
  1415. //  llerrs << "Filename is Empty!" << llendl;
  1416. //  return;
  1417. //  }
  1418. //  LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/
  1419. //  if(file)
  1420. //  {
  1421. //  // read in the whole file
  1422. //  fseek(file, 0L, SEEK_END);
  1423. //  long file_length = ftell(file);
  1424. //  fseek(file, 0L, SEEK_SET);
  1425. //  char* buffer = new char[file_length+1];
  1426. //  size_t nread = fread(buffer, 1, file_length, file);
  1427. //  if (nread < (size_t) file_length)
  1428. //  {
  1429. //  llwarns << "Short read" << llendl;
  1430. //  }
  1431. //  buffer[nread] = '';
  1432. //  fclose(file);
  1433. //  mScriptEd->mEditor->setText(LLStringExplicit(buffer));
  1434. //  mScriptEd->mEditor->makePristine();
  1435. //  delete[] buffer;
  1436. //  }
  1437. //  else
  1438. //  {
  1439. //  llwarns << "Error opening " << filename << llendl;
  1440. //  }
  1441. // }
  1442. void LLLiveLSLEditor::loadScriptText(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type)
  1443. {
  1444. LLVFile file(vfs, uuid, type);
  1445. S32 file_length = file.getSize();
  1446. std::vector<char> buffer(file_length + 1);
  1447. file.read((U8*)&buffer[0], file_length);
  1448. if (file.getLastBytesRead() != file_length ||
  1449. file_length <= 0)
  1450. {
  1451. llwarns << "Error reading " << uuid << ":" << type << llendl;
  1452. }
  1453. buffer[file_length] = '';
  1454. mScriptEd->setScriptText(LLStringExplicit(&buffer[0]), TRUE);
  1455. mScriptEd->mEditor->makePristine();
  1456. }
  1457. void LLLiveLSLEditor::onRunningCheckboxClicked( LLUICtrl*, void* userdata )
  1458. {
  1459. LLLiveLSLEditor* self = (LLLiveLSLEditor*) userdata;
  1460. LLViewerObject* object = gObjectList.findObject( self->mObjectUUID );
  1461. LLCheckBoxCtrl* runningCheckbox = self->getChild<LLCheckBoxCtrl>("running");
  1462. BOOL running =  runningCheckbox->get();
  1463. //self->mRunningCheckbox->get();
  1464. if( object )
  1465. {
  1466. LLMessageSystem* msg = gMessageSystem;
  1467. msg->newMessageFast(_PREHASH_SetScriptRunning);
  1468. msg->nextBlockFast(_PREHASH_AgentData);
  1469. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  1470. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  1471. msg->nextBlockFast(_PREHASH_Script);
  1472. msg->addUUIDFast(_PREHASH_ObjectID, self->mObjectUUID);
  1473. msg->addUUIDFast(_PREHASH_ItemID, self->mItemUUID);
  1474. msg->addBOOLFast(_PREHASH_Running, running);
  1475. msg->sendReliable(object->getRegion()->getHost());
  1476. }
  1477. else
  1478. {
  1479. runningCheckbox->set(!running);
  1480. LLNotificationsUtil::add("CouldNotStartStopScript");
  1481. }
  1482. }
  1483. void LLLiveLSLEditor::onReset(void *userdata)
  1484. {
  1485. LLLiveLSLEditor* self = (LLLiveLSLEditor*) userdata;
  1486. LLViewerObject* object = gObjectList.findObject( self->mObjectUUID );
  1487. if(object)
  1488. {
  1489. LLMessageSystem* msg = gMessageSystem;
  1490. msg->newMessageFast(_PREHASH_ScriptReset);
  1491. msg->nextBlockFast(_PREHASH_AgentData);
  1492. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  1493. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  1494. msg->nextBlockFast(_PREHASH_Script);
  1495. msg->addUUIDFast(_PREHASH_ObjectID, self->mObjectUUID);
  1496. msg->addUUIDFast(_PREHASH_ItemID, self->mItemUUID);
  1497. msg->sendReliable(object->getRegion()->getHost());
  1498. }
  1499. else
  1500. {
  1501. LLNotificationsUtil::add("CouldNotStartStopScript"); 
  1502. }
  1503. }
  1504. void LLLiveLSLEditor::draw()
  1505. {
  1506. LLViewerObject* object = gObjectList.findObject(mObjectUUID);
  1507. LLCheckBoxCtrl* runningCheckbox = getChild<LLCheckBoxCtrl>( "running");
  1508. if(object && mAskedForRunningInfo && mHaveRunningInfo)
  1509. {
  1510. if(object->permAnyOwner())
  1511. {
  1512. runningCheckbox->setLabel(getString("script_running"));
  1513. runningCheckbox->setEnabled(TRUE);
  1514. if(object->permAnyOwner())
  1515. {
  1516. runningCheckbox->setLabel(getString("script_running"));
  1517. runningCheckbox->setEnabled(TRUE);
  1518. }
  1519. else
  1520. {
  1521. runningCheckbox->setLabel(getString("public_objects_can_not_run"));
  1522. runningCheckbox->setEnabled(FALSE);
  1523. // *FIX: Set it to false so that the ui is correct for
  1524. // a box that is released to public. It could be
  1525. // incorrect after a release/claim cycle, but will be
  1526. // correct after clicking on it.
  1527. runningCheckbox->set(FALSE);
  1528. mMonoCheckbox->set(FALSE);
  1529. }
  1530. }
  1531. else
  1532. {
  1533. runningCheckbox->setLabel(getString("public_objects_can_not_run"));
  1534. runningCheckbox->setEnabled(FALSE);
  1535. // *FIX: Set it to false so that the ui is correct for
  1536. // a box that is released to public. It could be
  1537. // incorrect after a release/claim cycle, but will be
  1538. // correct after clicking on it.
  1539. runningCheckbox->set(FALSE);
  1540. mMonoCheckbox->setEnabled(FALSE);
  1541. // object may have fallen out of range.
  1542. mHaveRunningInfo = FALSE;
  1543. }
  1544. }
  1545. else if(!object)
  1546. {
  1547. // HACK: Display this information in the title bar.
  1548. // Really ought to put in main window.
  1549. setTitle(LLTrans::getString("ObjectOutOfRange"));
  1550. runningCheckbox->setEnabled(FALSE);
  1551. // object may have fallen out of range.
  1552. mHaveRunningInfo = FALSE;
  1553. }
  1554. LLPreview::draw();
  1555. }
  1556. void LLLiveLSLEditor::onSearchReplace(void* userdata)
  1557. {
  1558. LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata;
  1559. LLScriptEdCore* sec = self->mScriptEd; 
  1560. LLFloaterScriptSearch::show(sec);
  1561. }
  1562. struct LLLiveLSLSaveData
  1563. {
  1564. LLLiveLSLSaveData(const LLUUID& id, const LLViewerInventoryItem* item, BOOL active);
  1565. LLUUID mSaveObjectID;
  1566. LLPointer<LLViewerInventoryItem> mItem;
  1567. BOOL mActive;
  1568. };
  1569. LLLiveLSLSaveData::LLLiveLSLSaveData(const LLUUID& id,
  1570.  const LLViewerInventoryItem* item,
  1571.  BOOL active) :
  1572. mSaveObjectID(id),
  1573. mActive(active)
  1574. {
  1575. llassert(item);
  1576. mItem = new LLViewerInventoryItem(item);
  1577. }
  1578. void LLLiveLSLEditor::saveIfNeeded()
  1579. {
  1580. llinfos << "LLLiveLSLEditor::saveIfNeeded()" << llendl;
  1581. LLViewerObject* object = gObjectList.findObject(mObjectUUID);
  1582. if(!object)
  1583. {
  1584. LLNotificationsUtil::add("SaveScriptFailObjectNotFound");
  1585. return;
  1586. }
  1587. if(mItem.isNull() || !mItem->isComplete())
  1588. {
  1589. // $NOTE: While the error message may not be exactly correct,
  1590. // it's pretty close.
  1591. LLNotificationsUtil::add("SaveScriptFailObjectNotFound");
  1592. return;
  1593. }
  1594. // get the latest info about it. We used to be losing the script
  1595. // name on save, because the viewer object version of the item,
  1596. // and the editor version would get out of synch. Here's a good
  1597. // place to synch them back up.
  1598. LLInventoryItem* inv_item = dynamic_cast<LLInventoryItem*>(object->getInventoryObject(mItemUUID));
  1599. if(inv_item)
  1600. {
  1601. mItem->copyItem(inv_item);
  1602. }
  1603. // Don't need to save if we're pristine
  1604. if(!mScriptEd->hasChanged())
  1605. {
  1606. return;
  1607. }
  1608. mPendingUploads = 0;
  1609. // save the script
  1610. mScriptEd->enableSave(FALSE);
  1611. mScriptEd->mEditor->makePristine();
  1612. mScriptEd->mErrorList->deleteAllItems();
  1613. // set up the save on the local machine.
  1614. mScriptEd->mEditor->makePristine();
  1615. LLTransactionID tid;
  1616. tid.generate();
  1617. LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
  1618. std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id.asString());
  1619. std::string filename = llformat("%s.lsl", filepath.c_str());
  1620. mItem->setAssetUUID(asset_id);
  1621. mItem->setTransactionID(tid);
  1622. // write out the data, and store it in the asset database
  1623. LLFILE* fp = LLFile::fopen(filename, "wb");
  1624. if(!fp)
  1625. {
  1626. llwarns << "Unable to write to " << filename << llendl;
  1627. LLSD row;
  1628. row["columns"][0]["value"] = "Error writing to local file. Is your hard drive full?";
  1629. row["columns"][0]["font"] = "SANSSERIF_SMALL";
  1630. mScriptEd->mErrorList->addElement(row);
  1631. return;
  1632. }
  1633. std::string utf8text = mScriptEd->mEditor->getText();
  1634. // Special case for a completely empty script - stuff in one space so it can store properly.  See SL-46889
  1635. if ( utf8text.size() == 0 )
  1636. {
  1637. utf8text = " ";
  1638. }
  1639. fputs(utf8text.c_str(), fp);
  1640. fclose(fp);
  1641. fp = NULL;
  1642. // save it out to asset server
  1643. std::string url = object->getRegion()->getCapability("UpdateScriptTask");
  1644. getWindow()->incBusyCount();
  1645. mPendingUploads++;
  1646. BOOL is_running = getChild<LLCheckBoxCtrl>( "running")->get();
  1647. if (!url.empty())
  1648. {
  1649. uploadAssetViaCaps(url, filename, mObjectUUID, mItemUUID, is_running);
  1650. }
  1651. else if (gAssetStorage)
  1652. {
  1653. uploadAssetLegacy(filename, object, tid, is_running);
  1654. }
  1655. }
  1656. void LLLiveLSLEditor::uploadAssetViaCaps(const std::string& url,
  1657.  const std::string& filename,
  1658.  const LLUUID& task_id,
  1659.  const LLUUID& item_id,
  1660.  BOOL is_running)
  1661. {
  1662. llinfos << "Update Task Inventory via capability " << url << llendl;
  1663. LLSD body;
  1664. body["task_id"] = task_id;
  1665. body["item_id"] = item_id;
  1666. body["is_script_running"] = is_running;
  1667. body["target"] = monoChecked() ? "mono" : "lsl2";
  1668. LLHTTPClient::post(url, body,
  1669. new LLUpdateTaskInventoryResponder(body, filename, LLAssetType::AT_LSL_TEXT));
  1670. }
  1671. void LLLiveLSLEditor::uploadAssetLegacy(const std::string& filename,
  1672. LLViewerObject* object,
  1673. const LLTransactionID& tid,
  1674. BOOL is_running)
  1675. {
  1676. LLLiveLSLSaveData* data = new LLLiveLSLSaveData(mObjectUUID,
  1677. mItem,
  1678. is_running);
  1679. gAssetStorage->storeAssetData(filename, tid,
  1680.   LLAssetType::AT_LSL_TEXT,
  1681.   &onSaveTextComplete,
  1682.   (void*)data,
  1683.   FALSE);
  1684. LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
  1685. std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id.asString());
  1686. std::string dst_filename = llformat("%s.lso", filepath.c_str());
  1687. std::string err_filename = llformat("%s.out", filepath.c_str());
  1688. LLFILE *fp;
  1689. const BOOL compile_to_mono = FALSE;
  1690. if(!lscript_compile(filename.c_str(),
  1691. dst_filename.c_str(),
  1692. err_filename.c_str(),
  1693. compile_to_mono,
  1694. asset_id.asString().c_str(),
  1695. gAgent.isGodlike()))
  1696. {
  1697. // load the error file into the error scrolllist
  1698. llinfos << "Compile failed!" << llendl;
  1699. if(NULL != (fp = LLFile::fopen(err_filename, "r")))
  1700. {
  1701. char buffer[MAX_STRING]; /*Flawfinder: ignore*/
  1702. std::string line;
  1703. while(!feof(fp)) 
  1704. {
  1705. if (fgets(buffer, MAX_STRING, fp) == NULL)
  1706. {
  1707. buffer[0] = '';
  1708. }
  1709. if(feof(fp))
  1710. {
  1711. break;
  1712. }
  1713. else
  1714. {
  1715. line.assign(buffer);
  1716. LLStringUtil::stripNonprintable(line);
  1717. LLSD row;
  1718. row["columns"][0]["value"] = line;
  1719. row["columns"][0]["font"] = "OCRA";
  1720. mScriptEd->mErrorList->addElement(row);
  1721. }
  1722. }
  1723. fclose(fp);
  1724. mScriptEd->selectFirstError();
  1725. // don't set the asset id, because we want to save the
  1726. // script, even though the compile failed.
  1727. //mItem->setAssetUUID(LLUUID::null);
  1728. object->saveScript(mItem, FALSE, false);
  1729. dialog_refresh_all();
  1730. }
  1731. }
  1732. else
  1733. {
  1734. llinfos << "Compile worked!" << llendl;
  1735. mScriptEd->mErrorList->setCommentText(LLTrans::getString("CompileSuccessfulSaving"));
  1736. if(gAssetStorage)
  1737. {
  1738. llinfos << "LLLiveLSLEditor::saveAsset "
  1739. << mItem->getAssetUUID() << llendl;
  1740. getWindow()->incBusyCount();
  1741. mPendingUploads++;
  1742. LLLiveLSLSaveData* data = NULL;
  1743. data = new LLLiveLSLSaveData(mObjectUUID,
  1744.  mItem,
  1745.  is_running);
  1746. gAssetStorage->storeAssetData(dst_filename,
  1747.   tid,
  1748.   LLAssetType::AT_LSL_BYTECODE,
  1749.   &LLLiveLSLEditor::onSaveBytecodeComplete,
  1750.   (void*)data);
  1751. dialog_refresh_all();
  1752. }
  1753. }
  1754. // get rid of any temp files left lying around
  1755. LLFile::remove(filename);
  1756. LLFile::remove(err_filename);
  1757. LLFile::remove(dst_filename);
  1758. // If we successfully saved it, then we should be able to check/uncheck the running box!
  1759. LLCheckBoxCtrl* runningCheckbox = getChild<LLCheckBoxCtrl>( "running");
  1760. runningCheckbox->setLabel(getString("script_running"));
  1761. runningCheckbox->setEnabled(TRUE);
  1762. }
  1763. void LLLiveLSLEditor::onSaveTextComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed)
  1764. {
  1765. LLLiveLSLSaveData* data = (LLLiveLSLSaveData*)user_data;
  1766. if (status)
  1767. {
  1768. llwarns << "Unable to save text for a script." << llendl;
  1769. LLSD args;
  1770. args["REASON"] = std::string(LLAssetStorage::getErrorString(status));
  1771. LLNotificationsUtil::add("CompileQueueSaveText", args);
  1772. }
  1773. else
  1774. {
  1775. LLLiveLSLEditor* self = LLFloaterReg::findTypedInstance<LLLiveLSLEditor>("preview_scriptedit", data->mItem->getUUID()); //  ^ data->mSaveObjectID
  1776. if (self)
  1777. {
  1778. self->getWindow()->decBusyCount();
  1779. self->mPendingUploads--;
  1780. if (self->mPendingUploads <= 0
  1781. && self->mCloseAfterSave)
  1782. {
  1783. self->closeFloater();
  1784. }
  1785. }
  1786. }
  1787. delete data;
  1788. data = NULL;
  1789. }
  1790. void LLLiveLSLEditor::onSaveBytecodeComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed)
  1791. {
  1792. LLLiveLSLSaveData* data = (LLLiveLSLSaveData*)user_data;
  1793. if(!data)
  1794. return;
  1795. if(0 ==status)
  1796. {
  1797. llinfos << "LSL Bytecode saved" << llendl;
  1798. LLLiveLSLEditor* self = LLFloaterReg::findTypedInstance<LLLiveLSLEditor>("preview_scriptedit", data->mItem->getUUID()); //  ^ data->mSaveObjectID
  1799. if (self)
  1800. {
  1801. // Tell the user that the compile worked.
  1802. self->mScriptEd->mErrorList->setCommentText(LLTrans::getString("SaveComplete"));
  1803. // close the window if this completes both uploads
  1804. self->getWindow()->decBusyCount();
  1805. self->mPendingUploads--;
  1806. if (self->mPendingUploads <= 0
  1807. && self->mCloseAfterSave)
  1808. {
  1809. self->closeFloater();
  1810. }
  1811. }
  1812. LLViewerObject* object = gObjectList.findObject(data->mSaveObjectID);
  1813. if(object)
  1814. {
  1815. object->saveScript(data->mItem, data->mActive, false);
  1816. dialog_refresh_all();
  1817. //LLToolDragAndDrop::dropScript(object, ids->first,
  1818. //   LLAssetType::AT_LSL_TEXT, FALSE);
  1819. }
  1820. }
  1821. else
  1822. {
  1823. llinfos << "Problem saving LSL Bytecode (Live Editor)" << llendl;
  1824. llwarns << "Unable to save a compiled script." << llendl;
  1825. LLSD args;
  1826. args["REASON"] = std::string(LLAssetStorage::getErrorString(status));
  1827. LLNotificationsUtil::add("CompileQueueSaveBytecode", args);
  1828. }
  1829. std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_uuid.asString());
  1830. std::string dst_filename = llformat("%s.lso", filepath.c_str());
  1831. LLFile::remove(dst_filename);
  1832. delete data;
  1833. }
  1834. BOOL LLLiveLSLEditor::canClose()
  1835. {
  1836. return (mScriptEd->canClose());
  1837. }
  1838. void LLLiveLSLEditor::closeIfNeeded()
  1839. {
  1840. getWindow()->decBusyCount();
  1841. mPendingUploads--;
  1842. if (mPendingUploads <= 0 && mCloseAfterSave)
  1843. {
  1844. closeFloater();
  1845. }
  1846. }
  1847. // static
  1848. void LLLiveLSLEditor::onLoad(void* userdata)
  1849. {
  1850. LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata;
  1851. self->loadAsset();
  1852. }
  1853. // static
  1854. void LLLiveLSLEditor::onSave(void* userdata, BOOL close_after_save)
  1855. {
  1856. LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata;
  1857. self->mCloseAfterSave = close_after_save;
  1858. self->saveIfNeeded();
  1859. }
  1860. // static
  1861. void LLLiveLSLEditor::processScriptRunningReply(LLMessageSystem* msg, void**)
  1862. {
  1863. LLUUID item_id;
  1864. LLUUID object_id;
  1865. msg->getUUIDFast(_PREHASH_Script, _PREHASH_ObjectID, object_id);
  1866. msg->getUUIDFast(_PREHASH_Script, _PREHASH_ItemID, item_id);
  1867. LLLiveLSLEditor* instance = LLFloaterReg::findTypedInstance<LLLiveLSLEditor>("preview_scriptedit", item_id); //  ^ object_id
  1868. if(instance)
  1869. {
  1870. instance->mHaveRunningInfo = TRUE;
  1871. BOOL running;
  1872. msg->getBOOLFast(_PREHASH_Script, _PREHASH_Running, running);
  1873. LLCheckBoxCtrl* runningCheckbox = instance->getChild<LLCheckBoxCtrl>("running");
  1874. runningCheckbox->set(running);
  1875. BOOL mono;
  1876. msg->getBOOLFast(_PREHASH_Script, "Mono", mono);
  1877. LLCheckBoxCtrl* monoCheckbox = instance->getChild<LLCheckBoxCtrl>("mono");
  1878. monoCheckbox->setEnabled(instance->getIsModifiable() && have_script_upload_cap(object_id));
  1879. monoCheckbox->set(mono);
  1880. }
  1881. }
  1882. void LLLiveLSLEditor::onMonoCheckboxClicked(LLUICtrl*, void* userdata)
  1883. {
  1884. LLLiveLSLEditor* self = static_cast<LLLiveLSLEditor*>(userdata);
  1885. self->mMonoCheckbox->setEnabled(have_script_upload_cap(self->mObjectUUID));
  1886. self->mScriptEd->enableSave(self->getIsModifiable());
  1887. }
  1888. BOOL LLLiveLSLEditor::monoChecked() const
  1889. {
  1890. if(NULL != mMonoCheckbox)
  1891. {
  1892. return mMonoCheckbox->getValue()? TRUE : FALSE;
  1893. }
  1894. return FALSE;
  1895. }