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

Generated on Thu Jul 1 06:09:02 2010 for Second Life Viewer by  doxygen 1.4.7