llpreviewscript.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "llpreviewscript.h"
00035 
00036 #include "llassetstorage.h"
00037 #include "llassetuploadresponders.h"
00038 #include "llbutton.h"
00039 #include "llcheckboxctrl.h"
00040 #include "llcombobox.h"
00041 #include "lldir.h"
00042 #include "llinventorymodel.h"
00043 #include "llkeyboard.h"
00044 #include "lllineeditor.h"
00045 
00046 #include "llresmgr.h"
00047 #include "llscrollbar.h"
00048 #include "llscrollcontainer.h"
00049 #include "llscrolllistctrl.h"
00050 #include "llslider.h"
00051 #include "lscript_rt_interface.h"
00052 #include "lscript_export.h"
00053 #include "lltextbox.h"
00054 #include "lltooldraganddrop.h"
00055 #include "llvfile.h"
00056 
00057 #include "llagent.h"
00058 #include "llnotify.h"
00059 #include "llmenugl.h"
00060 #include "roles_constants.h"
00061 #include "llselectmgr.h"
00062 #include "llviewerinventory.h"
00063 #include "llviewermenu.h"
00064 #include "llviewerobject.h"
00065 #include "llviewerobjectlist.h"
00066 #include "llviewerregion.h"
00067 #include "llkeyboard.h"
00068 #include "llscrollcontainer.h"
00069 #include "llcheckboxctrl.h"
00070 #include "llselectmgr.h"
00071 #include "lltooldraganddrop.h"
00072 #include "llscrolllistctrl.h"
00073 #include "lltextbox.h"
00074 #include "llslider.h"
00075 #include "lldir.h"
00076 #include "llcombobox.h"
00077 //#include "llfloaterchat.h"
00078 #include "llviewerstats.h"
00079 #include "llviewertexteditor.h"
00080 #include "llviewerwindow.h"
00081 #include "lluictrlfactory.h"
00082 #include "llwebbrowserctrl.h"
00083 #include "lluictrlfactory.h"
00084 
00085 #include "llviewercontrol.h"
00086 #include "llappviewer.h"
00087 
00088 #include "llpanelinventory.h"
00089 
00090 
00091 const char HELLO_LSL[] =
00092         "default\n"
00093         "{\n"
00094         "    state_entry()\n"
00095     "    {\n"
00096     "        llSay(0, \"Hello, Avatar!\");\n"
00097     "    }\n"
00098         "\n"
00099         "    touch_start(integer total_number)\n"
00100         "    {\n"
00101         "        llSay(0, \"Touched.\");\n"
00102         "    }\n"
00103         "}\n";
00104 const char HELP_LSL[] = "lsl_guide.html";
00105 
00106 const char DEFAULT_SCRIPT_NAME[] = "New Script"; // *TODO:Translate?
00107 const char DEFAULT_SCRIPT_DESC[] = "(No Description)"; // *TODO:Translate?
00108 
00109 // Description and header information
00110 
00111 const S32 SCRIPT_BORDER = 4;
00112 const S32 SCRIPT_PAD = 5;
00113 const S32 SCRIPT_BUTTON_WIDTH = 128;
00114 const S32 SCRIPT_BUTTON_HEIGHT = 24;    // HACK: Use BTN_HEIGHT where possible.
00115 const S32 LINE_COLUMN_HEIGHT = 14;
00116 const S32 BTN_PAD = 8;
00117 
00118 const S32 SCRIPT_EDITOR_MIN_HEIGHT = 2 * SCROLLBAR_SIZE + 2 * LLPANEL_BORDER_WIDTH + 128;
00119 
00120 const S32 SCRIPT_MIN_WIDTH = 
00121         2 * SCRIPT_BORDER + 
00122         2 * SCRIPT_BUTTON_WIDTH + 
00123         SCRIPT_PAD + RESIZE_HANDLE_WIDTH +
00124         SCRIPT_PAD;
00125 
00126 const S32 SCRIPT_MIN_HEIGHT = 
00127         2 * SCRIPT_BORDER +
00128         3*(SCRIPT_BUTTON_HEIGHT + SCRIPT_PAD) +
00129         LINE_COLUMN_HEIGHT +
00130         SCRIPT_EDITOR_MIN_HEIGHT;
00131 
00132 const S32 MAX_EXPORT_SIZE = 1000;
00133 
00134 const S32 SCRIPT_SEARCH_WIDTH = 300;
00135 const S32 SCRIPT_SEARCH_HEIGHT = 120;
00136 const S32 SCRIPT_SEARCH_LABEL_WIDTH = 50;
00137 const S32 SCRIPT_SEARCH_BUTTON_WIDTH = 80;
00138 const S32 TEXT_EDIT_COLUMN_HEIGHT = 16;
00139 const S32 MAX_HISTORY_COUNT = 10;
00140 const F32 LIVE_HELP_REFRESH_TIME = 1.f;
00141 
00145 class LLFloaterScriptSearch : public LLFloater
00146 {
00147 public:
00148         LLFloaterScriptSearch(std::string title, LLRect rect, LLScriptEdCore* editor_core);
00149         ~LLFloaterScriptSearch();
00150 
00151         static void show(LLScriptEdCore* editor_core);
00152         static void onBtnSearch(void* userdata);
00153         void handleBtnSearch();
00154 
00155         static void onBtnReplace(void* userdata);
00156         void handleBtnReplace();
00157 
00158         static void onBtnReplaceAll(void* userdata);
00159         void handleBtnReplaceAll();
00160 
00161         LLScriptEdCore* getEditorCore() { return mEditorCore; }
00162         static LLFloaterScriptSearch* getInstance() { return sInstance; }
00163 
00164         void open();            /*Flawfinder: ignore*/
00165 
00166 private:
00167 
00168         LLScriptEdCore* mEditorCore;
00169 
00170         static LLFloaterScriptSearch*   sInstance;
00171 };
00172 
00173 LLFloaterScriptSearch* LLFloaterScriptSearch::sInstance = NULL;
00174 
00175 LLFloaterScriptSearch::LLFloaterScriptSearch(std::string title, LLRect rect, LLScriptEdCore* editor_core)
00176                 : LLFloater("script search",rect,title), mEditorCore(editor_core)
00177 {
00178         
00179         LLUICtrlFactory::getInstance()->buildFloater(this,"floater_script_search.xml");
00180 
00181         childSetAction("search_btn", onBtnSearch,this);
00182         childSetAction("replace_btn", onBtnReplace,this);
00183         childSetAction("replace_all_btn", onBtnReplaceAll,this);
00184         
00185         setDefaultBtn("search_btn");
00186 
00187         if (!getHost())
00188         {
00189                 LLRect curRect = getRect();
00190                 translate(rect.mLeft - curRect.mLeft, rect.mTop - curRect.mTop);
00191         }
00192         
00193         sInstance = this;
00194 
00195         childSetFocus("search_text", TRUE);
00196 
00197         // find floater in which script panel is embedded
00198         LLView* viewp = (LLView*)editor_core;
00199         while(viewp)
00200         {
00201                 LLFloater* floaterp = dynamic_cast<LLFloater*>(viewp);
00202                 if (floaterp)
00203                 {
00204                         floaterp->addDependentFloater(this);
00205                         break;
00206                 }
00207                 viewp = viewp->getParent();
00208         }
00209 }
00210 
00211 //static 
00212 void LLFloaterScriptSearch::show(LLScriptEdCore* editor_core)
00213 {
00214         if (sInstance && sInstance->mEditorCore && sInstance->mEditorCore != editor_core)
00215         {
00216                 sInstance->close();
00217                 delete sInstance;
00218         }
00219 
00220         if (!sInstance)
00221         {
00222                 S32 left = 0;
00223                 S32 top = 0;
00224                 gFloaterView->getNewFloaterPosition(&left,&top);
00225 
00226                 // sInstance will be assigned in the constructor.
00227                 new LLFloaterScriptSearch("Script Search",LLRect(left,top,left + SCRIPT_SEARCH_WIDTH,top - SCRIPT_SEARCH_HEIGHT),editor_core);
00228         }
00229 
00230         sInstance->open();              /*Flawfinder: ignore*/
00231 }
00232 
00233 LLFloaterScriptSearch::~LLFloaterScriptSearch()
00234 {
00235         sInstance = NULL;
00236 }
00237 
00238 // static 
00239 void LLFloaterScriptSearch::onBtnSearch(void *userdata)
00240 {
00241         LLFloaterScriptSearch* self = (LLFloaterScriptSearch*)userdata;
00242         self->handleBtnSearch();
00243 }
00244 
00245 void LLFloaterScriptSearch::handleBtnSearch()
00246 {
00247         LLCheckBoxCtrl* caseChk = getChild<LLCheckBoxCtrl>("case_text");
00248         mEditorCore->mEditor->selectNext(childGetText("search_text"), caseChk->get());
00249 }
00250 
00251 // static 
00252 void LLFloaterScriptSearch::onBtnReplace(void *userdata)
00253 {
00254         LLFloaterScriptSearch* self = (LLFloaterScriptSearch*)userdata;
00255         self->handleBtnReplace();
00256 }
00257 
00258 void LLFloaterScriptSearch::handleBtnReplace()
00259 {
00260         LLCheckBoxCtrl* caseChk = getChild<LLCheckBoxCtrl>("case_text");
00261         mEditorCore->mEditor->replaceText(childGetText("search_text"), childGetText("replace_text"), caseChk->get());
00262 }
00263 
00264 // static 
00265 void LLFloaterScriptSearch::onBtnReplaceAll(void *userdata)
00266 {
00267         LLFloaterScriptSearch* self = (LLFloaterScriptSearch*)userdata;
00268         self->handleBtnReplaceAll();
00269 }
00270 
00271 void LLFloaterScriptSearch::handleBtnReplaceAll()
00272 {
00273         LLCheckBoxCtrl* caseChk = getChild<LLCheckBoxCtrl>("case_text");
00274         mEditorCore->mEditor->replaceTextAll(childGetText("search_text"), childGetText("replace_text"), caseChk->get());
00275 }
00276 
00277 void LLFloaterScriptSearch::open()              /*Flawfinder: ignore*/
00278 {
00279         LLFloater::open();              /*Flawfinder: ignore*/
00280         childSetFocus("search_text", TRUE); 
00281 }
00282 
00286 
00287 LLScriptEdCore::LLScriptEdCore(
00288         const std::string& name,
00289         const LLRect& rect,
00290         const std::string& sample,
00291         const std::string& help,
00292         const LLHandle<LLFloater>& floater_handle,
00293         void (*load_callback)(void*),
00294         void (*save_callback)(void*, BOOL),
00295         void (*search_replace_callback) (void* userdata),
00296         void* userdata,
00297         S32 bottom_pad)
00298         :
00299         LLPanel( "name", rect ),
00300         mSampleText(sample),
00301         mHelpFile ( help ),
00302         mEditor( NULL ),
00303         mLoadCallback( load_callback ),
00304         mSaveCallback( save_callback ),
00305         mSearchReplaceCallback( search_replace_callback ),
00306         mUserdata( userdata ),
00307         mForceClose( FALSE ),
00308         mLastHelpToken(NULL),
00309         mLiveHelpHistorySize(0)
00310 {
00311         setFollowsAll();
00312         setBorderVisible(FALSE);
00313 
00314         
00315         LLUICtrlFactory::getInstance()->buildPanel(this, "floater_script_ed_panel.xml");
00316         
00317         mErrorList = getChild<LLScrollListCtrl>("lsl errors");
00318 
00319         mFunctions = getChild<LLComboBox>( "Insert...");
00320         
00321         childSetCommitCallback("Insert...", &LLScriptEdCore::onBtnInsertFunction, this);
00322 
00323         mEditor = getChild<LLViewerTextEditor>("Script Editor");
00324         mEditor->setFollowsAll();
00325         mEditor->setHandleEditKeysDirectly(TRUE);
00326         mEditor->setEnabled(TRUE);
00327         mEditor->setWordWrap(TRUE);
00328 
00329         LLDynamicArray<const char*> funcs;
00330         LLDynamicArray<const char*> tooltips;
00331         for (S32 i = 0; i < gScriptLibrary.mNextNumber; i++)
00332         {
00333                 // Make sure this isn't a god only function, or the agent is a god.
00334                 if (!gScriptLibrary.mFunctions[i]->mGodOnly || gAgent.isGodlike())
00335                 {
00336                         funcs.put(gScriptLibrary.mFunctions[i]->mName);
00337                         tooltips.put(gScriptLibrary.mFunctions[i]->mDesc);
00338                 }
00339         }
00340         LLColor3 color(0.5f, 0.0f, 0.15f);
00341                 
00342         mEditor->loadKeywords(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"keywords.ini"), funcs, tooltips, color);
00343 
00344         
00345         LLKeywordToken *token;
00346         LLKeywords::keyword_iterator_t token_it;
00347         for (token_it = mEditor->keywordsBegin(); token_it != mEditor->keywordsEnd(); ++token_it)
00348         {
00349                 token = token_it->second;
00350                 if (token->getColor() == color)
00351                         mFunctions->add(wstring_to_utf8str(token->getToken()));
00352         }
00353 
00354         for (token_it = mEditor->keywordsBegin(); token_it != mEditor->keywordsEnd(); ++token_it)
00355         {
00356                 token = token_it->second;
00357                 if (token->getColor() != color)
00358                         mFunctions->add(wstring_to_utf8str(token->getToken()));
00359         }
00360 
00361 
00362         childSetCommitCallback("lsl errors", &LLScriptEdCore::onErrorList, this);
00363         childSetAction("Save_btn", onBtnSave,this);
00364 
00365         initMenu();
00366                 
00367         // Do the work that addTabPanel() normally does.
00368         //LLRect tab_panel_rect( 0, getRect().getHeight(), getRect().getWidth(), 0 );
00369         //tab_panel_rect.stretch( -LLPANEL_BORDER_WIDTH );
00370         //mCodePanel->setFollowsAll();
00371         //mCodePanel->translate( tab_panel_rect.mLeft - mCodePanel->getRect().mLeft, tab_panel_rect.mBottom - mCodePanel->getRect().mBottom);
00372         //mCodePanel->reshape( tab_panel_rect.getWidth(), tab_panel_rect.getHeight(), TRUE );
00373         
00374 }
00375 
00376 LLScriptEdCore::~LLScriptEdCore()
00377 {
00378         deleteBridges();
00379 
00380         // If the search window is up for this editor, close it.
00381         LLFloaterScriptSearch* script_search = LLFloaterScriptSearch::getInstance();
00382         if (script_search && script_search->getEditorCore() == this)
00383         {
00384                 script_search->close();
00385                 delete script_search;
00386         }
00387 }
00388 
00389 void LLScriptEdCore::initMenu()
00390 {
00391 
00392         LLMenuItemCallGL* menuItem = getChild<LLMenuItemCallGL>("Save");
00393         menuItem->setMenuCallback(onBtnSave, this);
00394         menuItem->setEnabledCallback(hasChanged);
00395         
00396         menuItem = getChild<LLMenuItemCallGL>("Revert All Changes");
00397         menuItem->setMenuCallback(onBtnUndoChanges, this);
00398         menuItem->setEnabledCallback(hasChanged);
00399 
00400         menuItem = getChild<LLMenuItemCallGL>("Undo");
00401         menuItem->setMenuCallback(onUndoMenu, this);
00402         menuItem->setEnabledCallback(enableUndoMenu);
00403 
00404         menuItem = getChild<LLMenuItemCallGL>("Redo");
00405         menuItem->setMenuCallback(onRedoMenu, this);
00406         menuItem->setEnabledCallback(enableRedoMenu);
00407 
00408         menuItem = getChild<LLMenuItemCallGL>("Cut");
00409         menuItem->setMenuCallback(onCutMenu, this);
00410         menuItem->setEnabledCallback(enableCutMenu);
00411 
00412         menuItem = getChild<LLMenuItemCallGL>("Copy");
00413         menuItem->setMenuCallback(onCopyMenu, this);
00414         menuItem->setEnabledCallback(enableCopyMenu);
00415 
00416         menuItem = getChild<LLMenuItemCallGL>("Paste");
00417         menuItem->setMenuCallback(onPasteMenu, this);
00418         menuItem->setEnabledCallback(enablePasteMenu);
00419 
00420         menuItem = getChild<LLMenuItemCallGL>("Select All");
00421         menuItem->setMenuCallback(onSelectAllMenu, this);
00422         menuItem->setEnabledCallback(enableSelectAllMenu);
00423 
00424         menuItem = getChild<LLMenuItemCallGL>("Search / Replace...");
00425         menuItem->setMenuCallback(onSearchMenu, this);
00426         menuItem->setEnabledCallback(NULL);
00427 
00428         menuItem = getChild<LLMenuItemCallGL>("Help...");
00429         menuItem->setMenuCallback(onBtnHelp, this);
00430         menuItem->setEnabledCallback(NULL);
00431 
00432         menuItem = getChild<LLMenuItemCallGL>("LSL Wiki Help...");
00433         menuItem->setMenuCallback(onBtnDynamicHelp, this);
00434         menuItem->setEnabledCallback(NULL);
00435 }
00436 
00437 BOOL LLScriptEdCore::hasChanged(void* userdata)
00438 {
00439         LLScriptEdCore* self = (LLScriptEdCore*)userdata;
00440         if (!self || !self->mEditor) return FALSE;
00441 
00442         return !self->mEditor->isPristine();
00443 }
00444 
00445 void LLScriptEdCore::draw()
00446 {
00447         BOOL script_changed = !mEditor->isPristine();
00448         childSetEnabled("Save_btn", script_changed);
00449 
00450         if( mEditor->hasFocus() )
00451         {
00452                 S32 line = 0;
00453                 S32 column = 0;
00454                 mEditor->getCurrentLineAndColumn( &line, &column, FALSE );  // don't include wordwrap
00455                 std::string cursor_pos;
00456                 cursor_pos = llformat("Line %d, Column %d", line, column );
00457                 childSetText("line_col", cursor_pos);
00458         }
00459         else
00460         {
00461                 childSetText("line_col", LLString::null);
00462         }
00463 
00464         updateDynamicHelp();
00465 
00466         LLPanel::draw();
00467 }
00468 
00469 void LLScriptEdCore::updateDynamicHelp(BOOL immediate)
00470 {
00471         LLFloater* help_floater = mLiveHelpHandle.get();
00472         if (!help_floater) return;
00473 
00474         // update back and forward buttons
00475         LLButton* fwd_button = help_floater->getChild<LLButton>("fwd_btn");
00476         LLButton* back_button = help_floater->getChild<LLButton>("back_btn");
00477         LLWebBrowserCtrl* browser = help_floater->getChild<LLWebBrowserCtrl>("lsl_guide_html");
00478         back_button->setEnabled(browser->canNavigateBack());
00479         fwd_button->setEnabled(browser->canNavigateForward());
00480 
00481         if (!immediate && !gSavedSettings.getBOOL("ScriptHelpFollowsCursor"))
00482         {
00483                 return;
00484         }
00485 
00486         const LLTextSegment* segment = NULL;
00487         std::vector<const LLTextSegment*> selected_segments;
00488         mEditor->getSelectedSegments(selected_segments);
00489 
00490         // try segments in selection range first
00491         std::vector<const LLTextSegment*>::iterator segment_iter;
00492         for (segment_iter = selected_segments.begin(); segment_iter != selected_segments.end(); ++segment_iter)
00493         {
00494                 if((*segment_iter)->getToken() && (*segment_iter)->getToken()->getType() == LLKeywordToken::WORD)
00495                 {
00496                         segment = *segment_iter;
00497                         break;
00498                 }
00499         }
00500 
00501         // then try previous segment in case we just typed it
00502         if (!segment)
00503         {
00504                 const LLTextSegment* test_segment = mEditor->getPreviousSegment();
00505                 if(test_segment->getToken() && test_segment->getToken()->getType() == LLKeywordToken::WORD)
00506                 {
00507                         segment = test_segment;
00508                 }
00509         }
00510 
00511         if (segment)
00512         {
00513                 if (segment->getToken() != mLastHelpToken)
00514                 {
00515                         mLastHelpToken = segment->getToken();
00516                         mLiveHelpTimer.start();
00517                 }
00518                 if (immediate || (mLiveHelpTimer.getStarted() && mLiveHelpTimer.getElapsedTimeF32() > LIVE_HELP_REFRESH_TIME))
00519                 {
00520                         LLString help_string = mEditor->getText().substr(segment->getStart(), segment->getEnd() - segment->getStart());
00521                         setHelpPage(help_string);
00522                         mLiveHelpTimer.stop();
00523                 }
00524         }
00525         else if (immediate)
00526         {
00527                 setHelpPage("");
00528         }
00529 }
00530 
00531 void LLScriptEdCore::setHelpPage(const LLString& help_string)
00532 {
00533         LLFloater* help_floater = mLiveHelpHandle.get();
00534         if (!help_floater) return;
00535         
00536         LLWebBrowserCtrl* web_browser = help_floater->getChild<LLWebBrowserCtrl>("lsl_guide_html");
00537         if (!web_browser) return;
00538 
00539         LLComboBox* history_combo = help_floater->getChild<LLComboBox>("history_combo");
00540         if (!history_combo) return;
00541 
00542         LLUIString url_string = gSavedSettings.getString("LSLHelpURL");
00543         url_string.setArg("[APP_DIRECTORY]", gDirUtilp->getWorkingDir());
00544         url_string.setArg("[LSL_STRING]", help_string);
00545 
00546         addHelpItemToHistory(help_string);
00547 
00548         web_browser->navigateTo(url_string);
00549 
00550 }
00551 
00552 void LLScriptEdCore::addHelpItemToHistory(const LLString& help_string)
00553 {
00554         if (help_string.empty()) return;
00555 
00556         LLFloater* help_floater = mLiveHelpHandle.get();
00557         if (!help_floater) return;
00558 
00559         LLComboBox* history_combo = help_floater->getChild<LLComboBox>("history_combo");
00560         if (!history_combo) return;
00561 
00562         // separate history items from full item list
00563         if (mLiveHelpHistorySize == 0)
00564         {
00565                 LLSD row;
00566                 row["columns"][0]["type"] = "separator";
00567                 history_combo->addElement(row, ADD_TOP);
00568         }
00569         // delete all history items over history limit
00570         while(mLiveHelpHistorySize > MAX_HISTORY_COUNT - 1)
00571         {
00572                 history_combo->remove(mLiveHelpHistorySize - 1);
00573                 mLiveHelpHistorySize--;
00574         }
00575 
00576         history_combo->setSimple(help_string);
00577         S32 index = history_combo->getCurrentIndex();
00578 
00579         // if help string exists in the combo box
00580         if (index >= 0)
00581         {
00582                 S32 cur_index = history_combo->getCurrentIndex();
00583                 if (cur_index < mLiveHelpHistorySize)
00584                 {
00585                         // item found in history, bubble up to top
00586                         history_combo->remove(history_combo->getCurrentIndex());
00587                         mLiveHelpHistorySize--;
00588                 }
00589         }
00590         history_combo->add(help_string, LLSD(help_string), ADD_TOP);
00591         history_combo->selectFirstItem();
00592         mLiveHelpHistorySize++;
00593 }
00594 
00595 BOOL LLScriptEdCore::canClose()
00596 {
00597         if(mForceClose || mEditor->isPristine())
00598         {
00599                 return TRUE;
00600         }
00601         else
00602         {
00603                 // Bring up view-modal dialog: Save changes? Yes, No, Cancel
00604                 gViewerWindow->alertXml("SaveChanges", LLScriptEdCore::handleSaveChangesDialog, this);
00605                 return FALSE;
00606         }
00607 }
00608 
00609 // static
00610 void LLScriptEdCore::handleSaveChangesDialog( S32 option, void* userdata )
00611 {
00612         LLScriptEdCore* self = (LLScriptEdCore*) userdata;
00613         switch( option )
00614         {
00615         case 0:  // "Yes"
00616                 // close after saving
00617                 LLScriptEdCore::doSave( self, TRUE );
00618                 break;
00619 
00620         case 1:  // "No"
00621                 self->mForceClose = TRUE;
00622                 // This will close immediately because mForceClose is true, so we won't
00623                 // infinite loop with these dialogs. JC
00624                 ((LLFloater*) self->getParent())->close();
00625                 break;
00626 
00627         case 2: // "Cancel"
00628         default:
00629                 // If we were quitting, we didn't really mean it.
00630         LLAppViewer::instance()->abortQuit();
00631                 break;
00632         }
00633 }
00634 
00635 // static 
00636 void LLScriptEdCore::onHelpWebDialog(S32 option, void* userdata)
00637 {
00638         LLScriptEdCore* corep = (LLScriptEdCore*)userdata;
00639 
00640         switch(option)
00641         {
00642         case 0:
00643                 load_url_local_file(corep->mHelpFile.c_str());
00644                 break;
00645         default:
00646                 break;
00647         }
00648 }
00649 
00650 // static 
00651 void LLScriptEdCore::onBtnHelp(void* userdata)
00652 {
00653                 gViewerWindow->alertXml("WebLaunchLSLGuide",
00654                         onHelpWebDialog,
00655                         userdata);
00656 }
00657 
00658 // static 
00659 void LLScriptEdCore::onBtnDynamicHelp(void* userdata)
00660 {
00661         LLScriptEdCore* corep = (LLScriptEdCore*)userdata;
00662 
00663         LLFloater* live_help_floater = corep->mLiveHelpHandle.get();
00664         if (live_help_floater)
00665         {
00666                 live_help_floater->setFocus(TRUE);
00667                 corep->updateDynamicHelp(TRUE);
00668 
00669                 return;
00670         }
00671 
00672         live_help_floater = new LLFloater("lsl_help");
00673         LLUICtrlFactory::getInstance()->buildFloater(live_help_floater, "floater_lsl_guide.xml");
00674         ((LLFloater*)corep->getParent())->addDependentFloater(live_help_floater, TRUE);
00675         live_help_floater->childSetCommitCallback("lock_check", onCheckLock, userdata);
00676         live_help_floater->childSetValue("lock_check", gSavedSettings.getBOOL("ScriptHelpFollowsCursor"));
00677         live_help_floater->childSetCommitCallback("history_combo", onHelpComboCommit, userdata);
00678         live_help_floater->childSetAction("back_btn", onClickBack, userdata);
00679         live_help_floater->childSetAction("fwd_btn", onClickForward, userdata);
00680 
00681         LLWebBrowserCtrl* browser = live_help_floater->getChild<LLWebBrowserCtrl>("lsl_guide_html");
00682         browser->setAlwaysRefresh(TRUE);
00683 
00684         LLComboBox* help_combo = live_help_floater->getChild<LLComboBox>("history_combo");
00685         LLKeywordToken *token;
00686         LLKeywords::keyword_iterator_t token_it;
00687         for (token_it = corep->mEditor->keywordsBegin(); 
00688                 token_it != corep->mEditor->keywordsEnd(); 
00689                 ++token_it)
00690         {
00691                 token = token_it->second;
00692                 help_combo->add(wstring_to_utf8str(token->getToken()));
00693         }
00694         help_combo->sortByName();
00695 
00696         // re-initialize help variables
00697         corep->mLastHelpToken = NULL;
00698         corep->mLiveHelpHandle = live_help_floater->getHandle();
00699         corep->mLiveHelpHistorySize = 0;
00700         corep->updateDynamicHelp(TRUE);
00701 }
00702 
00703 //static 
00704 void LLScriptEdCore::onClickBack(void* userdata)
00705 {
00706         LLScriptEdCore* corep = (LLScriptEdCore*)userdata;
00707         LLFloater* live_help_floater = corep->mLiveHelpHandle.get();
00708         if (live_help_floater)
00709         {
00710                 LLWebBrowserCtrl* browserp = live_help_floater->getChild<LLWebBrowserCtrl>("lsl_guide_html");
00711                 if (browserp)
00712                 {
00713                         browserp->navigateBack();
00714                 }
00715         }
00716 }
00717 
00718 //static 
00719 void LLScriptEdCore::onClickForward(void* userdata)
00720 {
00721         LLScriptEdCore* corep = (LLScriptEdCore*)userdata;
00722         LLFloater* live_help_floater = corep->mLiveHelpHandle.get();
00723         if (live_help_floater)
00724         {
00725                 LLWebBrowserCtrl* browserp = live_help_floater->getChild<LLWebBrowserCtrl>("lsl_guide_html");
00726                 if (browserp)
00727                 {
00728                         browserp->navigateForward();
00729                 }
00730         }
00731 }
00732 
00733 // static
00734 void LLScriptEdCore::onCheckLock(LLUICtrl* ctrl, void* userdata)
00735 {
00736         LLScriptEdCore* corep = (LLScriptEdCore*)userdata;
00737 
00738         // clear out token any time we lock the frame, so we will refresh web page immediately when unlocked
00739         gSavedSettings.setBOOL("ScriptHelpFollowsCursor", ctrl->getValue().asBoolean());
00740 
00741         corep->mLastHelpToken = NULL;
00742 }
00743 
00744 // static 
00745 void LLScriptEdCore::onBtnInsertSample(void* userdata)
00746 {
00747         LLScriptEdCore* self = (LLScriptEdCore*) userdata;
00748 
00749         // Insert sample code
00750         self->mEditor->selectAll();
00751         self->mEditor->cut();
00752         self->mEditor->insertText(self->mSampleText);
00753 }
00754 
00755 // static 
00756 void LLScriptEdCore::onHelpComboCommit(LLUICtrl* ctrl, void* userdata)
00757 {
00758         LLScriptEdCore* corep = (LLScriptEdCore*)userdata;
00759 
00760         LLFloater* live_help_floater = corep->mLiveHelpHandle.get();
00761         if (live_help_floater)
00762         {
00763                 LLString help_string = ctrl->getValue().asString();
00764 
00765                 corep->addHelpItemToHistory(help_string);
00766 
00767                 LLWebBrowserCtrl* web_browser = live_help_floater->getChild<LLWebBrowserCtrl>("lsl_guide_html");
00768                 LLUIString url_string = gSavedSettings.getString("LSLHelpURL");
00769                 url_string.setArg("[APP_DIRECTORY]", gDirUtilp->getWorkingDir());
00770                 url_string.setArg("[LSL_STRING]", help_string);
00771                 web_browser->navigateTo(url_string);
00772         }
00773 }
00774 
00775 // static 
00776 void LLScriptEdCore::onBtnInsertFunction(LLUICtrl *ui, void* userdata)
00777 {
00778         LLScriptEdCore* self = (LLScriptEdCore*) userdata;
00779 
00780         // Insert sample code
00781         if(self->mEditor->getEnabled())
00782         {
00783                 self->mEditor->insertText(self->mFunctions->getSimple());
00784         }
00785         self->mEditor->setFocus(TRUE);
00786         self->setHelpPage(self->mFunctions->getSimple());
00787 }
00788 
00789 // static 
00790 void LLScriptEdCore::doSave( void* userdata, BOOL close_after_save )
00791 {
00792         LLViewerStats::getInstance()->incStat( LLViewerStats::ST_LSL_SAVE_COUNT );
00793 
00794         LLScriptEdCore* self = (LLScriptEdCore*) userdata;
00795 
00796         if( self->mSaveCallback )
00797         {
00798                 self->mSaveCallback( self->mUserdata, close_after_save );
00799         }
00800 }
00801 
00802 // static
00803 void LLScriptEdCore::onBtnSave(void* data)
00804 {
00805         // do the save, but don't close afterwards
00806         doSave(data, FALSE);
00807 }
00808 
00809 // static
00810 void LLScriptEdCore::onBtnUndoChanges( void* userdata )
00811 {
00812         LLScriptEdCore* self = (LLScriptEdCore*) userdata;
00813         if( !self->mEditor->tryToRevertToPristineState() )
00814         {
00815                 gViewerWindow->alertXml("ScriptCannotUndo",
00816                          LLScriptEdCore::handleReloadFromServerDialog, self);
00817         }
00818 }
00819 
00820 void LLScriptEdCore::onSearchMenu(void* userdata)
00821 {
00822         LLScriptEdCore* sec = (LLScriptEdCore*)userdata;
00823         LLFloaterScriptSearch::show(sec);
00824 }
00825 
00826 // static 
00827 void LLScriptEdCore::onUndoMenu(void* userdata)
00828 {
00829         LLScriptEdCore* self = (LLScriptEdCore*)userdata;
00830         if (!self || !self->mEditor) return;
00831         self->mEditor->undo();
00832 }
00833 
00834 // static 
00835 void LLScriptEdCore::onRedoMenu(void* userdata)
00836 {
00837         LLScriptEdCore* self = (LLScriptEdCore*)userdata;
00838         if (!self || !self->mEditor) return;
00839         self->mEditor->redo();
00840 }
00841 
00842 // static 
00843 void LLScriptEdCore::onCutMenu(void* userdata)
00844 {
00845         LLScriptEdCore* self = (LLScriptEdCore*)userdata;
00846         if (!self || !self->mEditor) return;
00847         self->mEditor->cut();
00848 }
00849 
00850 // static 
00851 void LLScriptEdCore::onCopyMenu(void* userdata)
00852 {
00853         LLScriptEdCore* self = (LLScriptEdCore*)userdata;
00854         if (!self || !self->mEditor) return;
00855         self->mEditor->copy();
00856 }
00857 
00858 // static 
00859 void LLScriptEdCore::onPasteMenu(void* userdata)
00860 {
00861         LLScriptEdCore* self = (LLScriptEdCore*)userdata;
00862         if (!self || !self->mEditor) return;
00863         self->mEditor->paste();
00864 }
00865 
00866 // static 
00867 void LLScriptEdCore::onSelectAllMenu(void* userdata)
00868 {
00869         LLScriptEdCore* self = (LLScriptEdCore*)userdata;
00870         if (!self || !self->mEditor) return;
00871         self->mEditor->selectAll();
00872 }
00873 
00874 // static 
00875 void LLScriptEdCore::onDeselectMenu(void* userdata)
00876 {
00877         LLScriptEdCore* self = (LLScriptEdCore*)userdata;
00878         if (!self || !self->mEditor) return;
00879         self->mEditor->deselect();
00880 }
00881 
00882 // static 
00883 BOOL LLScriptEdCore::enableUndoMenu(void* userdata)
00884 {
00885         LLScriptEdCore* self = (LLScriptEdCore*)userdata;
00886         if (!self || !self->mEditor) return FALSE;
00887         return self->mEditor->canUndo();
00888 }
00889 
00890 // static 
00891 BOOL LLScriptEdCore::enableRedoMenu(void* userdata)
00892 {
00893         LLScriptEdCore* self = (LLScriptEdCore*)userdata;
00894         if (!self || !self->mEditor) return FALSE;
00895         return self->mEditor->canRedo();
00896 }
00897 
00898 // static 
00899 BOOL LLScriptEdCore::enableCutMenu(void* userdata)
00900 {
00901         LLScriptEdCore* self = (LLScriptEdCore*)userdata;
00902         if (!self || !self->mEditor) return FALSE;
00903         return self->mEditor->canCut();
00904 }
00905 
00906 // static 
00907 BOOL LLScriptEdCore::enableCopyMenu(void* userdata)
00908 {
00909         LLScriptEdCore* self = (LLScriptEdCore*)userdata;
00910         if (!self || !self->mEditor) return FALSE;
00911         return self->mEditor->canCopy();
00912 }
00913 
00914 // static 
00915 BOOL LLScriptEdCore::enablePasteMenu(void* userdata)
00916 {
00917         LLScriptEdCore* self = (LLScriptEdCore*)userdata;
00918         if (!self || !self->mEditor) return FALSE;
00919         return self->mEditor->canPaste();
00920 }
00921 
00922 // static 
00923 BOOL LLScriptEdCore::enableSelectAllMenu(void* userdata)
00924 {
00925         LLScriptEdCore* self = (LLScriptEdCore*)userdata;
00926         if (!self || !self->mEditor) return FALSE;
00927         return self->mEditor->canSelectAll();
00928 }
00929 
00930 // static 
00931 BOOL LLScriptEdCore::enableDeselectMenu(void* userdata)
00932 {
00933         LLScriptEdCore* self = (LLScriptEdCore*)userdata;
00934         if (!self || !self->mEditor) return FALSE;
00935         return self->mEditor->canDeselect();
00936 }
00937 
00938 // static
00939 void LLScriptEdCore::onErrorList(LLUICtrl*, void* user_data)
00940 {
00941         LLScriptEdCore* self = (LLScriptEdCore*)user_data;
00942         LLScrollListItem* item = self->mErrorList->getFirstSelected();
00943         if(item)
00944         {
00945                 // *FIX: This fucked up little hack is here because we don't
00946                 // have a grep library. This is very brittle code.
00947                 S32 row = 0;
00948                 S32 column = 0;
00949                 const LLScrollListCell* cell = item->getColumn(0);
00950                 LLString line(cell->getValue().asString());
00951                 line.erase(0, 1);
00952                 LLString::replaceChar(line, ',',' ');
00953                 LLString::replaceChar(line, ')',' ');
00954                 sscanf(line.c_str(), "%d %d", &row, &column);
00955                 //llinfos << "LLScriptEdCore::onErrorList() - " << row << ", "
00956                 //<< column << llendl;
00957                 self->mEditor->setCursor(row, column);
00958                 self->mEditor->setFocus(TRUE);
00959         }
00960 }
00961 
00962 // static
00963 void LLScriptEdCore::handleReloadFromServerDialog( S32 option, void* userdata )
00964 {
00965         LLScriptEdCore* self = (LLScriptEdCore*) userdata;
00966         switch( option )
00967         {
00968         case 0: // "Yes"
00969                 if( self->mLoadCallback )
00970                 {
00971                         self->mEditor->setText( self->getString("loading") );
00972                         self->mLoadCallback( self->mUserdata );
00973                 }
00974                 break;
00975 
00976         case 1: // "No"
00977                 break;
00978 
00979         default:
00980                 llassert(0);
00981                 break;
00982         }
00983 }
00984 
00985 void LLScriptEdCore::selectFirstError()
00986 {
00987         // Select the first item;
00988         mErrorList->selectFirstItem();
00989         onErrorList(mErrorList, this);
00990 }
00991 
00992 
00993 struct LLEntryAndEdCore
00994 {
00995         LLScriptEdCore* mCore;
00996         LLEntryAndEdCore(LLScriptEdCore* core) :
00997                 mCore(core)
00998                 {}
00999 };
01000 
01001 void LLScriptEdCore::deleteBridges()
01002 {
01003         S32 count = mBridges.count();
01004         LLEntryAndEdCore* eandc;
01005         for(S32 i = 0; i < count; i++)
01006         {
01007                 eandc = mBridges.get(i);
01008                 delete eandc;
01009                 mBridges[i] = NULL;
01010         }
01011         mBridges.reset();
01012 }
01013 
01014 // virtual
01015 BOOL LLScriptEdCore::handleKeyHere(KEY key, MASK mask)
01016 {
01017         bool just_control = MASK_CONTROL == (mask & MASK_MODIFIERS);
01018 
01019         if(('S' == key) && just_control)
01020         {
01021                 if(mSaveCallback)
01022                 {
01023                         // don't close after saving
01024                         mSaveCallback(mUserdata, FALSE);
01025                 }
01026 
01027                 return TRUE;
01028         }
01029 
01030         if(('F' == key) && just_control)
01031         {
01032                 if(mSearchReplaceCallback)
01033                 {
01034                         mSearchReplaceCallback(mUserdata);
01035                 }
01036 
01037                 return TRUE;
01038         }
01039 
01040         return FALSE;
01041 }
01042 
01046 
01047 struct LLScriptSaveInfo
01048 {
01049         LLUUID mItemUUID;
01050         LLString mDescription;
01051         LLTransactionID mTransactionID;
01052 
01053         LLScriptSaveInfo(const LLUUID& uuid, const LLString& desc, LLTransactionID tid) :
01054                 mItemUUID(uuid), mDescription(desc),  mTransactionID(tid) {}
01055 };
01056 
01057 
01058 
01059 //static
01060 void* LLPreviewLSL::createScriptEdPanel(void* userdata)
01061 {
01062         
01063         LLPreviewLSL *self = (LLPreviewLSL*)userdata;
01064 
01065         self->mScriptEd =  new LLScriptEdCore("script panel",
01066                                                                    LLRect(),
01067                                                                    HELLO_LSL,
01068                                                                    HELP_LSL,
01069                                                                    self->getHandle(),
01070                                                                    LLPreviewLSL::onLoad,
01071                                                                    LLPreviewLSL::onSave,
01072                                                                    LLPreviewLSL::onSearchReplace,
01073                                                                    self,
01074                                                                    0);
01075 
01076         return self->mScriptEd;
01077 }
01078 
01079 
01080 LLPreviewLSL::LLPreviewLSL(const std::string& name, const LLRect& rect,
01081                                                    const std::string& title, const LLUUID& item_id )
01082 :       LLPreview( name, rect, title, item_id, LLUUID::null, TRUE,
01083                            SCRIPT_MIN_WIDTH, SCRIPT_MIN_HEIGHT ),
01084    mPendingUploads(0)
01085 {
01086 
01087         LLRect curRect = rect;
01088 
01089 
01090         LLCallbackMap::map_t factory_map;
01091         factory_map["script panel"] = LLCallbackMap(LLPreviewLSL::createScriptEdPanel, this);
01092 
01093 
01094         LLUICtrlFactory::getInstance()->buildFloater(this,"floater_script_preview.xml", &factory_map);
01095 
01096         const LLInventoryItem* item = getItem();        
01097 
01098         childSetCommitCallback("desc", LLPreview::onText, this);
01099         childSetText("desc", item->getDescription());
01100         childSetPrevalidate("desc", &LLLineEditor::prevalidatePrintableNotPipe);
01101 
01102         if (!getFloaterHost() && !getHost() && getAssetStatus() == PREVIEW_ASSET_UNLOADED)
01103         {
01104                 loadAsset();
01105         }
01106         
01107         setTitle(title);
01108         
01109         if (!getHost())
01110         {
01111                 reshape(curRect.getWidth(), curRect.getHeight(), TRUE);
01112                 setRect(curRect);
01113         }
01114 }
01115 
01116 // virtual
01117 void LLPreviewLSL::callbackLSLCompileSucceeded()
01118 {
01119         llinfos << "LSL Bytecode saved" << llendl;
01120         mScriptEd->mErrorList->addCommentText("Compile successful!");
01121         mScriptEd->mErrorList->addCommentText("Save complete.");
01122         closeIfNeeded();
01123 }
01124 
01125 // virtual
01126 void LLPreviewLSL::callbackLSLCompileFailed(const LLSD& compile_errors)
01127 {
01128         llinfos << "Compile failed!" << llendl;
01129 
01130         for(LLSD::array_const_iterator line = compile_errors.beginArray();
01131                 line < compile_errors.endArray();
01132                 line++)
01133         {
01134                 LLSD row;
01135                 row["columns"][0]["value"] = line->asString();
01136                 row["columns"][0]["font"] = "OCRA";
01137                 mScriptEd->mErrorList->addElement(row);
01138         }
01139         mScriptEd->selectFirstError();
01140         closeIfNeeded();
01141 }
01142 
01143 void LLPreviewLSL::loadAsset()
01144 {
01145         // *HACK: we poke into inventory to see if it's there, and if so,
01146         // then it might be part of the inventory library. If it's in the
01147         // library, then you can see the script, but not modify it.
01148         const LLInventoryItem* item = gInventory.getItem(mItemUUID);
01149         BOOL is_library = item
01150                 && !gInventory.isObjectDescendentOf(mItemUUID,
01151                                                                                         gAgent.getInventoryRootID());
01152         if(!item)
01153         {
01154                 // do the more generic search.
01155                 getItem();
01156         }
01157         if(item)
01158         {
01159                 BOOL is_copyable = gAgent.allowOperation(PERM_COPY, 
01160                                                                 item->getPermissions(), GP_OBJECT_MANIPULATE);
01161                 BOOL is_modifiable = gAgent.allowOperation(PERM_MODIFY,
01162                                                                 item->getPermissions(), GP_OBJECT_MANIPULATE);
01163                 if (gAgent.isGodlike() || (is_copyable && (is_modifiable || is_library)))
01164                 {
01165                         LLUUID* new_uuid = new LLUUID(mItemUUID);
01166                         gAssetStorage->getInvItemAsset(LLHost::invalid,
01167                                                                                 gAgent.getID(),
01168                                                                                 gAgent.getSessionID(),
01169                                                                                 item->getPermissions().getOwner(),
01170                                                                                 LLUUID::null,
01171                                                                                 item->getUUID(),
01172                                                                                 item->getAssetUUID(),
01173                                                                                 item->getType(),
01174                                                                                 &LLPreviewLSL::onLoadComplete,
01175                                                                                 (void*)new_uuid,
01176                                                                                 TRUE);
01177                         mAssetStatus = PREVIEW_ASSET_LOADING;
01178                 }
01179                 else
01180                 {
01181                         mScriptEd->mEditor->setText(mScriptEd->getString("can_not_view"));
01182                         mScriptEd->mEditor->makePristine();
01183                         mScriptEd->mEditor->setEnabled(FALSE);
01184                         mScriptEd->mFunctions->setEnabled(FALSE);
01185                         mAssetStatus = PREVIEW_ASSET_LOADED;
01186                 }
01187                 childSetVisible("lock", !is_modifiable);
01188                 mScriptEd->childSetEnabled("Insert...", is_modifiable);
01189         }
01190         else
01191         {
01192                 mScriptEd->mEditor->setText(LLString(HELLO_LSL));
01193                 mAssetStatus = PREVIEW_ASSET_LOADED;
01194         }
01195 }
01196 
01197 
01198 BOOL LLPreviewLSL::canClose()
01199 {
01200         return mScriptEd->canClose();
01201 }
01202 
01203 void LLPreviewLSL::closeIfNeeded()
01204 {
01205         // Find our window and close it if requested.
01206         getWindow()->decBusyCount();
01207         mPendingUploads--;
01208         if (mPendingUploads <= 0 && mCloseAfterSave)
01209         {
01210                 close();
01211         }
01212 }
01213 
01214 //override the llpreview open which attempts to load asset, load after xml ui made
01215 void LLPreviewLSL::open()               /*Flawfinder: ignore*/
01216 {
01217         LLFloater::open();              /*Flawfinder: ignore*/
01218 }
01219 
01220 void LLPreviewLSL::onSearchReplace(void* userdata)
01221 {
01222         LLPreviewLSL* self = (LLPreviewLSL*)userdata;
01223         LLScriptEdCore* sec = self->mScriptEd; 
01224         LLFloaterScriptSearch::show(sec);
01225 }
01226 
01227 // static
01228 void LLPreviewLSL::onLoad(void* userdata)
01229 {
01230         LLPreviewLSL* self = (LLPreviewLSL*)userdata;
01231         self->loadAsset();
01232 }
01233 
01234 // static
01235 void LLPreviewLSL::onSave(void* userdata, BOOL close_after_save)
01236 {
01237         LLPreviewLSL* self = (LLPreviewLSL*)userdata;
01238         self->mCloseAfterSave = close_after_save;
01239         self->saveIfNeeded();
01240 }
01241 
01242 // Save needs to compile the text in the buffer. If the compile
01243 // succeeds, then save both assets out to the database. If the compile
01244 // fails, go ahead and save the text anyway so that the user doesn't
01245 // get too fucked.
01246 void LLPreviewLSL::saveIfNeeded()
01247 {
01248         // llinfos << "LLPreviewLSL::saveIfNeeded()" << llendl;
01249         if(mScriptEd->mEditor->isPristine())
01250         {
01251                 return;
01252         }
01253 
01254         mPendingUploads = 0;
01255         mScriptEd->mErrorList->deleteAllItems();
01256         mScriptEd->mEditor->makePristine();
01257 
01258         // save off asset into file
01259         LLTransactionID tid;
01260         tid.generate();
01261         LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
01262         std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id.asString());
01263         std::string filename = llformat("%s.lsl", filepath.c_str());
01264 
01265         LLFILE* fp = LLFile::fopen(filename.c_str(), "wb");
01266         if(!fp)
01267         {
01268                 llwarns << "Unable to write to " << filename << llendl;
01269 
01270                 LLSD row;
01271                 row["columns"][0]["value"] = "Error writing to local file. Is your hard drive full?";
01272                 row["columns"][0]["font"] = "SANSSERIF_SMALL";
01273                 mScriptEd->mErrorList->addElement(row);
01274                 return;
01275         }
01276 
01277         LLString utf8text = mScriptEd->mEditor->getText();
01278         fputs(utf8text.c_str(), fp);
01279         fclose(fp);
01280         fp = NULL;
01281 
01282         const LLInventoryItem *inv_item = getItem();
01283         // save it out to asset server
01284         std::string url = gAgent.getRegion()->getCapability("UpdateScriptAgentInventory");
01285         if(inv_item)
01286         {
01287                 getWindow()->incBusyCount();
01288                 mPendingUploads++;
01289                 if (!url.empty())
01290                 {
01291                         uploadAssetViaCaps(url, filename, mItemUUID);
01292                 }
01293                 else if (gAssetStorage)
01294                 {
01295                         uploadAssetLegacy(filename, mItemUUID, tid);
01296                 }
01297         }
01298 }
01299 
01300 void LLPreviewLSL::uploadAssetViaCaps(const std::string& url,
01301                                                                           const std::string& filename,
01302                                                                           const LLUUID& item_id)
01303 {
01304         llinfos << "Update Agent Inventory via capability" << llendl;
01305         LLSD body;
01306         body["item_id"] = item_id;
01307         LLHTTPClient::post(url, body, new LLUpdateAgentInventoryResponder(body, filename));
01308 }
01309 
01310 void LLPreviewLSL::uploadAssetLegacy(const std::string& filename,
01311                                                                           const LLUUID& item_id,
01312                                                                           const LLTransactionID& tid)
01313 {
01314         LLLineEditor* descEditor = getChild<LLLineEditor>("desc");
01315         LLScriptSaveInfo* info = new LLScriptSaveInfo(item_id,
01316                                                                 descEditor->getText(),
01317                                                                 tid);
01318         gAssetStorage->storeAssetData(filename.c_str(), tid,
01319                                                                   LLAssetType::AT_LSL_TEXT,
01320                                                                   &LLPreviewLSL::onSaveComplete,
01321                                                                   info);
01322 
01323         LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
01324         std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id.asString());
01325         std::string dst_filename = llformat("%s.lso", filepath.c_str());
01326         std::string err_filename = llformat("%s.out", filepath.c_str());
01327 
01328         if(!lscript_compile(filename.c_str(),
01329                                                 dst_filename.c_str(),
01330                                                 err_filename.c_str(),
01331                                                 gAgent.isGodlike()))
01332         {
01333                 llinfos << "Compile failed!" << llendl;
01334                 //char command[256];
01335                 //sprintf(command, "type %s\n", err_filename);
01336                 //system(command);
01337 
01338                 // load the error file into the error scrolllist
01339                 LLFILE* fp = LLFile::fopen(err_filename.c_str(), "r");
01340                 if(fp)
01341                 {
01342                         char buffer[MAX_STRING];                /*Flawfinder: ignore*/
01343                         LLString line;
01344                         while(!feof(fp)) 
01345                         {
01346                                 if (fgets(buffer, MAX_STRING, fp) == NULL)
01347                                 {
01348                                         buffer[0] = '\0';
01349                                 }
01350                                 if(feof(fp))
01351                                 {
01352                                         break;
01353                                 }
01354                                 else
01355                                 {
01356                                         line.assign(buffer);
01357                                         LLString::stripNonprintable(line);
01358 
01359                                         LLSD row;
01360                                         row["columns"][0]["value"] = line;
01361                                         row["columns"][0]["font"] = "OCRA";
01362                                         mScriptEd->mErrorList->addElement(row);
01363                                 }
01364                         }
01365                         fclose(fp);
01366                         mScriptEd->selectFirstError();
01367                 }
01368         }
01369         else
01370         {
01371                 llinfos << "Compile worked!" << llendl;
01372                 if(gAssetStorage)
01373                 {
01374                         getWindow()->incBusyCount();
01375                         mPendingUploads++;
01376                         LLUUID* this_uuid = new LLUUID(mItemUUID);
01377                         gAssetStorage->storeAssetData(dst_filename.c_str(),
01378                                                                                   tid,
01379                                                                                   LLAssetType::AT_LSL_BYTECODE,
01380                                                                                   &LLPreviewLSL::onSaveBytecodeComplete,
01381                                                                                   (void**)this_uuid);
01382                 }
01383         }
01384 
01385         // get rid of any temp files left lying around
01386         LLFile::remove(filename.c_str());
01387         LLFile::remove(err_filename.c_str());
01388         LLFile::remove(dst_filename.c_str());
01389 }
01390 
01391 
01392 // static
01393 void LLPreviewLSL::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed)
01394 {
01395         LLScriptSaveInfo* info = reinterpret_cast<LLScriptSaveInfo*>(user_data);
01396         if(0 == status)
01397         {
01398                 if (info)
01399                 {
01400                         const LLViewerInventoryItem* item;
01401                         item = (const LLViewerInventoryItem*)gInventory.getItem(info->mItemUUID);
01402                         if(item)
01403                         {
01404                                 LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
01405                                 new_item->setAssetUUID(asset_uuid);
01406                                 new_item->setTransactionID(info->mTransactionID);
01407                                 new_item->updateServer(FALSE);
01408                                 gInventory.updateItem(new_item);
01409                                 gInventory.notifyObservers();
01410                         }
01411                         else
01412                         {
01413                                 llwarns << "Inventory item for script " << info->mItemUUID
01414                                         << " is no longer in agent inventory." << llendl
01415                         }
01416 
01417                         // Find our window and close it if requested.
01418                         LLPreviewLSL* self = (LLPreviewLSL*)LLPreview::find(info->mItemUUID);
01419                         if (self)
01420                         {
01421                                 getWindow()->decBusyCount();
01422                                 self->mPendingUploads--;
01423                                 if (self->mPendingUploads <= 0
01424                                         && self->mCloseAfterSave)
01425                                 {
01426                                         self->close();
01427                                 }
01428                         }
01429                 }
01430         }
01431         else
01432         {
01433                 llwarns << "Problem saving script: " << status << llendl;
01434                 LLStringBase<char>::format_map_t args;
01435                 args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status));
01436                 gViewerWindow->alertXml("SaveScriptFailReason", args);
01437         }
01438         delete info;
01439 }
01440 
01441 // static
01442 void LLPreviewLSL::onSaveBytecodeComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed)
01443 {
01444         LLUUID* instance_uuid = (LLUUID*)user_data;
01445         LLPreviewLSL* self = NULL;
01446         if(instance_uuid)
01447         {
01448                 self = LLPreviewLSL::getInstance(*instance_uuid);
01449         }
01450         if (0 == status)
01451         {
01452                 if (self)
01453                 {
01454                         LLSD row;
01455                         row["columns"][0]["value"] = "Compile successful!";
01456                         row["columns"][0]["font"] = "SANSSERIF_SMALL";
01457                         self->mScriptEd->mErrorList->addElement(row);
01458 
01459                         // Find our window and close it if requested.
01460                         self->getWindow()->decBusyCount();
01461                         self->mPendingUploads--;
01462                         if (self->mPendingUploads <= 0
01463                                 && self->mCloseAfterSave)
01464                         {
01465                                 self->close();
01466                         }
01467                 }
01468         }
01469         else
01470         {
01471                 llwarns << "Problem saving LSL Bytecode (Preview)" << llendl;
01472                 LLStringBase<char>::format_map_t args;
01473                 args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status));
01474                 gViewerWindow->alertXml("SaveBytecodeFailReason", args);
01475         }
01476         delete instance_uuid;
01477 }
01478 
01479 // static
01480 void LLPreviewLSL::onLoadComplete( LLVFS *vfs, const LLUUID& asset_uuid, LLAssetType::EType type,
01481                                                                    void* user_data, S32 status, LLExtStat ext_status)
01482 {
01483         lldebugs << "LLPreviewLSL::onLoadComplete: got uuid " << asset_uuid
01484                  << llendl;
01485         LLUUID* item_uuid = (LLUUID*)user_data;
01486         LLPreviewLSL* preview = LLPreviewLSL::getInstance(*item_uuid);
01487         if( preview )
01488         {
01489                 if(0 == status)
01490                 {
01491                         LLVFile file(vfs, asset_uuid, type);
01492                         S32 file_length = file.getSize();
01493 
01494                         char* buffer = new char[file_length+1];
01495                         file.read((U8*)buffer, file_length);            /*Flawfinder: ignore*/
01496 
01497                         // put a EOS at the end
01498                         buffer[file_length] = 0;
01499                         preview->mScriptEd->mEditor->setText(LLStringExplicit(buffer));
01500                         preview->mScriptEd->mEditor->makePristine();
01501                         delete [] buffer;
01502                         LLInventoryItem* item = gInventory.getItem(*item_uuid);
01503                         BOOL is_modifiable = FALSE;
01504                         if(item
01505                            && gAgent.allowOperation(PERM_MODIFY, item->getPermissions(),
01506                                                                         GP_OBJECT_MANIPULATE))
01507                         {
01508                                 is_modifiable = TRUE;           
01509                         }
01510                         preview->mScriptEd->mEditor->setEnabled(is_modifiable);
01511                         preview->mAssetStatus = PREVIEW_ASSET_LOADED;
01512                 }
01513                 else
01514                 {
01515                         LLViewerStats::getInstance()->incStat( LLViewerStats::ST_DOWNLOAD_FAILED );
01516 
01517                         if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
01518                                 LL_ERR_FILE_EMPTY == status)
01519                         {
01520                                 LLNotifyBox::showXml("ScriptMissing");
01521                         }
01522                         else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status)
01523                         {
01524                                 LLNotifyBox::showXml("ScriptNoPermissions");
01525                         }
01526                         else
01527                         {
01528                                 LLNotifyBox::showXml("UnableToLoadScript");
01529                         }
01530 
01531                         preview->mAssetStatus = PREVIEW_ASSET_ERROR;
01532                         llwarns << "Problem loading script: " << status << llendl;
01533                 }
01534         }
01535         delete item_uuid;
01536 }
01537 
01538 // static
01539 LLPreviewLSL* LLPreviewLSL::getInstance( const LLUUID& item_uuid )
01540 {
01541         LLPreview* instance = NULL;
01542         preview_map_t::iterator found_it = LLPreview::sInstances.find(item_uuid);
01543         if(found_it != LLPreview::sInstances.end())
01544         {
01545                 instance = found_it->second;
01546         }
01547         return (LLPreviewLSL*)instance;
01548 }
01549 
01550 void LLPreviewLSL::reshape(S32 width, S32 height, BOOL called_from_parent)
01551 {
01552         LLPreview::reshape( width, height, called_from_parent );
01553 
01554         if( !isMinimized() )
01555         {
01556                 // So that next time you open a script it will have the same height and width 
01557                 // (although not the same position).
01558                 gSavedSettings.setRect("PreviewScriptRect", getRect());
01559         }
01560 }
01561 
01565 
01566 LLMap<LLUUID, LLLiveLSLEditor*> LLLiveLSLEditor::sInstances;
01567 
01568 
01569 
01570 //static 
01571 void* LLLiveLSLEditor::createScriptEdPanel(void* userdata)
01572 {
01573         
01574         LLLiveLSLEditor *self = (LLLiveLSLEditor*)userdata;
01575 
01576         self->mScriptEd =  new LLScriptEdCore("script ed panel",
01577                                                                    LLRect(),
01578                                                                    HELLO_LSL,
01579                                                                    HELP_LSL,
01580                                                                    self->getHandle(),
01581                                                                    &LLLiveLSLEditor::onLoad,
01582                                                                    &LLLiveLSLEditor::onSave,
01583                                                                    &LLLiveLSLEditor::onSearchReplace,
01584                                                                    self,
01585                                                                    0);
01586 
01587         return self->mScriptEd;
01588 }
01589 
01590 
01591 LLLiveLSLEditor::LLLiveLSLEditor(const std::string& name,
01592                                                                  const LLRect& rect,
01593                                                                  const std::string& title,
01594                                                                  const LLUUID& object_id,
01595                                                                  const LLUUID& item_id) :
01596         LLPreview(name, rect, title, item_id, object_id, TRUE, SCRIPT_MIN_WIDTH, SCRIPT_MIN_HEIGHT),
01597         mObjectID(object_id),
01598         mItemID(item_id),
01599         mScriptEd(NULL),
01600         mAskedForRunningInfo(FALSE),
01601         mHaveRunningInfo(FALSE),
01602         mCloseAfterSave(FALSE),
01603         mPendingUploads(0)
01604 {
01605 
01606         
01607         BOOL is_new = FALSE;
01608         if(mItemID.isNull())
01609         {
01610                 mItemID.generate();
01611                 is_new = TRUE;
01612         }
01613 
01614 
01615         LLLiveLSLEditor::sInstances.addData(mItemID ^ mObjectID, this);
01616 
01617 
01618 
01619         LLCallbackMap::map_t factory_map;
01620         factory_map["script ed panel"] = LLCallbackMap(LLLiveLSLEditor::createScriptEdPanel, this);
01621 
01622         LLUICtrlFactory::getInstance()->buildFloater(this,"floater_live_lsleditor.xml", &factory_map);
01623 
01624 
01625         childSetCommitCallback("running", LLLiveLSLEditor::onRunningCheckboxClicked, this);
01626         childSetEnabled("running", FALSE);
01627 
01628         childSetAction("Reset",&LLLiveLSLEditor::onReset,this);
01629         childSetEnabled("Reset", TRUE);
01630 
01631 
01632         mScriptEd->mEditor->makePristine();
01633         loadAsset(is_new);
01634         mScriptEd->mEditor->setFocus(TRUE);
01635 
01636         
01637         if (!getHost())
01638         {
01639                 LLRect curRect = getRect();
01640                 translate(rect.mLeft - curRect.mLeft, rect.mTop - curRect.mTop);
01641         }
01642 
01643         
01644         setTitle(title);
01645 }
01646 
01647 LLLiveLSLEditor::~LLLiveLSLEditor()
01648 {
01649         LLLiveLSLEditor::sInstances.removeData(mItemID ^ mObjectID);
01650 }
01651 
01652 // this is called via LLPreview::loadAsset() virtual method
01653 void LLLiveLSLEditor::loadAsset()
01654 {
01655         loadAsset(FALSE);
01656 }
01657 
01658 // virtual
01659 void LLLiveLSLEditor::callbackLSLCompileSucceeded(const LLUUID& task_id,
01660                                                                                                   const LLUUID& item_id,
01661                                                                                                   bool is_script_running)
01662 {
01663         lldebugs << "LSL Bytecode saved" << llendl;
01664         mScriptEd->mErrorList->addCommentText("Compile successful!");
01665         mScriptEd->mErrorList->addCommentText("Save complete.");
01666         closeIfNeeded();
01667 }
01668 
01669 // virtual
01670 void LLLiveLSLEditor::callbackLSLCompileFailed(const LLSD& compile_errors)
01671 {
01672         lldebugs << "Compile failed!" << llendl;
01673         for(LLSD::array_const_iterator line = compile_errors.beginArray();
01674                 line < compile_errors.endArray();
01675                 line++)
01676         {
01677                 LLSD row;
01678                 row["columns"][0]["value"] = line->asString();
01679                 row["columns"][0]["font"] = "OCRA";
01680                 mScriptEd->mErrorList->addElement(row);
01681         }
01682         mScriptEd->selectFirstError();
01683         closeIfNeeded();
01684 }
01685 
01686 void LLLiveLSLEditor::loadAsset(BOOL is_new)
01687 {
01688         //llinfos << "LLLiveLSLEditor::loadAsset()" << llendl;
01689         if(!is_new)
01690         {
01691                 LLViewerObject* object = gObjectList.findObject(mObjectID);
01692                 if(object)
01693                 {
01694                         // HACK! we "know" that mItemID refers to a LLViewerInventoryItem...
01695                         LLViewerInventoryItem* item = (LLViewerInventoryItem*)object->getInventoryObject(mItemID);
01696                         if(item 
01697                                 && (gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE)
01698                                    || gAgent.isGodlike()))
01699                         {
01700                                 mItem = new LLViewerInventoryItem(item);
01701                                 //llinfos << "asset id " << mItem->getAssetUUID() << llendl;
01702                         }
01703 
01704                         if(!gAgent.isGodlike()
01705                            && (item
01706                                    && (!gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE)
01707                                            || !gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE))))
01708                         {
01709                                 mItem = new LLViewerInventoryItem(item);
01710                                 mScriptEd->mEditor->setText(getString("not_allowed"));
01711                                 mScriptEd->mEditor->makePristine();
01712                                 mScriptEd->mEditor->setEnabled(FALSE);
01713                                 mAssetStatus = PREVIEW_ASSET_LOADED;
01714                         }
01715                         else if(item && mItem.notNull())
01716                         {
01717                                 // request the text from the object
01718                                 LLUUID* user_data = new LLUUID(mItemID ^ mObjectID);
01719                                 gAssetStorage->getInvItemAsset(object->getRegion()->getHost(),
01720                                                                                         gAgent.getID(),
01721                                                                                         gAgent.getSessionID(),
01722                                                                                         item->getPermissions().getOwner(),
01723                                                                                         object->getID(),
01724                                                                                         item->getUUID(),
01725                                                                                         item->getAssetUUID(),
01726                                                                                         item->getType(),
01727                                                                                         &LLLiveLSLEditor::onLoadComplete,
01728                                                                                         (void*)user_data,
01729                                                                                         TRUE);
01730                                 LLMessageSystem* msg = gMessageSystem;
01731                                 msg->newMessageFast(_PREHASH_GetScriptRunning);
01732                                 msg->nextBlockFast(_PREHASH_Script);
01733                                 msg->addUUIDFast(_PREHASH_ObjectID, mObjectID);
01734                                 msg->addUUIDFast(_PREHASH_ItemID, mItemID);
01735                                 msg->sendReliable(object->getRegion()->getHost());
01736                                 mAskedForRunningInfo = TRUE;
01737                                 mAssetStatus = PREVIEW_ASSET_LOADING;
01738                         }
01739                         else
01740                         {
01741                                 mScriptEd->mEditor->setText(LLString::null);
01742                                 mScriptEd->mEditor->makePristine();
01743                                 mAssetStatus = PREVIEW_ASSET_LOADED;
01744                         }
01745 
01746                         if(item
01747                            && !gAgent.allowOperation(PERM_MODIFY, item->getPermissions(),
01748                                                                                 GP_OBJECT_MANIPULATE))
01749                         {
01750                                 mScriptEd->mEditor->setEnabled(FALSE);
01751                         }
01752                         // This is commented out, because we don't completely
01753                         // handle script exports yet.
01754                         /*
01755                         // request the exports from the object
01756                         gMessageSystem->newMessage("GetScriptExports");
01757                         gMessageSystem->nextBlock("ScriptBlock");
01758                         gMessageSystem->addUUID("AgentID", gAgent.getID());
01759                         U32 local_id = object->getLocalID();
01760                         gMessageSystem->addData("LocalID", &local_id);
01761                         gMessageSystem->addUUID("ItemID", mItemID);
01762                         LLHost host(object->getRegion()->getIP(),
01763                                                 object->getRegion()->getPort());
01764                         gMessageSystem->sendReliable(host);
01765                         */
01766                 }
01767 
01768                 // Initialization of the asset failed. Probably the result 
01769                 // of a bug somewhere else. Set up this editor in a no-go mode.
01770                 if(mItem.isNull())
01771                 {
01772                         // Set the inventory item to an incomplete item.
01773                         // This may be better than having a accessible null pointer around,
01774                         // though this newly allocated object will most likely be replaced.
01775                         mItem = new LLViewerInventoryItem();
01776                         mScriptEd->mEditor->setText(LLString::null);
01777                         mScriptEd->mEditor->makePristine();
01778                         mScriptEd->mEditor->setEnabled(FALSE);
01779                         mAssetStatus = PREVIEW_ASSET_LOADED;
01780                 }
01781         }
01782         else
01783         {
01784                 mScriptEd->mEditor->setText(LLString(HELLO_LSL));
01785                 //mScriptEd->mEditor->setText(LLString::null);
01786                 //mScriptEd->mEditor->makePristine();
01787                 LLPermissions perm;
01788                 perm.init(gAgent.getID(), gAgent.getID(), LLUUID::null, gAgent.getGroupID());
01789                 perm.initMasks(PERM_ALL, PERM_ALL, PERM_NONE, PERM_NONE, PERM_MOVE | PERM_TRANSFER);
01790                 mItem = new LLViewerInventoryItem(mItemID,
01791                                                                         mObjectID,
01792                                                                         perm,
01793                                                                         LLUUID::null,
01794                                                                         LLAssetType::AT_LSL_TEXT,
01795                                                                         LLInventoryType::IT_LSL,
01796                                                                         DEFAULT_SCRIPT_NAME,
01797                                                                         DEFAULT_SCRIPT_DESC,
01798                                                                         LLSaleInfo::DEFAULT,
01799                                                                         LLInventoryItem::II_FLAGS_NONE,
01800                                                                         time_corrected());
01801                 mAssetStatus = PREVIEW_ASSET_LOADED;
01802         }
01803 }
01804 
01805 // static
01806 void LLLiveLSLEditor::onLoadComplete(LLVFS *vfs, const LLUUID& asset_id,
01807                                                                          LLAssetType::EType type,
01808                                                                          void* user_data, S32 status, LLExtStat ext_status)
01809 {
01810         lldebugs << "LLLiveLSLEditor::onLoadComplete: got uuid " << asset_id
01811                  << llendl;
01812         LLLiveLSLEditor* instance = NULL;
01813         LLUUID* xored_id = (LLUUID*)user_data;
01814 
01815         if( LLLiveLSLEditor::sInstances.checkData(*xored_id) )
01816         {
01817                 instance = LLLiveLSLEditor::sInstances[*xored_id];
01818                 if( LL_ERR_NOERR == status )
01819                 {
01820                         instance->loadScriptText(vfs, asset_id, type);
01821                         instance->mAssetStatus = PREVIEW_ASSET_LOADED;
01822                 }
01823                 else
01824                 {
01825                         LLViewerStats::getInstance()->incStat( LLViewerStats::ST_DOWNLOAD_FAILED );
01826 
01827                         if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
01828                                 LL_ERR_FILE_EMPTY == status)
01829                         {
01830                                 LLNotifyBox::showXml("ScriptMissing");
01831                         }
01832                         else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status)
01833                         {
01834                                 LLNotifyBox::showXml("ScriptNoPermissions");
01835                         }
01836                         else
01837                         {
01838                                 LLNotifyBox::showXml("UnableToLoadScript");
01839                         }
01840                         instance->mAssetStatus = PREVIEW_ASSET_ERROR;
01841                 }
01842         }
01843 
01844         delete xored_id;
01845 }
01846 
01847 void LLLiveLSLEditor::loadScriptText(const char* filename)
01848 {
01849         if(!filename)
01850         {
01851                 llerrs << "Filename is Empty!" << llendl;
01852                 return;
01853         }
01854         LLFILE* file = LLFile::fopen(filename, "rb");           /*Flawfinder: ignore*/
01855         if(file)
01856         {
01857                 // read in the whole file
01858                 fseek(file, 0L, SEEK_END);
01859                 long file_length = ftell(file);
01860                 fseek(file, 0L, SEEK_SET);
01861                 char* buffer = new char[file_length+1];
01862                 size_t nread = fread(buffer, 1, file_length, file);
01863                 if (nread < (size_t) file_length)
01864                 {
01865                         llwarns << "Short read" << llendl;
01866                 }
01867                 buffer[nread] = '\0';
01868                 fclose(file);
01869                 mScriptEd->mEditor->setText(LLStringExplicit(buffer));
01870                 mScriptEd->mEditor->makePristine();
01871                 delete[] buffer;
01872         }
01873         else
01874         {
01875                 llwarns << "Error opening " << filename << llendl;
01876         }
01877 }
01878 
01879 void LLLiveLSLEditor::loadScriptText(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type)
01880 {
01881         LLVFile file(vfs, uuid, type);
01882         S32 file_length = file.getSize();
01883         char *buffer = new char[file_length + 1];
01884         file.read((U8*)buffer, file_length);            /*Flawfinder: ignore*/
01885 
01886         if (file.getLastBytesRead() != file_length ||
01887                 file_length <= 0)
01888         {
01889                 llwarns << "Error reading " << uuid << ":" << type << llendl;
01890         }
01891 
01892         buffer[file_length] = '\0';
01893 
01894         mScriptEd->mEditor->setText(LLStringExplicit(buffer));
01895         mScriptEd->mEditor->makePristine();
01896         delete[] buffer;
01897 
01898 }
01899 
01900 
01901 void LLLiveLSLEditor::onRunningCheckboxClicked( LLUICtrl*, void* userdata )
01902 {
01903         LLLiveLSLEditor* self = (LLLiveLSLEditor*) userdata;
01904         LLViewerObject* object = gObjectList.findObject( self->mObjectID );
01905         LLCheckBoxCtrl* runningCheckbox = self->getChild<LLCheckBoxCtrl>("running");
01906         BOOL running =  runningCheckbox->get();
01907         //self->mRunningCheckbox->get();
01908         if( object )
01909         {
01910                 LLMessageSystem* msg = gMessageSystem;
01911                 msg->newMessageFast(_PREHASH_SetScriptRunning);
01912                 msg->nextBlockFast(_PREHASH_AgentData);
01913                 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
01914                 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
01915                 msg->nextBlockFast(_PREHASH_Script);
01916                 msg->addUUIDFast(_PREHASH_ObjectID, self->mObjectID);
01917                 msg->addUUIDFast(_PREHASH_ItemID, self->mItemID);
01918                 msg->addBOOLFast(_PREHASH_Running, running);
01919                 msg->sendReliable(object->getRegion()->getHost());
01920         }
01921         else
01922         {
01923                 runningCheckbox->set(!running);
01924                 gViewerWindow->alertXml("CouldNotStartStopScript");
01925         }
01926 }
01927 
01928 void LLLiveLSLEditor::onReset(void *userdata)
01929 {
01930         LLLiveLSLEditor* self = (LLLiveLSLEditor*) userdata;
01931 
01932         LLViewerObject* object = gObjectList.findObject( self->mObjectID );
01933         if(object)
01934         {
01935                 LLMessageSystem* msg = gMessageSystem;
01936                 msg->newMessageFast(_PREHASH_ScriptReset);
01937                 msg->nextBlockFast(_PREHASH_AgentData);
01938                 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
01939                 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
01940                 msg->nextBlockFast(_PREHASH_Script);
01941                 msg->addUUIDFast(_PREHASH_ObjectID, self->mObjectID);
01942                 msg->addUUIDFast(_PREHASH_ItemID, self->mItemID);
01943                 msg->sendReliable(object->getRegion()->getHost());
01944         }
01945         else
01946         {
01947                 gViewerWindow->alertXml("CouldNotStartStopScript"); 
01948         }
01949 }
01950 
01951 void LLLiveLSLEditor::draw()
01952 {
01953         LLViewerObject* object = gObjectList.findObject(mObjectID);
01954         LLCheckBoxCtrl* runningCheckbox = getChild<LLCheckBoxCtrl>( "running");
01955                 if(object && mAskedForRunningInfo && mHaveRunningInfo)
01956         {
01957                 if(object->permAnyOwner())
01958                 {
01959                         runningCheckbox->setLabel(getString("script_running"));
01960                         runningCheckbox->setEnabled(TRUE);
01961                 }
01962                 else
01963                 {
01964                         runningCheckbox->setLabel(getString("public_objects_can_not_run"));
01965                         runningCheckbox->setEnabled(FALSE);
01966                         // *FIX: Set it to false so that the ui is correct for
01967                         // a box that is released to public. It could be
01968                         // incorrect after a release/claim cycle, but will be
01969                         // correct after clicking on it.
01970                         runningCheckbox->set(FALSE);
01971                 }
01972         }
01973         else if(!object)
01974         {
01975                 // HACK: Display this information in the title bar.
01976                 // Really ought to put in main window.
01977                 setTitle("Script (object out of range)");
01978                 runningCheckbox->setEnabled(FALSE);
01979                 // object may have fallen out of range.
01980                 mHaveRunningInfo = FALSE;
01981         }
01982 
01983         LLFloater::draw();
01984 }
01985 
01986 
01987 void LLLiveLSLEditor::onSearchReplace(void* userdata)
01988 {
01989         LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata;
01990 
01991         LLScriptEdCore* sec = self->mScriptEd; 
01992         LLFloaterScriptSearch::show(sec);
01993 }
01994 
01995 struct LLLiveLSLSaveData
01996 {
01997         LLLiveLSLSaveData(const LLUUID& id, const LLViewerInventoryItem* item, BOOL active);
01998         LLUUID mObjectID;
01999         LLPointer<LLViewerInventoryItem> mItem;
02000         BOOL mActive;
02001 };
02002 
02003 LLLiveLSLSaveData::LLLiveLSLSaveData(const LLUUID& id,
02004                                                                          const LLViewerInventoryItem* item,
02005                                                                          BOOL active) :
02006         mObjectID(id),
02007         mActive(active)
02008 {
02009         llassert(item);
02010         mItem = new LLViewerInventoryItem(item);
02011 }
02012 
02013 void LLLiveLSLEditor::saveIfNeeded()
02014 {
02015         llinfos << "LLLiveLSLEditor::saveIfNeeded()" << llendl;
02016         LLViewerObject* object = gObjectList.findObject(mObjectID);
02017         if(!object)
02018         {
02019                 gViewerWindow->alertXml("SaveScriptFailObjectNotFound");
02020                 return;
02021         }
02022 
02023         if(mItem.isNull() || !mItem->isComplete())
02024         {
02025                 // $NOTE: While the error message may not be exactly correct,
02026                 // it's pretty close.
02027                 gViewerWindow->alertXml("SaveScriptFailObjectNotFound");
02028                 return;
02029         }
02030 
02031         // get the latest info about it. We used to be losing the script
02032         // name on save, because the viewer object version of the item,
02033         // and the editor version would get out of synch. Here's a good
02034         // place to synch them back up.
02035         // HACK! we "know" that mItemID refers to a LLInventoryItem...
02036         LLInventoryItem* inv_item = (LLInventoryItem*)object->getInventoryObject(mItemID);
02037         if(inv_item)
02038         {
02039                 mItem->copyItem(inv_item);
02040         }
02041 
02042         // Don't need to save if we're pristine
02043         if(mScriptEd->mEditor->isPristine())
02044         {
02045                 return;
02046         }
02047 
02048         mPendingUploads = 0;
02049 
02050         // save the script
02051         mScriptEd->mEditor->makePristine();
02052         mScriptEd->mErrorList->deleteAllItems();
02053 
02054         // set up the save on the local machine.
02055         mScriptEd->mEditor->makePristine();
02056         LLTransactionID tid;
02057         tid.generate();
02058         LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
02059         std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id.asString());
02060         std::string filename = llformat("%s.lsl", filepath.c_str());
02061 
02062         mItem->setAssetUUID(asset_id);
02063         mItem->setTransactionID(tid);
02064 
02065         // write out the data, and store it in the asset database
02066         LLFILE* fp = LLFile::fopen(filename.c_str(), "wb");
02067         if(!fp)
02068         {
02069                 llwarns << "Unable to write to " << filename << llendl;
02070 
02071                 LLSD row;
02072                 row["columns"][0]["value"] = "Error writing to local file. Is your hard drive full?";
02073                 row["columns"][0]["font"] = "SANSSERIF_SMALL";
02074                 mScriptEd->mErrorList->addElement(row);
02075                 return;
02076         }
02077         LLString utf8text = mScriptEd->mEditor->getText();
02078 
02079         // Special case for a completely empty script - stuff in one space so it can store properly.  See SL-46889
02080         if ( utf8text.size() == 0 )
02081         {
02082                 utf8text = " ";
02083         }
02084 
02085         fputs(utf8text.c_str(), fp);
02086         fclose(fp);
02087         fp = NULL;
02088         
02089         // save it out to asset server
02090         std::string url = gAgent.getRegion()->getCapability("UpdateScriptTaskInventory");
02091         getWindow()->incBusyCount();
02092         mPendingUploads++;
02093         BOOL is_running = getChild<LLCheckBoxCtrl>( "running")->get();
02094         if (!url.empty())
02095         {
02096                 uploadAssetViaCaps(url, filename, mObjectID,
02097                                                    mItemID, is_running);
02098         }
02099         else if (gAssetStorage)
02100         {
02101                 uploadAssetLegacy(filename, object, tid, is_running);
02102         }
02103 }
02104 
02105 void LLLiveLSLEditor::uploadAssetViaCaps(const std::string& url,
02106                                                                                  const std::string& filename,
02107                                                                                  const LLUUID& task_id,
02108                                                                                  const LLUUID& item_id,
02109                                                                                  BOOL is_running)
02110 {
02111         llinfos << "Update Task Inventory via capability" << llendl;
02112         LLSD body;
02113         body["task_id"] = task_id;
02114         body["item_id"] = item_id;
02115         body["is_script_running"] = is_running;
02116         LLHTTPClient::post(url, body,
02117                 new LLUpdateTaskInventoryResponder(body, filename));
02118 }
02119 
02120 void LLLiveLSLEditor::uploadAssetLegacy(const std::string& filename,
02121                                                                                 LLViewerObject* object,
02122                                                                                 const LLTransactionID& tid,
02123                                                                                 BOOL is_running)
02124 {
02125         LLLiveLSLSaveData* data = new LLLiveLSLSaveData(mObjectID,
02126                                                                                                         mItem,
02127                                                                                                         is_running);
02128         gAssetStorage->storeAssetData(filename.c_str(), tid,
02129                                                                   LLAssetType::AT_LSL_TEXT,
02130                                                                   &onSaveTextComplete,
02131                                                                   (void*)data,
02132                                                                   FALSE);
02133 
02134         LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
02135         std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id.asString());
02136         std::string dst_filename = llformat("%s.lso", filepath.c_str());
02137         std::string err_filename = llformat("%s.out", filepath.c_str());
02138 
02139         LLFILE *fp;
02140         if(!lscript_compile(filename.c_str(),
02141                                                 dst_filename.c_str(),
02142                                                 err_filename.c_str(),
02143                                                 gAgent.isGodlike()))
02144         {
02145                 // load the error file into the error scrolllist
02146                 llinfos << "Compile failed!" << llendl;
02147                 if(NULL != (fp = LLFile::fopen(err_filename.c_str(), "r")))
02148                 {
02149                         char buffer[MAX_STRING];                /*Flawfinder: ignore*/
02150                         LLString line;
02151                         while(!feof(fp)) 
02152                         {
02153                                 
02154                                 if (fgets(buffer, MAX_STRING, fp) == NULL)
02155                                 {
02156                                         buffer[0] = '\0';
02157                                 }
02158                                 if(feof(fp))
02159                                 {
02160                                         break;
02161                                 }
02162                                 else
02163                                 {
02164                                         line.assign(buffer);
02165                                         LLString::stripNonprintable(line);
02166                                 
02167                                         LLSD row;
02168                                         row["columns"][0]["value"] = line;
02169                                         row["columns"][0]["font"] = "OCRA";
02170                                         mScriptEd->mErrorList->addElement(row);
02171                                 }
02172                         }
02173                         fclose(fp);
02174                         mScriptEd->selectFirstError();
02175                         // don't set the asset id, because we want to save the
02176                         // script, even though the compile failed.
02177                         //mItem->setAssetUUID(LLUUID::null);
02178                         object->saveScript(mItem, FALSE, false);
02179                         dialog_refresh_all();
02180                 }
02181         }
02182         else
02183         {
02184                 llinfos << "Compile worked!" << llendl;
02185                 mScriptEd->mErrorList->addCommentText("Compile successful, saving...");
02186                 if(gAssetStorage)
02187                 {
02188                         llinfos << "LLLiveLSLEditor::saveAsset "
02189                                         << mItem->getAssetUUID() << llendl;
02190                         getWindow()->incBusyCount();
02191                         mPendingUploads++;
02192                         LLLiveLSLSaveData* data = NULL;
02193                         data = new LLLiveLSLSaveData(mObjectID,
02194                                                                                  mItem,
02195                                                                                  is_running);
02196                         gAssetStorage->storeAssetData(dst_filename.c_str(),
02197                                                                                   tid,
02198                                                                                   LLAssetType::AT_LSL_BYTECODE,
02199                                                                                   &LLLiveLSLEditor::onSaveBytecodeComplete,
02200                                                                                   (void*)data);
02201                         dialog_refresh_all();
02202                 }
02203         }
02204 
02205         // get rid of any temp files left lying around
02206         LLFile::remove(filename.c_str());
02207         LLFile::remove(err_filename.c_str());
02208         LLFile::remove(dst_filename.c_str());
02209 
02210         // If we successfully saved it, then we should be able to check/uncheck the running box!
02211         LLCheckBoxCtrl* runningCheckbox = getChild<LLCheckBoxCtrl>( "running");
02212         runningCheckbox->setLabel(getString("script_running"));
02213         runningCheckbox->setEnabled(TRUE);
02214 }
02215 
02216 void LLLiveLSLEditor::onSaveTextComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed)
02217 {
02218         LLLiveLSLSaveData* data = (LLLiveLSLSaveData*)user_data;
02219 
02220         if (status)
02221         {
02222                 llwarns << "Unable to save text for a script." << llendl;
02223                 LLStringBase<char>::format_map_t args;
02224                 args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status));
02225                 gViewerWindow->alertXml("CompileQueueSaveText", args);
02226         }
02227         else
02228         {
02229                 LLLiveLSLEditor* self = sInstances.getIfThere(data->mItem->getUUID() ^ data->mObjectID);
02230                 if (self)
02231                 {
02232                         self->getWindow()->decBusyCount();
02233                         self->mPendingUploads--;
02234                         if (self->mPendingUploads <= 0
02235                                 && self->mCloseAfterSave)
02236                         {
02237                                 self->close();
02238                         }
02239                 }
02240         }
02241         delete data;
02242         data = NULL;
02243 }
02244 
02245 
02246 void LLLiveLSLEditor::onSaveBytecodeComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed)
02247 {
02248         LLLiveLSLSaveData* data = (LLLiveLSLSaveData*)user_data;
02249         if(!data)
02250                 return;
02251         if(0 ==status)
02252         {
02253                 llinfos << "LSL Bytecode saved" << llendl;
02254                 LLUUID xor_id = data->mItem->getUUID() ^ data->mObjectID;
02255                 LLLiveLSLEditor* self = sInstances.getIfThere(xor_id);
02256                 if(self)
02257                 {
02258                         // Tell the user that the compile worked.
02259                         self->mScriptEd->mErrorList->addCommentText("Save complete.");
02260                         // close the window if this completes both uploads
02261                         self->getWindow()->decBusyCount();
02262                         self->mPendingUploads--;
02263                         if (self->mPendingUploads <= 0
02264                                 && self->mCloseAfterSave)
02265                         {
02266                                 self->close();
02267                         }
02268                 }
02269                 LLViewerObject* object = gObjectList.findObject(data->mObjectID);
02270                 if(object)
02271                 {
02272                         object->saveScript(data->mItem, data->mActive, false);
02273                         dialog_refresh_all();
02274                         //LLToolDragAndDrop::dropScript(object, ids->first,
02275                         //                                                LLAssetType::AT_LSL_TEXT, FALSE);
02276                 }
02277         }
02278         else
02279         {
02280                 llinfos << "Problem saving LSL Bytecode (Live Editor)" << llendl;
02281                 llwarns << "Unable to save a compiled script." << llendl;
02282 
02283                 LLStringBase<char>::format_map_t args;
02284                 args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status));
02285                 gViewerWindow->alertXml("CompileQueueSaveBytecode", args);
02286         }
02287 
02288         std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_uuid.asString());
02289         std::string dst_filename = llformat("%s.lso", filepath.c_str());
02290         LLFile::remove(dst_filename.c_str());
02291         delete data;
02292 }
02293 
02294 void LLLiveLSLEditor::open()
02295 {
02296         LLFloater::open();              /*Flawfinder: ignore*/
02297 }
02298 
02299 BOOL LLLiveLSLEditor::canClose()
02300 {
02301         return (mScriptEd->canClose());
02302 }
02303 
02304 void LLLiveLSLEditor::closeIfNeeded()
02305 {
02306         getWindow()->decBusyCount();
02307         mPendingUploads--;
02308         if (mPendingUploads <= 0 && mCloseAfterSave)
02309         {
02310                 close();
02311         }
02312 }
02313 
02314 // static
02315 void LLLiveLSLEditor::onLoad(void* userdata)
02316 {
02317         LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata;
02318         self->loadAsset();
02319 }
02320 
02321 // static
02322 void LLLiveLSLEditor::onSave(void* userdata, BOOL close_after_save)
02323 {
02324         LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata;
02325         self->mCloseAfterSave = close_after_save;
02326         self->saveIfNeeded();
02327 }
02328 
02329 // static
02330 LLLiveLSLEditor* LLLiveLSLEditor::show(const LLUUID& script_id, const LLUUID& object_id)
02331 {
02332         LLLiveLSLEditor* instance = NULL;
02333         LLUUID xored_id = script_id ^ object_id;
02334         if(LLLiveLSLEditor::sInstances.checkData(xored_id))
02335         {
02336                 // Move the existing view to the front
02337                 instance = LLLiveLSLEditor::sInstances[xored_id];
02338                 instance->open();               /*Flawfinder: ignore*/
02339         }
02340         return instance;
02341 }
02342 
02343 // static
02344 void LLLiveLSLEditor::hide(const LLUUID& script_id, const LLUUID& object_id)
02345 {
02346         LLUUID xored_id = script_id ^ object_id;
02347         if( LLLiveLSLEditor::sInstances.checkData( xored_id ) )
02348         {
02349                 LLLiveLSLEditor* instance = LLLiveLSLEditor::sInstances[xored_id];
02350                 if(instance->getParent())
02351                 {
02352                         instance->getParent()->removeChild(instance);
02353                 }
02354                 delete instance;
02355         }
02356 }
02357 // static
02358 LLLiveLSLEditor* LLLiveLSLEditor::find(const LLUUID& script_id, const LLUUID& object_id)
02359 {
02360         LLUUID xored_id = script_id ^ object_id;
02361         return sInstances.getIfThere(xored_id);
02362 }
02363 
02364 
02365 // static
02366 void LLLiveLSLEditor::processScriptRunningReply(LLMessageSystem* msg, void**)
02367 {
02368         LLUUID item_id;
02369         LLUUID object_id;
02370         msg->getUUIDFast(_PREHASH_Script, _PREHASH_ObjectID, object_id);
02371         msg->getUUIDFast(_PREHASH_Script, _PREHASH_ItemID, item_id);
02372         LLUUID xored_id = item_id ^ object_id;
02373         if(LLLiveLSLEditor::sInstances.checkData(xored_id))
02374         {
02375                 LLLiveLSLEditor* instance = LLLiveLSLEditor::sInstances[xored_id];
02376                 instance->mHaveRunningInfo = TRUE;
02377                 BOOL running;
02378                 msg->getBOOLFast(_PREHASH_Script, _PREHASH_Running, running);
02379                 LLCheckBoxCtrl* runningCheckbox = instance->getChild<LLCheckBoxCtrl>("running");
02380                 runningCheckbox->set(running);
02381         }
02382 }
02383 
02384 void LLLiveLSLEditor::reshape(S32 width, S32 height, BOOL called_from_parent)
02385 {
02386         LLFloater::reshape( width, height, called_from_parent );
02387 
02388         if( !isMinimized() )
02389         {
02390                 // So that next time you open a script it will have the same height and width 
02391                 // (although not the same position).
02392                 gSavedSettings.setRect("PreviewScriptRect", getRect());
02393         }
02394 }

Generated on Fri May 16 08:33:57 2008 for SecondLife by  doxygen 1.5.5