summaryrefslogtreecommitdiff
path: root/indra/newview/llpreviewscript.cpp
diff options
context:
space:
mode:
authorJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
committerJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
commit420b91db29485df39fd6e724e782c449158811cb (patch)
treeb471a94563af914d3ed3edd3e856d21cb1b69945 /indra/newview/llpreviewscript.cpp
Print done when done.
Diffstat (limited to 'indra/newview/llpreviewscript.cpp')
-rw-r--r--indra/newview/llpreviewscript.cpp1984
1 files changed, 1984 insertions, 0 deletions
diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp
new file mode 100644
index 0000000000..175824d866
--- /dev/null
+++ b/indra/newview/llpreviewscript.cpp
@@ -0,0 +1,1984 @@
+/**
+ * @file llpreviewscript.cpp
+ * @brief LLPreviewScript class implementation
+ *
+ * Copyright (c) 2002-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llpreviewscript.h"
+
+#include "llassetstorage.h"
+#include "llbutton.h"
+#include "llcheckboxctrl.h"
+#include "llcombobox.h"
+#include "lldir.h"
+#include "llinventorymodel.h"
+#include "llkeyboard.h"
+#include "lllineeditor.h"
+
+#include "llresmgr.h"
+#include "llscrollbar.h"
+#include "llscrollcontainer.h"
+#include "llscrolllistctrl.h"
+#include "llslider.h"
+#include "lscript_rt_interface.h"
+#include "lscript_export.h"
+#include "lltextbox.h"
+#include "lltooldraganddrop.h"
+#include "llvfile.h"
+
+#include "llagent.h"
+#include "llnotify.h"
+#include "llmenugl.h"
+#include "roles_constants.h"
+#include "llselectmgr.h"
+#include "llviewerinventory.h"
+#include "llviewermenu.h"
+#include "llviewerobject.h"
+#include "llviewerobjectlist.h"
+#include "llviewerregion.h"
+#include "llkeyboard.h"
+#include "llscrollcontainer.h"
+#include "llcheckboxctrl.h"
+#include "llselectmgr.h"
+#include "lltooldraganddrop.h"
+#include "llscrolllistctrl.h"
+#include "lltextbox.h"
+#include "llslider.h"
+#include "viewer.h"
+#include "lldir.h"
+#include "llcombobox.h"
+//#include "llfloaterchat.h"
+#include "llviewerstats.h"
+#include "llviewertexteditor.h"
+#include "llviewerwindow.h"
+#include "llvieweruictrlfactory.h"
+#include "lluictrlfactory.h"
+
+#include "viewer.h"
+
+#include "llpanelinventory.h"
+
+
+const char HELLO_LSL[] =
+ "default\n"
+ "{\n"
+ " state_entry()\n"
+ " {\n"
+ " llSay(0, \"Hello, Avatar!\");\n"
+ " }\n"
+ "\n"
+ " touch_start(integer total_number)\n"
+ " {\n"
+ " llSay(0, \"Touched.\");\n"
+ " }\n"
+ "}\n";
+const char HELP_LSL[] = "lsl_guide.html";
+
+const char DEFAULT_SCRIPT_NAME[] = "New Script";
+const char DEFAULT_SCRIPT_DESC[] = "(No Description)";
+
+const char ENABLED_RUNNING_CHECKBOX_LABEL[] = "Running";
+const char DISABLED_RUNNING_CHECKBOX_LABEL[] = "Public Objects cannot run scripts";
+
+// Description and header information
+
+const S32 SCRIPT_BORDER = 4;
+const S32 SCRIPT_PAD = 5;
+const S32 SCRIPT_BUTTON_WIDTH = 128;
+const S32 SCRIPT_BUTTON_HEIGHT = 24; // HACK: Use BTN_HEIGHT where possible.
+const S32 LINE_COLUMN_HEIGHT = 14;
+const S32 BTN_PAD = 8;
+
+const S32 SCRIPT_EDITOR_MIN_HEIGHT = 2 * SCROLLBAR_SIZE + 2 * LLPANEL_BORDER_WIDTH + 128;
+
+const S32 SCRIPT_MIN_WIDTH =
+ 2 * SCRIPT_BORDER +
+ 2 * SCRIPT_BUTTON_WIDTH +
+ SCRIPT_PAD + RESIZE_HANDLE_WIDTH +
+ SCRIPT_PAD;
+
+const S32 SCRIPT_MIN_HEIGHT =
+ 2 * SCRIPT_BORDER +
+ 3*(SCRIPT_BUTTON_HEIGHT + SCRIPT_PAD) +
+ LINE_COLUMN_HEIGHT +
+ SCRIPT_EDITOR_MIN_HEIGHT;
+
+const S32 MAX_EXPORT_SIZE = 1000;
+
+const S32 SCRIPT_SEARCH_WIDTH = 300;
+const S32 SCRIPT_SEARCH_HEIGHT = 120;
+const S32 SCRIPT_SEARCH_LABEL_WIDTH = 50;
+const S32 SCRIPT_SEARCH_BUTTON_WIDTH = 80;
+const S32 TEXT_EDIT_COLUMN_HEIGHT = 16;
+/// ---------------------------------------------------------------------------
+/// LLFloaterScriptSearch
+/// ---------------------------------------------------------------------------
+class LLFloaterScriptSearch : public LLFloater
+{
+public:
+ LLFloaterScriptSearch(std::string title, LLRect rect, LLScriptEdCore* editor_core);
+ ~LLFloaterScriptSearch();
+
+ static void show(LLScriptEdCore* editor_core);
+ static void onBtnSearch(void* userdata);
+ void handleBtnSearch();
+
+ static void onBtnReplace(void* userdata);
+ void handleBtnReplace();
+
+ static void onBtnReplaceAll(void* userdata);
+ void handleBtnReplaceAll();
+
+ LLScriptEdCore* getEditorCore() { return mEditorCore; }
+ static LLFloaterScriptSearch* getInstance() { return sInstance; }
+
+ void open();
+
+private:
+
+ LLScriptEdCore* mEditorCore;
+
+ static LLFloaterScriptSearch* sInstance;
+};
+
+LLFloaterScriptSearch* LLFloaterScriptSearch::sInstance = NULL;
+
+LLFloaterScriptSearch::LLFloaterScriptSearch(std::string title, LLRect rect, LLScriptEdCore* editor_core)
+ : LLFloater("script search",rect,title), mEditorCore(editor_core)
+{
+
+ gUICtrlFactory->buildFloater(this,"floater_script_search.xml");
+
+ childSetAction("search_btn", onBtnSearch,this);
+ childSetAction("replace_btn", onBtnReplace,this);
+ childSetAction("replace_all_btn", onBtnReplaceAll,this);
+
+ setDefaultBtn("search_btn");
+
+ if (!getHost())
+ {
+ LLRect curRect = getRect();
+ translate(rect.mLeft - curRect.mLeft, rect.mTop - curRect.mTop);
+ }
+
+ sInstance = this;
+
+ childSetFocus("search_text", TRUE);
+}
+
+//static
+void LLFloaterScriptSearch::show(LLScriptEdCore* editor_core)
+{
+ if (sInstance && sInstance->mEditorCore && sInstance->mEditorCore != editor_core)
+ {
+ sInstance->close();
+ delete sInstance;
+ }
+
+ if (!sInstance)
+ {
+ S32 left = 0;
+ S32 top = 0;
+ gFloaterView->getNewFloaterPosition(&left,&top);
+
+ // sInstance will be assigned in the constructor.
+ new LLFloaterScriptSearch("Script Search",LLRect(left,top,left + SCRIPT_SEARCH_WIDTH,top - SCRIPT_SEARCH_HEIGHT),editor_core);
+ }
+
+ sInstance->open();
+}
+
+LLFloaterScriptSearch::~LLFloaterScriptSearch()
+{
+ sInstance = NULL;
+}
+
+// static
+void LLFloaterScriptSearch::onBtnSearch(void *userdata)
+{
+ LLFloaterScriptSearch* self = (LLFloaterScriptSearch*)userdata;
+ self->handleBtnSearch();
+}
+
+void LLFloaterScriptSearch::handleBtnSearch()
+{
+ LLCheckBoxCtrl* caseChk = LLUICtrlFactory::getCheckBoxByName(this,"case_text");
+ mEditorCore->mEditor->selectNext(childGetText("search_text"), caseChk->get());
+}
+
+// static
+void LLFloaterScriptSearch::onBtnReplace(void *userdata)
+{
+ LLFloaterScriptSearch* self = (LLFloaterScriptSearch*)userdata;
+ self->handleBtnReplace();
+}
+
+void LLFloaterScriptSearch::handleBtnReplace()
+{
+ LLCheckBoxCtrl* caseChk = LLUICtrlFactory::getCheckBoxByName(this,"case_text");
+ mEditorCore->mEditor->replaceText(childGetText("search_text"), childGetText("replace_text"), caseChk->get());
+}
+
+// static
+void LLFloaterScriptSearch::onBtnReplaceAll(void *userdata)
+{
+ LLFloaterScriptSearch* self = (LLFloaterScriptSearch*)userdata;
+ self->handleBtnReplaceAll();
+}
+
+void LLFloaterScriptSearch::handleBtnReplaceAll()
+{
+ LLCheckBoxCtrl* caseChk = LLUICtrlFactory::getCheckBoxByName(this,"case_text");
+ mEditorCore->mEditor->replaceTextAll(childGetText("search_text"), childGetText("replace_text"), caseChk->get());
+}
+
+void LLFloaterScriptSearch::open()
+{
+ LLFloater::open();
+ childSetFocus("search_text", TRUE);
+}
+/// ---------------------------------------------------------------------------
+/// LLScriptEdCore
+/// ---------------------------------------------------------------------------
+
+LLScriptEdCore::LLScriptEdCore(
+ const std::string& name,
+ const LLRect& rect,
+ const std::string& sample,
+ const std::string& help,
+ const LLViewHandle& floater_handle,
+ void (*load_callback)(void*),
+ void (*save_callback)(void*, BOOL),
+ void* userdata,
+ S32 bottom_pad)
+ :
+ LLPanel( "name", rect ),
+ mSampleText(sample),
+ mHelpFile ( help ),
+ mEditor( NULL ),
+ mLoadCallback( load_callback ),
+ mSaveCallback( save_callback ),
+ mUserdata( userdata ),
+ mForceClose( FALSE )
+{
+ setFollowsAll();
+ setBorderVisible(FALSE);
+
+
+ gUICtrlFactory->buildPanel(this, "floater_script_ed_panel.xml");
+
+ mErrorList = LLUICtrlFactory::getScrollListByName(this, "lsl errors");
+
+ mFunctions = LLUICtrlFactory::getComboBoxByName(this, "Insert...");
+
+ childSetCommitCallback("Insert...", &LLScriptEdCore::onBtnInsertFunction, this);
+ mFunctions->setLabel("Insert...");
+
+ mEditor = LLViewerUICtrlFactory::getViewerTextEditorByName(this, "Script Editor");
+ mEditor->setReadOnlyBgColor(gColors.getColor( "ScriptBgReadOnlyColor" ) );
+ mEditor->setFollowsAll();
+ mEditor->setHandleEditKeysDirectly(TRUE);
+ mEditor->setEnabled(TRUE);
+ mEditor->setWordWrap(TRUE);
+
+ LLDynamicArray<const char*> funcs;
+ LLDynamicArray<const char*> tooltips;
+ for (S32 i = 0; i < gScriptLibrary.mNextNumber; i++)
+ {
+ // Make sure this isn't a god only function, or the agent is a god.
+ if (!gScriptLibrary.mFunctions[i]->mGodOnly || gAgent.isGodlike())
+ {
+ funcs.put(gScriptLibrary.mFunctions[i]->mName);
+ tooltips.put(gScriptLibrary.mFunctions[i]->mDesc);
+ }
+ }
+ LLColor3 color(0.5f, 0.0f, 0.15f);
+
+ mEditor->loadKeywords(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"keywords.ini"), funcs, tooltips, color);
+
+
+ LLKeywordToken *token;
+ LLKeywords::word_token_map_t::iterator token_it;
+ for (token_it = mEditor->mKeywords.mWordTokenMap.begin(); token_it != mEditor->mKeywords.mWordTokenMap.end(); ++token_it)
+ {
+ token = token_it->second;
+ if (token->mColor == color)
+ mFunctions->add(wstring_to_utf8str(token->mToken));
+ }
+
+ for (token_it = mEditor->mKeywords.mWordTokenMap.begin(); token_it != mEditor->mKeywords.mWordTokenMap.end(); ++token_it)
+ {
+ token = token_it->second;
+ if (token->mColor != color)
+ mFunctions->add(wstring_to_utf8str(token->mToken));
+ }
+
+
+ childSetCommitCallback("lsl errors", &LLScriptEdCore::onErrorList, this);
+ childSetAction("Save_btn", onBtnSave,this);
+
+ initMenu();
+
+
+ // Do the work that addTabPanel() normally does.
+ //LLRect tab_panel_rect( 0, mRect.getHeight(), mRect.getWidth(), 0 );
+ //tab_panel_rect.stretch( -LLPANEL_BORDER_WIDTH );
+ //mCodePanel->setFollowsAll();
+ //mCodePanel->translate( tab_panel_rect.mLeft - mCodePanel->getRect().mLeft, tab_panel_rect.mBottom - mCodePanel->getRect().mBottom);
+ //mCodePanel->reshape( tab_panel_rect.getWidth(), tab_panel_rect.getHeight(), TRUE );
+
+}
+
+LLScriptEdCore::~LLScriptEdCore()
+{
+ deleteBridges();
+
+ // If the search window is up for this editor, close it.
+ LLFloaterScriptSearch* script_search = LLFloaterScriptSearch::getInstance();
+ if (script_search && script_search->getEditorCore() == this)
+ {
+ script_search->close();
+ delete script_search;
+ }
+}
+
+void LLScriptEdCore::initMenu()
+{
+
+ LLMenuItemCallGL* menuItem = LLUICtrlFactory::getMenuItemCallByName(this, "Save");
+ menuItem->setMenuCallback(onBtnSave, this);
+ menuItem->setEnabledCallback(hasChanged);
+
+ menuItem = LLUICtrlFactory::getMenuItemCallByName(this, "Revert All Changes");
+ menuItem->setMenuCallback(onBtnUndoChanges, this);
+ menuItem->setEnabledCallback(hasChanged);
+
+ menuItem = LLUICtrlFactory::getMenuItemCallByName(this, "Undo");
+ menuItem->setMenuCallback(onUndoMenu, this);
+ menuItem->setEnabledCallback(enableUndoMenu);
+
+ menuItem = LLUICtrlFactory::getMenuItemCallByName(this, "Redo");
+ menuItem->setMenuCallback(onRedoMenu, this);
+ menuItem->setEnabledCallback(enableRedoMenu);
+
+ menuItem = LLUICtrlFactory::getMenuItemCallByName(this, "Cut");
+ menuItem->setMenuCallback(onCutMenu, this);
+ menuItem->setEnabledCallback(enableCutMenu);
+
+ menuItem = LLUICtrlFactory::getMenuItemCallByName(this, "Copy");
+ menuItem->setMenuCallback(onCopyMenu, this);
+ menuItem->setEnabledCallback(enableCopyMenu);
+
+ menuItem = LLUICtrlFactory::getMenuItemCallByName(this, "Paste");
+ menuItem->setMenuCallback(onPasteMenu, this);
+ menuItem->setEnabledCallback(enablePasteMenu);
+
+ menuItem = LLUICtrlFactory::getMenuItemCallByName(this, "Select All");
+ menuItem->setMenuCallback(onSelectAllMenu, this);
+ menuItem->setEnabledCallback(enableSelectAllMenu);
+
+ menuItem = LLUICtrlFactory::getMenuItemCallByName(this, "Search / Replace...");
+ menuItem->setMenuCallback(onSearchMenu, this);
+ menuItem->setEnabledCallback(NULL);
+
+ menuItem = LLUICtrlFactory::getMenuItemCallByName(this, "Help...");
+ menuItem->setMenuCallback(onBtnHelp, this);
+ menuItem->setEnabledCallback(NULL);
+
+}
+
+BOOL LLScriptEdCore::hasChanged(void* userdata)
+{
+ LLScriptEdCore* self = (LLScriptEdCore*)userdata;
+ if (!self || !self->mEditor) return FALSE;
+
+ return !self->mEditor->isPristine();
+}
+
+void LLScriptEdCore::draw()
+{
+ BOOL script_changed = !mEditor->isPristine();
+ childSetEnabled("Save_btn", script_changed);
+
+ if( mEditor->hasFocus() )
+ {
+ S32 line = 0;
+ S32 column = 0;
+ mEditor->getCurrentLineAndColumn( &line, &column, FALSE ); // don't include wordwrap
+ char cursor_pos[STD_STRING_BUF_SIZE];
+ sprintf( cursor_pos, "Line %d, Column %d", line, column );
+ childSetText("line_col", cursor_pos);
+ }
+ else
+ {
+ childSetText("line_col", "");
+ }
+
+ LLPanel::draw();
+}
+
+BOOL LLScriptEdCore::canClose()
+{
+ if(mForceClose || mEditor->isPristine())
+ {
+ return TRUE;
+ }
+ else
+ {
+ // Bring up view-modal dialog: Save changes? Yes, No, Cancel
+ gViewerWindow->alertXml("SaveChanges", LLScriptEdCore::handleSaveChangesDialog, this);
+ return FALSE;
+ }
+}
+
+// static
+void LLScriptEdCore::handleSaveChangesDialog( S32 option, void* userdata )
+{
+ LLScriptEdCore* self = (LLScriptEdCore*) userdata;
+ switch( option )
+ {
+ case 0: // "Yes"
+ // close after saving
+ LLScriptEdCore::doSave( self, TRUE );
+ break;
+
+ case 1: // "No"
+ self->mForceClose = TRUE;
+ // This will close immediately because mForceClose is true, so we won't
+ // infinite loop with these dialogs. JC
+ ((LLFloater*) self->getParent())->close();
+ break;
+
+ case 2: // "Cancel"
+ default:
+ // If we were quitting, we didn't really mean it.
+ app_abort_quit();
+ break;
+ }
+}
+
+// static
+void LLScriptEdCore::onHelpWebDialog(S32 option, void* userdata)
+{
+ LLScriptEdCore* corep = (LLScriptEdCore*)userdata;
+
+ switch(option)
+ {
+ case 0:
+ load_url_local_file(corep->mHelpFile.c_str());
+ break;
+ default:
+ break;
+ }
+}
+
+// static
+void LLScriptEdCore::onBtnHelp(void* userdata)
+{
+ gViewerWindow->alertXml("WebLaunchLSLGuide",
+ onHelpWebDialog,
+ userdata);
+}
+
+// static
+void LLScriptEdCore::onBtnInsertSample(void* userdata)
+{
+ LLScriptEdCore* self = (LLScriptEdCore*) userdata;
+
+ // Insert sample code
+ self->mEditor->selectAll();
+ self->mEditor->cut();
+ self->mEditor->insertText(self->mSampleText);
+}
+
+// static
+void LLScriptEdCore::onBtnInsertFunction(LLUICtrl *ui, void* userdata)
+{
+ LLScriptEdCore* self = (LLScriptEdCore*) userdata;
+
+ // Insert sample code
+ if(self->mEditor->getEnabled())
+ {
+ self->mEditor->insertText(self->mFunctions->getSimple());
+ }
+ self->mEditor->setFocus(TRUE);
+}
+
+// static
+void LLScriptEdCore::doSave( void* userdata, BOOL close_after_save )
+{
+ if( gViewerStats )
+ {
+ gViewerStats->incStat( LLViewerStats::ST_LSL_SAVE_COUNT );
+ }
+
+ LLScriptEdCore* self = (LLScriptEdCore*) userdata;
+
+ if( self->mSaveCallback )
+ {
+ self->mSaveCallback( self->mUserdata, close_after_save );
+ }
+}
+
+// static
+void LLScriptEdCore::onBtnSave(void* data)
+{
+ // do the save, but don't close afterwards
+ doSave(data, FALSE);
+}
+
+// static
+void LLScriptEdCore::onBtnUndoChanges( void* userdata )
+{
+ LLScriptEdCore* self = (LLScriptEdCore*) userdata;
+ if( !self->mEditor->tryToRevertToPristineState() )
+ {
+ gViewerWindow->alertXml("ScriptCannotUndo",
+ LLScriptEdCore::handleReloadFromServerDialog, self);
+ }
+}
+
+void LLScriptEdCore::onSearchMenu(void* userdata)
+{
+ LLScriptEdCore* sec = (LLScriptEdCore*)userdata;
+ LLFloaterScriptSearch::show(sec);
+}
+
+// static
+void LLScriptEdCore::onUndoMenu(void* userdata)
+{
+ LLScriptEdCore* self = (LLScriptEdCore*)userdata;
+ if (!self || !self->mEditor) return;
+ self->mEditor->undo();
+}
+
+// static
+void LLScriptEdCore::onRedoMenu(void* userdata)
+{
+ LLScriptEdCore* self = (LLScriptEdCore*)userdata;
+ if (!self || !self->mEditor) return;
+ self->mEditor->redo();
+}
+
+// static
+void LLScriptEdCore::onCutMenu(void* userdata)
+{
+ LLScriptEdCore* self = (LLScriptEdCore*)userdata;
+ if (!self || !self->mEditor) return;
+ self->mEditor->cut();
+}
+
+// static
+void LLScriptEdCore::onCopyMenu(void* userdata)
+{
+ LLScriptEdCore* self = (LLScriptEdCore*)userdata;
+ if (!self || !self->mEditor) return;
+ self->mEditor->copy();
+}
+
+// static
+void LLScriptEdCore::onPasteMenu(void* userdata)
+{
+ LLScriptEdCore* self = (LLScriptEdCore*)userdata;
+ if (!self || !self->mEditor) return;
+ self->mEditor->paste();
+}
+
+// static
+void LLScriptEdCore::onSelectAllMenu(void* userdata)
+{
+ LLScriptEdCore* self = (LLScriptEdCore*)userdata;
+ if (!self || !self->mEditor) return;
+ self->mEditor->selectAll();
+}
+
+// static
+void LLScriptEdCore::onDeselectMenu(void* userdata)
+{
+ LLScriptEdCore* self = (LLScriptEdCore*)userdata;
+ if (!self || !self->mEditor) return;
+ self->mEditor->deselect();
+}
+
+// static
+BOOL LLScriptEdCore::enableUndoMenu(void* userdata)
+{
+ LLScriptEdCore* self = (LLScriptEdCore*)userdata;
+ if (!self || !self->mEditor) return FALSE;
+ return self->mEditor->canUndo();
+}
+
+// static
+BOOL LLScriptEdCore::enableRedoMenu(void* userdata)
+{
+ LLScriptEdCore* self = (LLScriptEdCore*)userdata;
+ if (!self || !self->mEditor) return FALSE;
+ return self->mEditor->canRedo();
+}
+
+// static
+BOOL LLScriptEdCore::enableCutMenu(void* userdata)
+{
+ LLScriptEdCore* self = (LLScriptEdCore*)userdata;
+ if (!self || !self->mEditor) return FALSE;
+ return self->mEditor->canCut();
+}
+
+// static
+BOOL LLScriptEdCore::enableCopyMenu(void* userdata)
+{
+ LLScriptEdCore* self = (LLScriptEdCore*)userdata;
+ if (!self || !self->mEditor) return FALSE;
+ return self->mEditor->canCopy();
+}
+
+// static
+BOOL LLScriptEdCore::enablePasteMenu(void* userdata)
+{
+ LLScriptEdCore* self = (LLScriptEdCore*)userdata;
+ if (!self || !self->mEditor) return FALSE;
+ return self->mEditor->canPaste();
+}
+
+// static
+BOOL LLScriptEdCore::enableSelectAllMenu(void* userdata)
+{
+ LLScriptEdCore* self = (LLScriptEdCore*)userdata;
+ if (!self || !self->mEditor) return FALSE;
+ return self->mEditor->canSelectAll();
+}
+
+// static
+BOOL LLScriptEdCore::enableDeselectMenu(void* userdata)
+{
+ LLScriptEdCore* self = (LLScriptEdCore*)userdata;
+ if (!self || !self->mEditor) return FALSE;
+ return self->mEditor->canDeselect();
+}
+
+// static
+void LLScriptEdCore::onErrorList(LLUICtrl*, void* user_data)
+{
+ LLScriptEdCore* self = (LLScriptEdCore*)user_data;
+ LLScrollListItem* item = self->mErrorList->getFirstSelected();
+ if(item)
+ {
+ // *FIX: This fucked up little hack is here because we don't
+ // have a grep library. This is very brittle code.
+ S32 row = 0;
+ S32 column = 0;
+ const LLScrollListCell* cell = item->getColumn(0);
+ LLString line(cell->getText());
+ line.erase(0, 1);
+ LLString::replaceChar(line, ',',' ');
+ LLString::replaceChar(line, ')',' ');
+ sscanf(line.c_str(), "%d %d", &row, &column);
+ //llinfos << "LLScriptEdCore::onErrorList() - " << row << ", "
+ //<< column << llendl;
+ self->mEditor->setCursor(row, column);
+ self->mEditor->setFocus(TRUE);
+ }
+}
+
+// static
+void LLScriptEdCore::handleReloadFromServerDialog( S32 option, void* userdata )
+{
+ LLScriptEdCore* self = (LLScriptEdCore*) userdata;
+ switch( option )
+ {
+ case 0: // "Yes"
+ if( self->mLoadCallback )
+ {
+ self->mEditor->setText( "Loading..." );
+ self->mLoadCallback( self->mUserdata );
+ }
+ break;
+
+ case 1: // "No"
+ break;
+
+ default:
+ llassert(0);
+ break;
+ }
+}
+
+void LLScriptEdCore::selectFirstError()
+{
+ // Select the first item;
+ mErrorList->selectFirstItem();
+ onErrorList(mErrorList, this);
+}
+
+
+struct LLEntryAndEdCore
+{
+ LLScriptEdCore* mCore;
+ LLEntryAndEdCore(LLScriptEdCore* core) :
+ mCore(core)
+ {}
+};
+
+void LLScriptEdCore::deleteBridges()
+{
+ S32 count = mBridges.count();
+ LLEntryAndEdCore* eandc;
+ for(S32 i = 0; i < count; i++)
+ {
+ eandc = mBridges.get(i);
+ delete eandc;
+ mBridges[i] = NULL;
+ }
+ mBridges.reset();
+}
+
+// virtual
+BOOL LLScriptEdCore::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
+{
+ if(getVisible() && getEnabled())
+ {
+ if(('S' == key) && (MASK_CONTROL == (mask & MASK_CONTROL)))
+ {
+ if(mSaveCallback)
+ {
+ // don't close after saving
+ mSaveCallback(mUserdata, FALSE);
+ }
+
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/// ---------------------------------------------------------------------------
+/// LLPreviewLSL
+/// ---------------------------------------------------------------------------
+
+struct LLScriptSaveInfo
+{
+ LLUUID mItemUUID;
+ LLString mDescription;
+ LLTransactionID mTransactionID;
+
+ LLScriptSaveInfo(const LLUUID& uuid, const LLString& desc, LLTransactionID tid) :
+ mItemUUID(uuid), mDescription(desc), mTransactionID(tid) {}
+};
+
+
+
+//static
+void* LLPreviewLSL::createScriptEdPanel(void* userdata)
+{
+
+ LLPreviewLSL *self = (LLPreviewLSL*)userdata;
+
+ self->mScriptEd = new LLScriptEdCore("script panel",
+ LLRect(),
+ HELLO_LSL,
+ HELP_LSL,
+ self->mViewHandle,
+ LLPreviewLSL::onLoad,
+ LLPreviewLSL::onSave,
+ self,
+ 0);
+
+ return self->mScriptEd;
+}
+
+
+LLPreviewLSL::LLPreviewLSL(const std::string& name, const LLRect& rect,
+ const std::string& title, const LLUUID& item_id )
+: LLPreview( name, rect, title, item_id, LLUUID::null, TRUE,
+ SCRIPT_MIN_WIDTH, SCRIPT_MIN_HEIGHT ),
+ mPendingUploads(0)
+{
+
+ LLRect curRect = rect;
+
+
+ LLCallbackMap::map_t factory_map;
+ factory_map["script panel"] = LLCallbackMap(LLPreviewLSL::createScriptEdPanel, this);
+
+
+ gUICtrlFactory->buildFloater(this,"floater_script_preview.xml", &factory_map);
+
+ moveResizeHandleToFront();
+
+
+ LLInventoryItem* item = getItem();
+
+ childSetCommitCallback("desc", LLPreview::onText, this);
+ childSetText("desc", item->getDescription());
+ childSetPrevalidate("desc", &LLLineEditor::prevalidatePrintableNotPipe);
+
+ LLMultiFloater* hostp = getHost();
+
+ if (!sHostp && !hostp && getAssetStatus() == PREVIEW_ASSET_UNLOADED)
+ {
+ loadAsset();
+ }
+
+ setTitle(title);
+
+ if (!getHost())
+ {
+ reshape(curRect.getWidth(), curRect.getHeight(), TRUE);
+ setRect(curRect);
+ }
+}
+
+
+void LLPreviewLSL::loadAsset()
+{
+ // *HACK: we poke into inventory to see if it's there, and if so,
+ // then it might be part of the inventory library. If it's in the
+ // library, then you can see the script, but not modify it.
+ LLInventoryItem* item = gInventory.getItem(mItemUUID);
+ BOOL is_library = item
+ && !gInventory.isObjectDescendentOf(mItemUUID,
+ gAgent.getInventoryRootID());
+ if(!item)
+ {
+ // do the more generic search.
+ getItem();
+ }
+ if(item && !(item->getAssetUUID().isNull()))
+ {
+ BOOL is_copyable = gAgent.allowOperation(PERM_COPY,
+ item->getPermissions(), GP_OBJECT_MANIPULATE);
+ BOOL is_modifiable = gAgent.allowOperation(PERM_MODIFY,
+ item->getPermissions(), GP_OBJECT_MANIPULATE);
+ if (gAgent.isGodlike() || (is_copyable && (is_modifiable || is_library)))
+ {
+ LLUUID* new_uuid = new LLUUID(mItemUUID);
+ gAssetStorage->getInvItemAsset(LLHost::invalid,
+ gAgent.getID(),
+ gAgent.getSessionID(),
+ item->getPermissions().getOwner(),
+ LLUUID::null,
+ item->getUUID(),
+ item->getAssetUUID(),
+ item->getType(),
+ &LLPreviewLSL::onLoadComplete,
+ (void*)new_uuid,
+ TRUE);
+ mAssetStatus = PREVIEW_ASSET_LOADING;
+ }
+ else
+ {
+ mScriptEd->mEditor->setText("You are not allowed to view this script.");
+ mScriptEd->mEditor->makePristine();
+ mScriptEd->mEditor->setEnabled(FALSE);
+ mScriptEd->mFunctions->setEnabled(FALSE);
+ mAssetStatus = PREVIEW_ASSET_LOADED;
+ }
+ childSetVisible("lock", !is_modifiable);
+ mScriptEd->childSetEnabled("Insert...", is_modifiable);
+ }
+ else
+ {
+ mScriptEd->mEditor->setText(HELLO_LSL);
+ mAssetStatus = PREVIEW_ASSET_LOADED;
+ }
+}
+
+
+BOOL LLPreviewLSL::canClose()
+{
+ return mScriptEd->canClose();
+}
+
+//override the llpreview open which attempts to load asset, load after xml ui made
+void LLPreviewLSL::open()
+{
+ LLFloater::open();
+}
+
+// static
+void LLPreviewLSL::onLoad(void* userdata)
+{
+ LLPreviewLSL* self = (LLPreviewLSL*)userdata;
+ self->loadAsset();
+}
+
+// static
+void LLPreviewLSL::onSave(void* userdata, BOOL close_after_save)
+{
+ LLPreviewLSL* self = (LLPreviewLSL*)userdata;
+ self->mCloseAfterSave = close_after_save;
+ self->saveIfNeeded();
+}
+
+
+// Save needs to compile the text in the buffer. If the compile
+// succeeds, then save both assets out to the database. If the compile
+// fails, go ahead and save the text anyway so that the user doesn't
+// get too fucked.
+void LLPreviewLSL::saveIfNeeded()
+{
+ // llinfos << "LLPreviewLSL::save()" << llendl;
+ if(!mScriptEd->mEditor->isPristine())
+ {
+ mPendingUploads = 0;
+ mScriptEd->mErrorList->deleteAllItems();
+ mScriptEd->mEditor->makePristine();
+
+ // We need to update the asset information
+ LLTransactionID tid;
+ LLAssetID uuid;
+ tid.generate();
+ uuid = tid.makeAssetID(gAgent.getSecureSessionID());
+ char uuid_string[UUID_STR_LENGTH];
+ uuid.toString(uuid_string);
+ char filename[LL_MAX_PATH];
+ sprintf(filename, "%s.lsl", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string).c_str());
+ FILE* fp = LLFile::fopen(filename, "wb");
+ if(!fp)
+ {
+ llwarns << "Unable to write to " << filename << llendl;
+ LLScrollListItem* item = new LLScrollListItem();
+ item->addColumn("Error writing to local file. Is your hard drive full?", LLFontGL::sSansSerifSmall);
+ mScriptEd->mErrorList->addItem(item);
+ return;
+ }
+
+ LLString utf8text = mScriptEd->mEditor->getText();
+ //fprintf(fp, "%s|%s\n", LLAssetType::lookup(LLAssetType::AT_LSL_TEXT),
+ //uuid_string);
+ //fprintf(fp,"{\n%s}\n", text.c_str());
+ fputs(utf8text.c_str(), fp);
+ fclose(fp);
+ fp = NULL;
+
+ // also write it out to the vfs for upload
+ LLVFile file(gVFS, uuid, LLAssetType::AT_LSL_TEXT, LLVFile::APPEND);
+ S32 size = utf8text.length() + 1;
+
+ file.setMaxSize(size);
+ file.write((U8*)utf8text.c_str(), size);
+
+ LLInventoryItem *inv_item = getItem();
+
+ // save it out to database
+ if(gAssetStorage && inv_item)
+ {
+ getWindow()->incBusyCount();
+ mPendingUploads++;
+ LLScriptSaveInfo* info = NULL;
+
+ LLLineEditor* descEditor = LLUICtrlFactory::getLineEditorByName(this, "desc");
+
+ info = new LLScriptSaveInfo(mItemUUID,
+ descEditor->getText(),
+ tid);
+ gAssetStorage->storeAssetData(tid, LLAssetType::AT_LSL_TEXT, &LLPreviewLSL::onSaveComplete, info);
+ }
+
+ char dst_filename[LL_MAX_PATH];
+ sprintf(dst_filename, "%s.lso", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string).c_str());
+ char err_filename[LL_MAX_PATH];
+ sprintf(err_filename, "%s.out", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string).c_str());
+ LLScrollListItem* item = NULL;
+ const LLFontGL* err_font = gResMgr->getRes(LLFONT_OCRA);
+ if(!lscript_compile(filename, dst_filename, err_filename, gAgent.isGodlike()))
+ {
+ llinfos << "Compile failed!" << llendl;
+ //char command[256];
+ //sprintf(command, "type %s\n", err_filename);
+ //system(command);
+
+ // load the error file into the error scrolllist
+ if(NULL != (fp = LLFile::fopen(err_filename, "r")))
+ {
+ char buffer[MAX_STRING];
+ LLString line;
+ while(!feof(fp))
+ {
+
+ fgets(buffer, MAX_STRING, fp);
+ if(feof(fp))
+ {
+ break;
+ }
+ else if(!buffer)
+ {
+ continue;
+ }
+ else
+ {
+ line.assign(buffer);
+ LLString::stripNonprintable(line);
+ item = new LLScrollListItem();
+ item->addColumn(line, err_font);
+ mScriptEd->mErrorList->addItem(item);
+ }
+ }
+ fclose(fp);
+ mScriptEd->selectFirstError();
+ }
+ }
+ else
+ {
+ llinfos << "Compile worked!" << llendl;
+ if(gAssetStorage)
+ {
+ // move the compiled file into the vfs for transport
+ FILE* fp = LLFile::fopen(dst_filename, "rb");
+ LLVFile file(gVFS, uuid, LLAssetType::AT_LSL_BYTECODE, LLVFile::APPEND);
+
+ fseek(fp, 0, SEEK_END);
+ S32 size = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ file.setMaxSize(size);
+
+ const S32 buf_size = 65536;
+ U8 copy_buf[buf_size];
+ while ((size = fread(copy_buf, 1, buf_size, fp)))
+ {
+ file.write(copy_buf, size);
+ }
+ fclose(fp);
+ fp = NULL;
+ getWindow()->incBusyCount();
+ mPendingUploads++;
+ LLUUID* this_uuid = new LLUUID(mItemUUID);
+ gAssetStorage->storeAssetData(tid,
+ LLAssetType::AT_LSL_BYTECODE,
+ &LLPreviewLSL::onSaveBytecodeComplete,
+ (void**)this_uuid);
+ }
+ }
+
+ // get rid of any temp files left lying around
+ LLFile::remove(filename);
+ LLFile::remove(err_filename);
+ LLFile::remove(dst_filename);
+ }
+}
+
+
+// static
+void LLPreviewLSL::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status) // StoreAssetData callback (fixed)
+{
+ LLScriptSaveInfo* info = reinterpret_cast<LLScriptSaveInfo*>(user_data);
+ if(0 == status)
+ {
+ if (info)
+ {
+ LLViewerInventoryItem* item;
+ item = (LLViewerInventoryItem*)gInventory.getItem(info->mItemUUID);
+ if(item)
+ {
+ LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
+ new_item->setAssetUUID(asset_uuid);
+ new_item->setTransactionID(info->mTransactionID);
+ new_item->updateServer(FALSE);
+ gInventory.updateItem(new_item);
+ gInventory.notifyObservers();
+ }
+ else
+ {
+ llwarns << "Inventory item for script " << info->mItemUUID
+ << " is no longer in agent inventory." << llendl
+ }
+
+ // Find our window and close it if requested.
+ LLPreviewLSL* self = (LLPreviewLSL*)LLPreview::find(info->mItemUUID);
+ if (self)
+ {
+ getWindow()->decBusyCount();
+ self->mPendingUploads--;
+ if (self->mPendingUploads <= 0
+ && self->mCloseAfterSave)
+ {
+ self->close();
+ }
+ }
+ }
+ }
+ else
+ {
+ llwarns << "Problem saving script: " << status << llendl;
+ LLStringBase<char>::format_map_t args;
+ args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status));
+ gViewerWindow->alertXml("SaveScriptFailReason", args);
+ }
+ delete info;
+}
+
+// static
+void LLPreviewLSL::onSaveBytecodeComplete(const LLUUID& asset_uuid, void* user_data, S32 status) // StoreAssetData callback (fixed)
+{
+ LLUUID* instance_uuid = (LLUUID*)user_data;
+ LLPreviewLSL* self = NULL;
+ if(instance_uuid)
+ {
+ self = LLPreviewLSL::getInstance(*instance_uuid);
+ }
+ if (0 == status)
+ {
+ if (self)
+ {
+ LLScrollListItem* item = new LLScrollListItem();
+ item->addColumn("Compile successful!", LLFontGL::sSansSerifSmall);
+ self->mScriptEd->mErrorList->addItem(item);
+
+ // Find our window and close it if requested.
+ self->getWindow()->decBusyCount();
+ self->mPendingUploads--;
+ if (self->mPendingUploads <= 0
+ && self->mCloseAfterSave)
+ {
+ self->close();
+ }
+ }
+ }
+ else
+ {
+ llwarns << "Problem saving LSL Bytecode (Preview)" << llendl;
+ LLStringBase<char>::format_map_t args;
+ args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status));
+ gViewerWindow->alertXml("SaveBytecodeFailReason", args);
+ }
+ delete instance_uuid;
+}
+
+// static
+void LLPreviewLSL::onLoadComplete( LLVFS *vfs, const LLUUID& asset_uuid, LLAssetType::EType type,
+ void* user_data, S32 status)
+{
+ LLUUID* item_uuid = (LLUUID*)user_data;
+ LLPreviewLSL* preview = LLPreviewLSL::getInstance(*item_uuid);
+ if( preview )
+ {
+ if(0 == status)
+ {
+ LLVFile file(vfs, asset_uuid, type);
+ S32 file_length = file.getSize();
+
+ char* buffer = new char[file_length+1];
+ file.read((U8*)buffer, file_length);
+
+ // put a EOS at the end
+ buffer[file_length] = 0;
+ preview->mScriptEd->mEditor->setText(buffer);
+ preview->mScriptEd->mEditor->makePristine();
+ delete [] buffer;
+ LLInventoryItem* item = gInventory.getItem(*item_uuid);
+ BOOL is_modifiable = FALSE;
+ if(item
+ && gAgent.allowOperation(PERM_MODIFY, item->getPermissions(),
+ GP_OBJECT_MANIPULATE))
+ {
+ is_modifiable = TRUE;
+ }
+ preview->mScriptEd->mEditor->setEnabled(is_modifiable);
+ preview->mAssetStatus = PREVIEW_ASSET_LOADED;
+ }
+ else
+ {
+ if( gViewerStats )
+ {
+ gViewerStats->incStat( LLViewerStats::ST_DOWNLOAD_FAILED );
+ }
+
+ if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
+ LL_ERR_FILE_EMPTY == status)
+ {
+ LLNotifyBox::showXml("ScriptMissing");
+ }
+ else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status)
+ {
+ LLNotifyBox::showXml("ScriptNoPermissions");
+ }
+ else
+ {
+ LLNotifyBox::showXml("UnableToLoadScript");
+ }
+
+ preview->mAssetStatus = PREVIEW_ASSET_ERROR;
+ llwarns << "Problem loading script: " << status << llendl;
+ }
+ }
+ delete item_uuid;
+}
+
+// static
+LLPreviewLSL* LLPreviewLSL::getInstance( const LLUUID& item_uuid )
+{
+ LLPreview* instance = NULL;
+ preview_map_t::iterator found_it = LLPreview::sInstances.find(item_uuid);
+ if(found_it != LLPreview::sInstances.end())
+ {
+ instance = found_it->second;
+ }
+ return (LLPreviewLSL*)instance;
+}
+
+void LLPreviewLSL::reshape(S32 width, S32 height, BOOL called_from_parent)
+{
+ LLPreview::reshape( width, height, called_from_parent );
+
+ if( !isMinimized() )
+ {
+ // So that next time you open a script it will have the same height and width
+ // (although not the same position).
+ gSavedSettings.setRect("PreviewScriptRect", mRect);
+ }
+}
+
+/// ---------------------------------------------------------------------------
+/// LLLiveLSLEditor
+/// ---------------------------------------------------------------------------
+
+LLMap<LLUUID, LLLiveLSLEditor*> LLLiveLSLEditor::sInstances;
+
+
+
+//static
+void* LLLiveLSLEditor::createScriptEdPanel(void* userdata)
+{
+
+ LLLiveLSLEditor *self = (LLLiveLSLEditor*)userdata;
+
+ self->mScriptEd = new LLScriptEdCore("script ed panel",
+ LLRect(),
+ HELLO_LSL,
+ HELP_LSL,
+ self->mViewHandle,
+ &LLLiveLSLEditor::onLoad,
+ &LLLiveLSLEditor::onSave,
+ self,
+ 0);
+
+ return self->mScriptEd;
+}
+
+
+LLLiveLSLEditor::LLLiveLSLEditor(const std::string& name,
+ const LLRect& rect,
+ const std::string& title,
+ const LLUUID& object_id,
+ const LLUUID& item_id) :
+ LLFloater(name, rect, title, TRUE, SCRIPT_MIN_WIDTH, SCRIPT_MIN_HEIGHT),
+ mObjectID(object_id),
+ mItemID(item_id),
+ mScriptEd(NULL),
+ mAskedForRunningInfo(FALSE),
+ mHaveRunningInfo(FALSE),
+ mCloseAfterSave(FALSE),
+ mPendingUploads(0)
+{
+
+
+ BOOL is_new = FALSE;
+ if(mItemID.isNull())
+ {
+ mItemID.generate();
+ is_new = TRUE;
+ }
+
+
+ LLLiveLSLEditor::sInstances.addData(mItemID ^ mObjectID, this);
+
+
+
+ LLCallbackMap::map_t factory_map;
+ factory_map["script ed panel"] = LLCallbackMap(LLLiveLSLEditor::createScriptEdPanel, this);
+
+ moveResizeHandleToFront();
+
+ gUICtrlFactory->buildFloater(this,"floater_live_lsleditor.xml", &factory_map);
+
+
+ childSetCommitCallback("running", LLLiveLSLEditor::onRunningCheckboxClicked, this);
+ childSetEnabled("running", FALSE);
+
+ childSetAction("Reset",&LLLiveLSLEditor::onReset,this);
+ childSetEnabled("Reset", TRUE);
+
+
+ mScriptEd->mEditor->makePristine();
+ loadAsset(is_new);
+ mScriptEd->mEditor->setFocus(TRUE);
+
+
+ if (!getHost())
+ {
+ LLRect curRect = getRect();
+ translate(rect.mLeft - curRect.mLeft, rect.mTop - curRect.mTop);
+ }
+
+
+ setTitle(title);
+
+}
+
+LLLiveLSLEditor::~LLLiveLSLEditor()
+{
+ LLLiveLSLEditor::sInstances.removeData(mItemID ^ mObjectID);
+}
+
+
+void LLLiveLSLEditor::loadAsset(BOOL is_new)
+{
+ //llinfos << "LLLiveLSLEditor::loadAsset()" << llendl;
+ if(!is_new)
+ {
+ LLViewerObject* object = gObjectList.findObject(mObjectID);
+ if(object)
+ {
+ // HACK! we "know" that mItemID refers to a LLViewerInventoryItem...
+ LLViewerInventoryItem* item = (LLViewerInventoryItem*)object->getInventoryObject(mItemID);
+ if(item
+ && (gAgent.allowOperation(PERM_COPY, item->getPermissions(),
+ GP_OBJECT_MANIPULATE)
+ || gAgent.isGodlike()))
+ {
+ mItem = new LLViewerInventoryItem(item);
+ //llinfos << "asset id " << mItem->getAssetUUID() << llendl;
+ }
+
+ if(!gAgent.isGodlike()
+ && (item
+ && (!gAgent.allowOperation(PERM_COPY, item->getPermissions(),
+ GP_OBJECT_MANIPULATE)
+ || !gAgent.allowOperation(PERM_MODIFY,
+ item->getPermissions(), GP_OBJECT_MANIPULATE))))
+
+ {
+ mScriptEd->mEditor->setText("You are not allowed to view this script.");
+ mScriptEd->mEditor->makePristine();
+ mScriptEd->mEditor->setEnabled(FALSE);
+ }
+ else if(mItem.notNull() && mItem->getAssetUUID().notNull())
+ {
+ // request the text from the object
+ LLUUID* user_data = new LLUUID(mItemID ^ mObjectID);
+ gAssetStorage->getInvItemAsset(object->getRegion()->getHost(),
+ gAgent.getID(),
+ gAgent.getSessionID(),
+ item->getPermissions().getOwner(),
+ object->getID(),
+ item->getUUID(),
+ item->getAssetUUID(),
+ item->getType(),
+ &LLLiveLSLEditor::onLoadComplete,
+ (void*)user_data,
+ TRUE);
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_GetScriptRunning);
+ msg->nextBlockFast(_PREHASH_Script);
+ msg->addUUIDFast(_PREHASH_ObjectID, mObjectID);
+ msg->addUUIDFast(_PREHASH_ItemID, mItemID);
+ msg->sendReliable(object->getRegion()->getHost());
+ mAskedForRunningInfo = TRUE;
+ }
+ else
+ {
+ mScriptEd->mEditor->setText("");
+ mScriptEd->mEditor->makePristine();
+ }
+
+ if(item
+ && !gAgent.allowOperation(PERM_MODIFY, item->getPermissions(),
+ GP_OBJECT_MANIPULATE))
+ {
+ mScriptEd->mEditor->setEnabled(FALSE);
+ }
+ // This is commented out, because we don't completely
+ // handle script exports yet.
+ /*
+ // request the exports from the object
+ gMessageSystem->newMessage("GetScriptExports");
+ gMessageSystem->nextBlock("ScriptBlock");
+ gMessageSystem->addUUID("AgentID", gAgent.getID());
+ U32 local_id = object->getLocalID();
+ gMessageSystem->addData("LocalID", &local_id);
+ gMessageSystem->addUUID("ItemID", mItemID);
+ LLHost host(object->getRegion()->getIP(),
+ object->getRegion()->getPort());
+ gMessageSystem->sendReliable(host);
+ */
+ }
+ }
+ else
+ {
+ mScriptEd->mEditor->setText(HELLO_LSL);
+ //mScriptEd->mEditor->setText("");
+ //mScriptEd->mEditor->makePristine();
+ LLPermissions perm;
+ perm.init(gAgent.getID(), gAgent.getID(), LLUUID::null, gAgent.getGroupID());
+ perm.initMasks(PERM_ALL, PERM_ALL, PERM_NONE, PERM_NONE, PERM_MOVE | PERM_TRANSFER);
+ mItem = new LLViewerInventoryItem(mItemID,
+ mObjectID,
+ perm,
+ LLUUID::null,
+ LLAssetType::AT_LSL_TEXT,
+ LLInventoryType::IT_LSL,
+ DEFAULT_SCRIPT_NAME,
+ DEFAULT_SCRIPT_DESC,
+ LLSaleInfo::DEFAULT,
+ LLInventoryItem::II_FLAGS_NONE,
+ time_corrected());
+ }
+}
+
+// static
+void LLLiveLSLEditor::onLoadComplete(LLVFS *vfs, const LLUUID& asset_id,
+ LLAssetType::EType type,
+ void* user_data, S32 status)
+{
+ LLLiveLSLEditor* instance = NULL;
+ LLUUID* xored_id = (LLUUID*)user_data;
+
+ if( LLLiveLSLEditor::sInstances.checkData(*xored_id) )
+ {
+ if( LL_ERR_NOERR == status )
+ {
+ instance = LLLiveLSLEditor::sInstances[*xored_id];
+ instance->loadScriptText(vfs, asset_id, type);
+ }
+ else
+ {
+ if( gViewerStats )
+ {
+ gViewerStats->incStat( LLViewerStats::ST_DOWNLOAD_FAILED );
+ }
+
+ if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
+ LL_ERR_FILE_EMPTY == status)
+ {
+ LLNotifyBox::showXml("ScriptMissing");
+ }
+ else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status)
+ {
+ LLNotifyBox::showXml("ScriptNoPermissions");
+ }
+ else
+ {
+ LLNotifyBox::showXml("UnableToLoadScript");
+ }
+ }
+ }
+
+ delete xored_id;
+}
+
+void LLLiveLSLEditor::loadScriptText(const char* filename)
+{
+ FILE* file = LLFile::fopen(filename, "rb");
+ if(file)
+ {
+ // read in the whole file
+ fseek(file, 0L, SEEK_END);
+ S32 file_length = ftell(file);
+ fseek(file, 0L, SEEK_SET);
+ char* buffer = new char[file_length+1];
+ fread(buffer, file_length, 1, file);
+ fclose(file);
+ buffer[file_length] = 0;
+ mScriptEd->mEditor->setText(buffer);
+ mScriptEd->mEditor->makePristine();
+ delete[] buffer;
+ }
+ else
+ {
+ llwarns << "Error opening " << filename << llendl;
+ }
+}
+
+void LLLiveLSLEditor::loadScriptText(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type)
+{
+ LLVFile file(vfs, uuid, type);
+ S32 file_length = file.getSize();
+ char *buffer = new char[file_length + 1];
+ file.read((U8*)buffer, file_length);
+
+ if (file.getLastBytesRead() != file_length ||
+ file_length <= 0)
+ {
+ llwarns << "Error reading " << uuid << ":" << type << llendl;
+ }
+
+ buffer[file_length] = '\0';
+
+ mScriptEd->mEditor->setText(buffer);
+ mScriptEd->mEditor->makePristine();
+ delete[] buffer;
+
+}
+
+
+void LLLiveLSLEditor::onRunningCheckboxClicked( LLUICtrl*, void* userdata )
+{
+ LLLiveLSLEditor* self = (LLLiveLSLEditor*) userdata;
+ LLViewerObject* object = gObjectList.findObject( self->mObjectID );
+ LLCheckBoxCtrl* runningCheckbox = LLUICtrlFactory::getCheckBoxByName(self, "running");
+ BOOL running = runningCheckbox->get();
+ //self->mRunningCheckbox->get();
+ if( object )
+ {
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_SetScriptRunning);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_Script);
+ msg->addUUIDFast(_PREHASH_ObjectID, self->mObjectID);
+ msg->addUUIDFast(_PREHASH_ItemID, self->mItemID);
+ msg->addBOOLFast(_PREHASH_Running, running);
+ msg->sendReliable(object->getRegion()->getHost());
+ }
+ else
+ {
+ runningCheckbox->set(!running);
+ gViewerWindow->alertXml("CouldNotStartStopScript");
+ }
+}
+
+void LLLiveLSLEditor::onReset(void *userdata)
+{
+ LLLiveLSLEditor* self = (LLLiveLSLEditor*) userdata;
+
+ LLViewerObject* object = gObjectList.findObject( self->mObjectID );
+ if(object)
+ {
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_ScriptReset);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_Script);
+ msg->addUUIDFast(_PREHASH_ObjectID, self->mObjectID);
+ msg->addUUIDFast(_PREHASH_ItemID, self->mItemID);
+ msg->sendReliable(object->getRegion()->getHost());
+ }
+ else
+ {
+ gViewerWindow->alertXml("CouldNotStartStopScript");
+ }
+}
+
+void LLLiveLSLEditor::draw()
+{
+ if(getVisible())
+ {
+ LLViewerObject* object = gObjectList.findObject(mObjectID);
+ LLCheckBoxCtrl* runningCheckbox = LLUICtrlFactory::getCheckBoxByName(this, "running");
+ if(object && mAskedForRunningInfo && mHaveRunningInfo)
+ {
+ if(object->permAnyOwner())
+ {
+ runningCheckbox->setLabel(ENABLED_RUNNING_CHECKBOX_LABEL);
+ runningCheckbox->setEnabled(TRUE);
+ }
+ else
+ {
+ runningCheckbox->setLabel(DISABLED_RUNNING_CHECKBOX_LABEL);
+ runningCheckbox->setEnabled(FALSE);
+ // *FIX: Set it to false so that the ui is correct for
+ // a box that is released to public. It could be
+ // incorrect after a release/claim cycle, but will be
+ // correct after clicking on it.
+ runningCheckbox->set(FALSE);
+ }
+ }
+ else if(!object)
+ {
+ // HACK: Display this information in the title bar.
+ // Really ought to put in main window.
+ setTitle("Script (object out of range)");
+ runningCheckbox->setEnabled(FALSE);
+ // object may have fallen out of range.
+ mHaveRunningInfo = FALSE;
+ }
+ LLFloater::draw();
+ }
+}
+
+struct LLLiveLSLSaveData
+{
+ LLLiveLSLSaveData(const LLUUID& id, const LLViewerInventoryItem* item, BOOL active);
+ LLUUID mObjectID;
+ LLPointer<LLViewerInventoryItem> mItem;
+ BOOL mActive;
+};
+
+LLLiveLSLSaveData::LLLiveLSLSaveData(const LLUUID& id,
+ const LLViewerInventoryItem* item,
+ BOOL active) :
+ mObjectID(id),
+ mActive(active)
+{
+ llassert(item);
+ mItem = new LLViewerInventoryItem(item);
+}
+
+void LLLiveLSLEditor::saveIfNeeded()
+{
+ llinfos << "LLLiveLSLEditor::saveIfNeeded()" << llendl;
+ LLViewerObject* object = gObjectList.findObject(mObjectID);
+ if(!object)
+ {
+ gViewerWindow->alertXml("SaveScriptFailObjectNotFound");
+ return;
+ }
+
+ // get the latest info about it. We used to be losing the script
+ // name on save, because the viewer object version of the item,
+ // and the editor version would get out of synch. Here's a good
+ // place to synch them back up.
+ // HACK! we "know" that mItemID refers to a LLInventoryItem...
+ LLInventoryItem* inv_item = (LLInventoryItem*)object->getInventoryObject(mItemID);
+ if(inv_item)
+ {
+ mItem->copy(inv_item);
+ }
+
+ // Don't need to save if we're pristine
+ if(mScriptEd->mEditor->isPristine())
+ {
+ return;
+ }
+
+ mPendingUploads = 0;
+
+ // save the script
+ mScriptEd->mEditor->makePristine();
+ mScriptEd->mErrorList->deleteAllItems();
+
+ // set up the save on the local machine.
+ mScriptEd->mEditor->makePristine();
+ LLTransactionID tid;
+ LLAssetID uuid;
+ tid.generate();
+ uuid = tid.makeAssetID(gAgent.getSecureSessionID());
+ mItem->setAssetUUID(uuid);
+ mItem->setTransactionID(tid);
+
+ // write out the data, and store it in the asset database
+ char uuid_string[UUID_STR_LENGTH];
+ uuid.toString(uuid_string);
+ char filename[LL_MAX_PATH];
+ sprintf(filename, "%s.lsl", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string).c_str());
+ FILE* fp = LLFile::fopen(filename, "wb");
+ if(!fp)
+ {
+ llwarns << "Unable to write to " << filename << llendl;
+ LLScrollListItem* item = new LLScrollListItem();
+ item->addColumn("Error writing to local file. Is your hard drive full?", LLFontGL::sSansSerifSmall);
+ mScriptEd->mErrorList->addItem(item);
+ return;
+ }
+ LLString utf8text = mScriptEd->mEditor->getText();
+ fputs(utf8text.c_str(), fp);
+ fclose(fp);
+
+ LLCheckBoxCtrl* runningCheckbox = LLUICtrlFactory::getCheckBoxByName(this, "running");
+
+ // save it out to database
+ if(gAssetStorage)
+ {
+ // write it out to the vfs for upload
+ LLVFile file(gVFS, uuid, LLAssetType::AT_LSL_TEXT, LLVFile::APPEND);
+ S32 size = utf8text.length() + 1;
+
+ file.setMaxSize(size);
+ file.write((U8*)utf8text.c_str(), size);
+
+ getWindow()->incBusyCount();
+ mPendingUploads++;
+ LLLiveLSLSaveData* data = new LLLiveLSLSaveData(mObjectID,
+ mItem,
+ runningCheckbox->get());
+ gAssetStorage->storeAssetData(tid, LLAssetType::AT_LSL_TEXT, &onSaveTextComplete, (void*)data, FALSE);
+ }
+
+#if LL_WINDOWS
+ // This major hack was inserted because sometimes compilation
+ // would fail because it couldn't open this file... I decided
+ // to make a loop until open was successful. This seems to be
+ // a problem specific to ntfs.
+ fp = NULL;
+ const U32 MAX_TRIES = 20;
+ U32 tries = MAX_TRIES;
+ while((!fp) && --tries)
+ {
+ ms_sleep(17);
+ fp = LLFile::fopen(filename, "r");
+ if(!fp)
+ {
+ llwarns << "Trying to open the source file " << filename
+ << " again" << llendl;
+ }
+ else
+ {
+ fclose(fp);
+ }
+ }
+ fp = NULL;
+#endif
+
+ char dst_filename[LL_MAX_PATH];
+ sprintf(dst_filename, "%s.lso", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string).c_str());
+ char err_filename[LL_MAX_PATH];
+ sprintf(err_filename, "%s.out", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string).c_str());
+ LLScrollListItem* item = NULL;
+ const LLFontGL* err_font = gResMgr->getRes(LLFONT_OCRA);
+ if(!lscript_compile(filename, dst_filename, err_filename, gAgent.isGodlike()))
+ {
+ // load the error file into the error scrolllist
+ llinfos << "Compile failed!" << llendl;
+ if(NULL != (fp = LLFile::fopen(err_filename, "r")))
+ {
+ char buffer[MAX_STRING];
+ LLString line;
+ while(!feof(fp))
+ {
+
+ fgets(buffer, MAX_STRING, fp);
+ if(feof(fp))
+ {
+ break;
+ }
+ else if(!buffer)
+ {
+ continue;
+ }
+ else
+ {
+ line.assign(buffer);
+ LLString::stripNonprintable(line);
+ item = new LLScrollListItem();
+ item->addColumn(line, err_font);
+ mScriptEd->mErrorList->addItem(item);
+ }
+ }
+ fclose(fp);
+ mScriptEd->selectFirstError();
+ // don't set the asset id, because we want to save the
+ // script, even though the compile failed.
+ //mItem->setAssetUUID(LLUUID::null);
+ object->saveScript(mItem, FALSE, false);
+ dialog_refresh_all();
+ }
+ }
+ else
+ {
+ llinfos << "Compile worked!" << llendl;
+ mScriptEd->mErrorList->addSimpleItem("Compile successful, saving...");
+ if(gAssetStorage)
+ {
+ llinfos << "LLLiveLSLEditor::saveAsset "
+ << mItem->getAssetUUID() << llendl;
+
+ // move the compiled file into the vfs for transport
+ FILE* fp = LLFile::fopen(dst_filename, "rb");
+ LLVFile file(gVFS, uuid, LLAssetType::AT_LSL_BYTECODE, LLVFile::APPEND);
+
+ fseek(fp, 0, SEEK_END);
+ S32 size = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ file.setMaxSize(size);
+
+ const S32 buf_size = 65536;
+ U8 copy_buf[buf_size];
+ while ((size = fread(copy_buf, 1, buf_size, fp)))
+ {
+ file.write(copy_buf, size);
+ }
+ fclose(fp);
+ fp = NULL;
+
+ getWindow()->incBusyCount();
+ mPendingUploads++;
+ LLLiveLSLSaveData* data = NULL;
+ data = new LLLiveLSLSaveData(mObjectID,
+ mItem,
+ runningCheckbox->get());
+ gAssetStorage->storeAssetData(tid,
+ LLAssetType::AT_LSL_BYTECODE,
+ &LLLiveLSLEditor::onSaveBytecodeComplete,
+ (void*)data);
+ dialog_refresh_all();
+ }
+ }
+
+ // get rid of any temp files left lying around
+ LLFile::remove(filename);
+ LLFile::remove(err_filename);
+ LLFile::remove(dst_filename);
+
+ // If we successfully saved it, then we should be able to check/uncheck the running box!
+ runningCheckbox->setLabel(ENABLED_RUNNING_CHECKBOX_LABEL);
+ runningCheckbox->setEnabled(TRUE);
+}
+
+void LLLiveLSLEditor::onSaveTextComplete(const LLUUID& asset_uuid, void* user_data, S32 status) // StoreAssetData callback (fixed)
+{
+ LLLiveLSLSaveData* data = (LLLiveLSLSaveData*)user_data;
+
+ if (status)
+ {
+ llwarns << "Unable to save text for a script." << llendl;
+ LLStringBase<char>::format_map_t args;
+ args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status));
+ gViewerWindow->alertXml("CompileQueueSaveText", args);
+ }
+ else
+ {
+ LLLiveLSLEditor* self = sInstances.getIfThere(data->mItem->getUUID() ^ data->mObjectID);
+ if (self)
+ {
+ self->getWindow()->decBusyCount();
+ self->mPendingUploads--;
+ if (self->mPendingUploads <= 0
+ && self->mCloseAfterSave)
+ {
+ self->close();
+ }
+ }
+ }
+ delete data;
+ data = NULL;
+}
+
+
+void LLLiveLSLEditor::onSaveBytecodeComplete(const LLUUID& asset_uuid, void* user_data, S32 status) // StoreAssetData callback (fixed)
+{
+ LLLiveLSLSaveData* data = (LLLiveLSLSaveData*)user_data;
+ if(!data)
+ return;
+ if(0 ==status)
+ {
+ llinfos << "LSL Bytecode saved" << llendl;
+ LLUUID xor_id = data->mItem->getUUID() ^ data->mObjectID;
+ LLLiveLSLEditor* self = sInstances.getIfThere(xor_id);
+ if(self)
+ {
+ // Tell the user that the compile worked.
+ self->mScriptEd->mErrorList->addSimpleItem("Save complete.");
+ // close the window if this completes both uploads
+ self->getWindow()->decBusyCount();
+ self->mPendingUploads--;
+ if (self->mPendingUploads <= 0
+ && self->mCloseAfterSave)
+ {
+ self->close();
+ }
+ }
+ LLViewerObject* object = gObjectList.findObject(data->mObjectID);
+ if(object)
+ {
+ object->saveScript(data->mItem, data->mActive, false);
+ dialog_refresh_all();
+ //LLToolDragAndDrop::dropScript(object, ids->first,
+ // LLAssetType::AT_LSL_TEXT, FALSE);
+ }
+ }
+ else
+ {
+ llinfos << "Problem saving LSL Bytecode (Live Editor)" << llendl;
+ llwarns << "Unable to save a compiled script." << llendl;
+
+ LLStringBase<char>::format_map_t args;
+ args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status));
+ gViewerWindow->alertXml("CompileQueueSaveBytecode", args);
+ }
+ char uuid_string[UUID_STR_LENGTH];
+ data->mItem->getAssetUUID().toString(uuid_string);
+ char dst_filename[LL_MAX_PATH];
+ sprintf(dst_filename, "%s.lso", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string).c_str());
+ LLFile::remove(dst_filename);
+ sprintf(dst_filename, "%s.lsl", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string).c_str());
+ LLFile::remove(dst_filename);
+ delete data;
+}
+
+BOOL LLLiveLSLEditor::canClose()
+{
+ return (mScriptEd->canClose());
+}
+
+// static
+void LLLiveLSLEditor::onLoad(void* userdata)
+{
+ LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata;
+ self->loadAsset();
+}
+
+// static
+void LLLiveLSLEditor::onSave(void* userdata, BOOL close_after_save)
+{
+ LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata;
+ self->mCloseAfterSave = close_after_save;
+ self->saveIfNeeded();
+}
+
+// static
+LLLiveLSLEditor* LLLiveLSLEditor::show(const LLUUID& script_id, const LLUUID& object_id)
+{
+ LLLiveLSLEditor* instance = NULL;
+ LLUUID xored_id = script_id ^ object_id;
+ if(LLLiveLSLEditor::sInstances.checkData(xored_id))
+ {
+ // Move the existing view to the front
+ instance = LLLiveLSLEditor::sInstances[xored_id];
+ instance->open();
+ }
+ return instance;
+}
+
+// static
+void LLLiveLSLEditor::hide(const LLUUID& script_id, const LLUUID& object_id)
+{
+ LLUUID xored_id = script_id ^ object_id;
+ if( LLLiveLSLEditor::sInstances.checkData( xored_id ) )
+ {
+ LLLiveLSLEditor* instance = LLLiveLSLEditor::sInstances[xored_id];
+ if(instance->getParent())
+ {
+ instance->getParent()->removeChild(instance);
+ }
+ delete instance;
+ }
+}
+
+// static
+void LLLiveLSLEditor::processScriptRunningReply(LLMessageSystem* msg, void**)
+{
+ LLUUID item_id;
+ LLUUID object_id;
+ msg->getUUIDFast(_PREHASH_Script, _PREHASH_ObjectID, object_id);
+ msg->getUUIDFast(_PREHASH_Script, _PREHASH_ItemID, item_id);
+ LLUUID xored_id = item_id ^ object_id;
+ if(LLLiveLSLEditor::sInstances.checkData(xored_id))
+ {
+ LLLiveLSLEditor* instance = LLLiveLSLEditor::sInstances[xored_id];
+ instance->mHaveRunningInfo = TRUE;
+ BOOL running;
+ msg->getBOOLFast(_PREHASH_Script, _PREHASH_Running, running);
+ LLCheckBoxCtrl* runningCheckbox = LLUICtrlFactory::getCheckBoxByName(instance, "running");
+ runningCheckbox->set(running);
+ }
+}
+
+void LLLiveLSLEditor::reshape(S32 width, S32 height, BOOL called_from_parent)
+{
+ LLFloater::reshape( width, height, called_from_parent );
+
+ if( !isMinimized() )
+ {
+ // So that next time you open a script it will have the same height and width
+ // (although not the same position).
+ gSavedSettings.setRect("PreviewScriptRect", mRect);
+ }
+}