From b2fcba25c8dd04318420af30f877b0984a524055 Mon Sep 17 00:00:00 2001 From: Vadim ProductEngine Date: Sat, 13 Nov 2010 00:53:29 +0200 Subject: STORM-52 FIXED Made it possible to use an external script editor. The editor can be specified: * via "ExternalEditor" setting in settings.xml * via LL_SCRIPT_EDITOR variable Removed obsolete XUIEditor setting in favor of the new one. --- indra/newview/llpreviewscript.cpp | 235 +++++++++++++++++++++++++++++--------- 1 file changed, 182 insertions(+), 53 deletions(-) (limited to 'indra/newview/llpreviewscript.cpp') diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index cf2ea38288..330e809c53 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -34,11 +34,13 @@ #include "llcheckboxctrl.h" #include "llcombobox.h" #include "lldir.h" +#include "llexternaleditor.h" #include "llfloaterreg.h" #include "llinventorydefines.h" #include "llinventorymodel.h" #include "llkeyboard.h" #include "lllineeditor.h" +#include "lllivefile.h" #include "llhelp.h" #include "llnotificationsutil.h" #include "llresmgr.h" @@ -115,6 +117,54 @@ static bool have_script_upload_cap(LLUUID& object_id) return object && (! object->getRegion()->getCapability("UpdateScriptTask").empty()); } +/// --------------------------------------------------------------------------- +/// LLLiveLSLFile +/// --------------------------------------------------------------------------- +class LLLiveLSLFile : public LLLiveFile +{ +public: + LLLiveLSLFile(std::string file_path, LLLiveLSLEditor* parent); + ~LLLiveLSLFile(); + + void ignoreNextUpdate() { mIgnoreNextUpdate = true; } + +protected: + /*virtual*/ bool loadFile(); + + LLLiveLSLEditor* mParent; + bool mIgnoreNextUpdate; +}; + +LLLiveLSLFile::LLLiveLSLFile(std::string file_path, LLLiveLSLEditor* parent) +: mParent(parent) +, mIgnoreNextUpdate(false) +, LLLiveFile(file_path, 1.0) +{ +} + +LLLiveLSLFile::~LLLiveLSLFile() +{ + LLFile::remove(filename()); +} + +bool LLLiveLSLFile::loadFile() +{ + if (mIgnoreNextUpdate) + { + mIgnoreNextUpdate = false; + return true; + } + + if (!mParent->loadScriptText(filename())) + { + return false; + } + + // Disable sync to avoid recursive load->save->load calls. + mParent->saveIfNeeded(false); + return true; +} + /// --------------------------------------------------------------------------- /// LLFloaterScriptSearch /// --------------------------------------------------------------------------- @@ -281,6 +331,7 @@ LLScriptEdCore::LLScriptEdCore( const LLHandle& floater_handle, void (*load_callback)(void*), void (*save_callback)(void*, BOOL), + void (*edit_callback)(void*), void (*search_replace_callback) (void* userdata), void* userdata, S32 bottom_pad) @@ -290,6 +341,7 @@ LLScriptEdCore::LLScriptEdCore( mEditor( NULL ), mLoadCallback( load_callback ), mSaveCallback( save_callback ), + mEditCallback( edit_callback ), mSearchReplaceCallback( search_replace_callback ), mUserdata( userdata ), mForceClose( FALSE ), @@ -329,6 +381,7 @@ BOOL LLScriptEdCore::postBuild() childSetCommitCallback("lsl errors", &LLScriptEdCore::onErrorList, this); childSetAction("Save_btn", boost::bind(&LLScriptEdCore::doSave,this,FALSE)); + childSetAction("Edit_btn", boost::bind(&LLScriptEdCore::onEditButtonClick, this)); initMenu(); @@ -809,6 +862,13 @@ void LLScriptEdCore::doSave( BOOL close_after_save ) } } +void LLScriptEdCore::onEditButtonClick() +{ + if (mEditCallback) + { + mEditCallback(mUserdata); + } +} void LLScriptEdCore::onBtnUndoChanges() { @@ -949,6 +1009,7 @@ void* LLPreviewLSL::createScriptEdPanel(void* userdata) self->getHandle(), LLPreviewLSL::onLoad, LLPreviewLSL::onSave, + NULL, // no edit callback LLPreviewLSL::onSearchReplace, self, 0); @@ -1417,6 +1478,7 @@ void* LLLiveLSLEditor::createScriptEdPanel(void* userdata) self->getHandle(), &LLLiveLSLEditor::onLoad, &LLLiveLSLEditor::onSave, + &LLLiveLSLEditor::onEdit, &LLLiveLSLEditor::onSearchReplace, self, 0); @@ -1433,6 +1495,7 @@ LLLiveLSLEditor::LLLiveLSLEditor(const LLSD& key) : mCloseAfterSave(FALSE), mPendingUploads(0), mIsModifiable(FALSE), + mLiveFile(NULL), mIsNew(false) { mFactoryMap["script ed panel"] = LLCallbackMap(LLLiveLSLEditor::createScriptEdPanel, this); @@ -1458,6 +1521,7 @@ BOOL LLLiveLSLEditor::postBuild() LLLiveLSLEditor::~LLLiveLSLEditor() { + delete mLiveFile; } // virtual @@ -1639,38 +1703,39 @@ void LLLiveLSLEditor::onLoadComplete(LLVFS *vfs, const LLUUID& asset_id, delete xored_id; } -// unused -// void LLLiveLSLEditor::loadScriptText(const std::string& filename) -// { -// if(!filename) -// { -// llerrs << "Filename is Empty!" << llendl; -// return; -// } -// LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/ -// if(file) -// { -// // read in the whole file -// fseek(file, 0L, SEEK_END); -// long file_length = ftell(file); -// fseek(file, 0L, SEEK_SET); -// char* buffer = new char[file_length+1]; -// size_t nread = fread(buffer, 1, file_length, file); -// if (nread < (size_t) file_length) -// { -// llwarns << "Short read" << llendl; -// } -// buffer[nread] = '\0'; -// fclose(file); -// mScriptEd->mEditor->setText(LLStringExplicit(buffer)); -// mScriptEd->mEditor->makePristine(); -// delete[] buffer; -// } -// else -// { -// llwarns << "Error opening " << filename << llendl; -// } -// } + bool LLLiveLSLEditor::loadScriptText(const std::string& filename) + { + if (filename.empty()) + { + llwarns << "Empty file name" << llendl; + return false; + } + + LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/ + if (!file) + { + llwarns << "Error opening " << filename << llendl; + return false; + } + + // read in the whole file + fseek(file, 0L, SEEK_END); + size_t file_length = (size_t) ftell(file); + fseek(file, 0L, SEEK_SET); + char* buffer = new char[file_length+1]; + size_t nread = fread(buffer, 1, file_length, file); + if (nread < file_length) + { + llwarns << "Short read" << llendl; + } + buffer[nread] = '\0'; + fclose(file); + mScriptEd->mEditor->setText(LLStringExplicit(buffer)); + //mScriptEd->mEditor->makePristine(); + delete[] buffer; + + return true; + } void LLLiveLSLEditor::loadScriptText(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type) { @@ -1825,9 +1890,8 @@ LLLiveLSLSaveData::LLLiveLSLSaveData(const LLUUID& id, mItem = new LLViewerInventoryItem(item); } -void LLLiveLSLEditor::saveIfNeeded() +void LLLiveLSLEditor::saveIfNeeded(bool sync) { - llinfos << "LLLiveLSLEditor::saveIfNeeded()" << llendl; LLViewerObject* object = gObjectList.findObject(mObjectUUID); if(!object) { @@ -1877,9 +1941,74 @@ void LLLiveLSLEditor::saveIfNeeded() mItem->setAssetUUID(asset_id); mItem->setTransactionID(tid); - // write out the data, and store it in the asset database + writeToFile(filename); + + if (sync) + { + // Sync with external ed2itor. + std::string tmp_file = getTmpFileName(); + llstat s; + if (LLFile::stat(tmp_file, &s) == 0) // file exists + { + if (mLiveFile) mLiveFile->ignoreNextUpdate(); + writeToFile(tmp_file); + } + } + + // save it out to asset server + std::string url = object->getRegion()->getCapability("UpdateScriptTask"); + getWindow()->incBusyCount(); + mPendingUploads++; + BOOL is_running = getChild( "running")->get(); + if (!url.empty()) + { + uploadAssetViaCaps(url, filename, mObjectUUID, mItemUUID, is_running); + } + else if (gAssetStorage) + { + uploadAssetLegacy(filename, object, tid, is_running); + } +} + +void LLLiveLSLEditor::openExternalEditor() +{ + LLViewerObject* object = gObjectList.findObject(mObjectUUID); + if(!object) + { + LLNotificationsUtil::add("SaveScriptFailObjectNotFound"); + return; + } + + delete mLiveFile; // deletes file + + // Save the script to a temporary file. + std::string filename = getTmpFileName(); + writeToFile(filename); + + // Start watching file changes. + mLiveFile = new LLLiveLSLFile(filename, this); + mLiveFile->addToEventTimer(); + + // Open it in external editor. + { + LLExternalEditor ed; + + if (!ed.setCommand("LL_SCRIPT_EDITOR")) + { + std::string msg = "Select an editor by setting the environment variable LL_SCRIPT_EDITOR " + "or the ExternalEditor setting"; // *TODO: localize + LLNotificationsUtil::add("GenericAlert", LLSD().with("MESSAGE", msg)); + return; + } + + ed.run(filename); + } +} + +bool LLLiveLSLEditor::writeToFile(const std::string& filename) +{ LLFILE* fp = LLFile::fopen(filename, "wb"); - if(!fp) + if (!fp) { llwarns << "Unable to write to " << filename << llendl; @@ -1887,33 +2016,25 @@ void LLLiveLSLEditor::saveIfNeeded() row["columns"][0]["value"] = "Error writing to local file. Is your hard drive full?"; row["columns"][0]["font"] = "SANSSERIF_SMALL"; mScriptEd->mErrorList->addElement(row); - return; + return false; } + std::string utf8text = mScriptEd->mEditor->getText(); // Special case for a completely empty script - stuff in one space so it can store properly. See SL-46889 - if ( utf8text.size() == 0 ) + if (utf8text.size() == 0) { utf8text = " "; } fputs(utf8text.c_str(), fp); fclose(fp); - fp = NULL; - - // save it out to asset server - std::string url = object->getRegion()->getCapability("UpdateScriptTask"); - getWindow()->incBusyCount(); - mPendingUploads++; - BOOL is_running = getChild( "running")->get(); - if (!url.empty()) - { - uploadAssetViaCaps(url, filename, mObjectUUID, mItemUUID, is_running); - } - else if (gAssetStorage) - { - uploadAssetLegacy(filename, object, tid, is_running); - } + return true; +} + +std::string LLLiveLSLEditor::getTmpFileName() +{ + return std::string(LLFile::tmpdir()) + "sl_script_" + mObjectUUID.asString() + ".lsl"; } void LLLiveLSLEditor::uploadAssetViaCaps(const std::string& url, @@ -2138,6 +2259,14 @@ void LLLiveLSLEditor::onSave(void* userdata, BOOL close_after_save) self->saveIfNeeded(); } + +// static +void LLLiveLSLEditor::onEdit(void* userdata) +{ + LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata; + self->openExternalEditor(); +} + // static void LLLiveLSLEditor::processScriptRunningReply(LLMessageSystem* msg, void**) { -- cgit v1.2.3 From 37cd8ad2a27188538c29fdcce58cf8ec6185231c Mon Sep 17 00:00:00 2001 From: Vadim ProductEngine Date: Mon, 13 Dec 2010 13:38:46 +0200 Subject: STORM-781 FIXED Added support for editing multiple scripts within inventory of the same object using external editor. The bug was caused by using the object ID as temporary file name for editing script, which of course didn't work for multiple scripts in the same object inventory. The fix is to use MD5("object id" + "script inventory item id") for the file name. --- indra/newview/llpreviewscript.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'indra/newview/llpreviewscript.cpp') diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 330e809c53..d0ebf047e8 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -2034,7 +2034,17 @@ bool LLLiveLSLEditor::writeToFile(const std::string& filename) std::string LLLiveLSLEditor::getTmpFileName() { - return std::string(LLFile::tmpdir()) + "sl_script_" + mObjectUUID.asString() + ".lsl"; + // Take script inventory item id (within the object inventory) + // to consideration so that it's possible to edit multiple scripts + // in the same object inventory simultaneously (STORM-781). + std::string script_id = mObjectUUID.asString() + "_" + mItemUUID.asString(); + + // Use MD5 sum to make the file name shorter and not exceed maximum path length. + char script_id_hash_str[33]; /* Flawfinder: ignore */ + LLMD5 script_id_hash((const U8 *)script_id.c_str()); + script_id_hash.hex_digest(script_id_hash_str); + + return std::string(LLFile::tmpdir()) + "sl_script_" + script_id_hash_str + ".lsl"; } void LLLiveLSLEditor::uploadAssetViaCaps(const std::string& url, -- cgit v1.2.3 From 0eb491417e8479516b07cc9237242b60d36d10f5 Mon Sep 17 00:00:00 2001 From: Vadim ProductEngine Date: Wed, 22 Dec 2010 21:48:42 +0200 Subject: STORM-806 FIXED Enabled external editor for inventory scripts. Changes: * Moved external editor handling to LLScriptEdCore which is shared between LLLiveLSLEditor (object script editor) and LLPreviewLSL (inventory script editor). * The Edit button is now only enabled when appropriate. --- indra/newview/llpreviewscript.cpp | 349 +++++++++++++++++++------------------- 1 file changed, 170 insertions(+), 179 deletions(-) (limited to 'indra/newview/llpreviewscript.cpp') diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index d0ebf047e8..22ff362b5a 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -123,7 +123,9 @@ static bool have_script_upload_cap(LLUUID& object_id) class LLLiveLSLFile : public LLLiveFile { public: - LLLiveLSLFile(std::string file_path, LLLiveLSLEditor* parent); + typedef boost::function change_callback_t; + + LLLiveLSLFile(std::string file_path, change_callback_t change_cb); ~LLLiveLSLFile(); void ignoreNextUpdate() { mIgnoreNextUpdate = true; } @@ -131,15 +133,16 @@ public: protected: /*virtual*/ bool loadFile(); - LLLiveLSLEditor* mParent; + change_callback_t mOnChangeCallback; bool mIgnoreNextUpdate; }; -LLLiveLSLFile::LLLiveLSLFile(std::string file_path, LLLiveLSLEditor* parent) -: mParent(parent) +LLLiveLSLFile::LLLiveLSLFile(std::string file_path, change_callback_t change_cb) +: mOnChangeCallback(change_cb) , mIgnoreNextUpdate(false) , LLLiveFile(file_path, 1.0) { + llassert(mOnChangeCallback); } LLLiveLSLFile::~LLLiveLSLFile() @@ -155,14 +158,7 @@ bool LLLiveLSLFile::loadFile() return true; } - if (!mParent->loadScriptText(filename())) - { - return false; - } - - // Disable sync to avoid recursive load->save->load calls. - mParent->saveIfNeeded(false); - return true; + return mOnChangeCallback(filename()); } /// --------------------------------------------------------------------------- @@ -327,11 +323,11 @@ struct LLSECKeywordCompare }; LLScriptEdCore::LLScriptEdCore( + LLScriptEdContainer* container, const std::string& sample, const LLHandle& floater_handle, void (*load_callback)(void*), void (*save_callback)(void*, BOOL), - void (*edit_callback)(void*), void (*search_replace_callback) (void* userdata), void* userdata, S32 bottom_pad) @@ -341,19 +337,21 @@ LLScriptEdCore::LLScriptEdCore( mEditor( NULL ), mLoadCallback( load_callback ), mSaveCallback( save_callback ), - mEditCallback( edit_callback ), mSearchReplaceCallback( search_replace_callback ), mUserdata( userdata ), mForceClose( FALSE ), mLastHelpToken(NULL), mLiveHelpHistorySize(0), mEnableSave(FALSE), + mLiveFile(NULL), + mContainer(container), mHasScriptData(FALSE) { setFollowsAll(); setBorderVisible(FALSE); setXMLFilename("panel_script_ed.xml"); + llassert_always(mContainer != NULL); } LLScriptEdCore::~LLScriptEdCore() @@ -367,6 +365,8 @@ LLScriptEdCore::~LLScriptEdCore() script_search->closeFloater(); delete script_search; } + + delete mLiveFile; } BOOL LLScriptEdCore::postBuild() @@ -381,7 +381,7 @@ BOOL LLScriptEdCore::postBuild() childSetCommitCallback("lsl errors", &LLScriptEdCore::onErrorList, this); childSetAction("Save_btn", boost::bind(&LLScriptEdCore::doSave,this,FALSE)); - childSetAction("Edit_btn", boost::bind(&LLScriptEdCore::onEditButtonClick, this)); + childSetAction("Edit_btn", boost::bind(&LLScriptEdCore::openInExternalEditor, this)); initMenu(); @@ -514,6 +514,79 @@ void LLScriptEdCore::setScriptText(const std::string& text, BOOL is_valid) } } +bool LLScriptEdCore::loadScriptText(const std::string& filename) +{ + if (filename.empty()) + { + llwarns << "Empty file name" << llendl; + return false; + } + + LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/ + if (!file) + { + llwarns << "Error opening " << filename << llendl; + return false; + } + + // read in the whole file + fseek(file, 0L, SEEK_END); + size_t file_length = (size_t) ftell(file); + fseek(file, 0L, SEEK_SET); + char* buffer = new char[file_length+1]; + size_t nread = fread(buffer, 1, file_length, file); + if (nread < file_length) + { + llwarns << "Short read" << llendl; + } + buffer[nread] = '\0'; + fclose(file); + + mEditor->setText(LLStringExplicit(buffer)); + delete[] buffer; + + return true; +} + +bool LLScriptEdCore::writeToFile(const std::string& filename) +{ + LLFILE* fp = LLFile::fopen(filename, "wb"); + if (!fp) + { + llwarns << "Unable to write to " << filename << llendl; + + LLSD row; + row["columns"][0]["value"] = "Error writing to local file. Is your hard drive full?"; + row["columns"][0]["font"] = "SANSSERIF_SMALL"; + mErrorList->addElement(row); + return false; + } + + std::string utf8text = mEditor->getText(); + + // Special case for a completely empty script - stuff in one space so it can store properly. See SL-46889 + if (utf8text.size() == 0) + { + utf8text = " "; + } + + fputs(utf8text.c_str(), fp); + fclose(fp); + return true; +} + +void LLScriptEdCore::sync() +{ + // Sync with external editor. + std::string tmp_file = mContainer->getTmpFileName(); + llstat s; + if (LLFile::stat(tmp_file, &s) == 0) // file exists + { + if (mLiveFile) mLiveFile->ignoreNextUpdate(); + writeToFile(tmp_file); + } +} + bool LLScriptEdCore::hasChanged() { if (!mEditor) return false; @@ -690,6 +763,12 @@ BOOL LLScriptEdCore::canClose() } } +void LLScriptEdCore::setEnableEditing(bool enable) +{ + mEditor->setEnabled(enable); + getChildView("Edit_btn")->setEnabled(enable); +} + bool LLScriptEdCore::handleSaveChangesDialog(const LLSD& notification, const LLSD& response ) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); @@ -862,11 +941,31 @@ void LLScriptEdCore::doSave( BOOL close_after_save ) } } -void LLScriptEdCore::onEditButtonClick() +void LLScriptEdCore::openInExternalEditor() { - if (mEditCallback) + delete mLiveFile; // deletes file + + // Save the script to a temporary file. + std::string filename = mContainer->getTmpFileName(); + writeToFile(filename); + + // Start watching file changes. + mLiveFile = new LLLiveLSLFile(filename, boost::bind(&LLScriptEdContainer::onExternalChange, mContainer, _1)); + mLiveFile->addToEventTimer(); + + // Open it in external editor. { - mEditCallback(mUserdata); + LLExternalEditor ed; + + if (!ed.setCommand("LL_SCRIPT_EDITOR")) + { + std::string msg = "Select an editor by setting the environment variable LL_SCRIPT_EDITOR " + "or the ExternalEditor setting"; // *TODO: localize + LLNotificationsUtil::add("GenericAlert", LLSD().with("MESSAGE", msg)); + return; + } + + ed.run(filename); } } @@ -982,6 +1081,43 @@ BOOL LLScriptEdCore::handleKeyHere(KEY key, MASK mask) return FALSE; } +/// --------------------------------------------------------------------------- +/// LLScriptEdContainer +/// --------------------------------------------------------------------------- + +LLScriptEdContainer::LLScriptEdContainer(const LLSD& key) +: LLPreview(key) +, mScriptEd(NULL) +{ +} + +std::string LLScriptEdContainer::getTmpFileName() +{ + // Take script inventory item id (within the object inventory) + // to consideration so that it's possible to edit multiple scripts + // in the same object inventory simultaneously (STORM-781). + std::string script_id = mObjectUUID.asString() + "_" + mItemUUID.asString(); + + // Use MD5 sum to make the file name shorter and not exceed maximum path length. + char script_id_hash_str[33]; /* Flawfinder: ignore */ + LLMD5 script_id_hash((const U8 *)script_id.c_str()); + script_id_hash.hex_digest(script_id_hash_str); + + return std::string(LLFile::tmpdir()) + "sl_script_" + script_id_hash_str + ".lsl"; +} + +bool LLScriptEdContainer::onExternalChange(const std::string& filename) +{ + if (!mScriptEd->loadScriptText(filename)) + { + return false; + } + + // Disable sync to avoid recursive load->save->load calls. + saveIfNeeded(false); + return true; +} + /// --------------------------------------------------------------------------- /// LLPreviewLSL /// --------------------------------------------------------------------------- @@ -1005,11 +1141,11 @@ void* LLPreviewLSL::createScriptEdPanel(void* userdata) LLPreviewLSL *self = (LLPreviewLSL*)userdata; self->mScriptEd = new LLScriptEdCore( + self, HELLO_LSL, self->getHandle(), LLPreviewLSL::onLoad, LLPreviewLSL::onSave, - NULL, // no edit callback LLPreviewLSL::onSearchReplace, self, 0); @@ -1019,7 +1155,7 @@ void* LLPreviewLSL::createScriptEdPanel(void* userdata) LLPreviewLSL::LLPreviewLSL(const LLSD& key ) - : LLPreview( key ), +: LLScriptEdContainer(key), mPendingUploads(0) { mFactoryMap["script panel"] = LLCallbackMap(LLPreviewLSL::createScriptEdPanel, this); @@ -1110,7 +1246,6 @@ void LLPreviewLSL::loadAsset() { mScriptEd->setScriptText(mScriptEd->getString("can_not_view"), FALSE); mScriptEd->mEditor->makePristine(); - mScriptEd->mEditor->setEnabled(FALSE); mScriptEd->mFunctions->setEnabled(FALSE); mAssetStatus = PREVIEW_ASSET_LOADED; } @@ -1120,6 +1255,7 @@ void LLPreviewLSL::loadAsset() else { mScriptEd->setScriptText(std::string(HELLO_LSL), TRUE); + mScriptEd->setEnableEditing(TRUE); mAssetStatus = PREVIEW_ASSET_LOADED; } } @@ -1166,7 +1302,7 @@ void LLPreviewLSL::onSave(void* userdata, BOOL close_after_save) // 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. -void LLPreviewLSL::saveIfNeeded() +void LLPreviewLSL::saveIfNeeded(bool sync /*= true*/) { // llinfos << "LLPreviewLSL::saveIfNeeded()" << llendl; if(!mScriptEd->hasChanged()) @@ -1185,23 +1321,13 @@ void LLPreviewLSL::saveIfNeeded() std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id.asString()); std::string filename = filepath + ".lsl"; - LLFILE* fp = LLFile::fopen(filename, "wb"); - if(!fp) - { - llwarns << "Unable to write to " << filename << llendl; + mScriptEd->writeToFile(filename); - LLSD row; - row["columns"][0]["value"] = "Error writing to local file. Is your hard drive full?"; - row["columns"][0]["font"] = "SANSSERIF_SMALL"; - mScriptEd->mErrorList->addElement(row); - return; + if (sync) + { + mScriptEd->sync(); } - std::string utf8text = mScriptEd->mEditor->getText(); - fputs(utf8text.c_str(), fp); - fclose(fp); - fp = NULL; - const LLInventoryItem *inv_item = getItem(); // save it out to asset server std::string url = gAgent.getRegion()->getCapability("UpdateScriptAgent"); @@ -1433,7 +1559,7 @@ void LLPreviewLSL::onLoadComplete( LLVFS *vfs, const LLUUID& asset_uuid, LLAsset { is_modifiable = TRUE; } - preview->mScriptEd->mEditor->setEnabled(is_modifiable); + preview->mScriptEd->setEnableEditing(is_modifiable); preview->mAssetStatus = PREVIEW_ASSET_LOADED; } else @@ -1474,11 +1600,11 @@ void* LLLiveLSLEditor::createScriptEdPanel(void* userdata) LLLiveLSLEditor *self = (LLLiveLSLEditor*)userdata; self->mScriptEd = new LLScriptEdCore( + self, HELLO_LSL, self->getHandle(), &LLLiveLSLEditor::onLoad, &LLLiveLSLEditor::onSave, - &LLLiveLSLEditor::onEdit, &LLLiveLSLEditor::onSearchReplace, self, 0); @@ -1488,14 +1614,12 @@ void* LLLiveLSLEditor::createScriptEdPanel(void* userdata) LLLiveLSLEditor::LLLiveLSLEditor(const LLSD& key) : - LLPreview(key), - mScriptEd(NULL), + LLScriptEdContainer(key), mAskedForRunningInfo(FALSE), mHaveRunningInfo(FALSE), mCloseAfterSave(FALSE), mPendingUploads(0), mIsModifiable(FALSE), - mLiveFile(NULL), mIsNew(false) { mFactoryMap["script ed panel"] = LLCallbackMap(LLLiveLSLEditor::createScriptEdPanel, this); @@ -1519,11 +1643,6 @@ BOOL LLLiveLSLEditor::postBuild() return LLPreview::postBuild(); } -LLLiveLSLEditor::~LLLiveLSLEditor() -{ - delete mLiveFile; -} - // virtual void LLLiveLSLEditor::callbackLSLCompileSucceeded(const LLUUID& task_id, const LLUUID& item_id, @@ -1580,7 +1699,6 @@ void LLLiveLSLEditor::loadAsset() mItem = new LLViewerInventoryItem(item); mScriptEd->setScriptText(getString("not_allowed"), FALSE); mScriptEd->mEditor->makePristine(); - mScriptEd->mEditor->setEnabled(FALSE); mScriptEd->enableSave(FALSE); mAssetStatus = PREVIEW_ASSET_LOADED; } @@ -1618,10 +1736,6 @@ void LLLiveLSLEditor::loadAsset() mIsModifiable = item && gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE); - if(!mIsModifiable) - { - mScriptEd->mEditor->setEnabled(FALSE); - } // This is commented out, because we don't completely // handle script exports yet. @@ -1677,6 +1791,7 @@ void LLLiveLSLEditor::onLoadComplete(LLVFS *vfs, const LLUUID& asset_id, if( LL_ERR_NOERR == status ) { instance->loadScriptText(vfs, asset_id, type); + instance->mScriptEd->setEnableEditing(TRUE); instance->mAssetStatus = PREVIEW_ASSET_LOADED; } else @@ -1703,40 +1818,6 @@ void LLLiveLSLEditor::onLoadComplete(LLVFS *vfs, const LLUUID& asset_id, delete xored_id; } - bool LLLiveLSLEditor::loadScriptText(const std::string& filename) - { - if (filename.empty()) - { - llwarns << "Empty file name" << llendl; - return false; - } - - LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/ - if (!file) - { - llwarns << "Error opening " << filename << llendl; - return false; - } - - // read in the whole file - fseek(file, 0L, SEEK_END); - size_t file_length = (size_t) ftell(file); - fseek(file, 0L, SEEK_SET); - char* buffer = new char[file_length+1]; - size_t nread = fread(buffer, 1, file_length, file); - if (nread < file_length) - { - llwarns << "Short read" << llendl; - } - buffer[nread] = '\0'; - fclose(file); - mScriptEd->mEditor->setText(LLStringExplicit(buffer)); - //mScriptEd->mEditor->makePristine(); - delete[] buffer; - - return true; - } - void LLLiveLSLEditor::loadScriptText(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type) { LLVFile file(vfs, uuid, type); @@ -1890,7 +1971,8 @@ LLLiveLSLSaveData::LLLiveLSLSaveData(const LLUUID& id, mItem = new LLViewerInventoryItem(item); } -void LLLiveLSLEditor::saveIfNeeded(bool sync) +// virtual +void LLLiveLSLEditor::saveIfNeeded(bool sync /*= true*/) { LLViewerObject* object = gObjectList.findObject(mObjectUUID); if(!object) @@ -1941,18 +2023,11 @@ void LLLiveLSLEditor::saveIfNeeded(bool sync) mItem->setAssetUUID(asset_id); mItem->setTransactionID(tid); - writeToFile(filename); + mScriptEd->writeToFile(filename); if (sync) { - // Sync with external ed2itor. - std::string tmp_file = getTmpFileName(); - llstat s; - if (LLFile::stat(tmp_file, &s) == 0) // file exists - { - if (mLiveFile) mLiveFile->ignoreNextUpdate(); - writeToFile(tmp_file); - } + mScriptEd->sync(); } // save it out to asset server @@ -1970,83 +2045,6 @@ void LLLiveLSLEditor::saveIfNeeded(bool sync) } } -void LLLiveLSLEditor::openExternalEditor() -{ - LLViewerObject* object = gObjectList.findObject(mObjectUUID); - if(!object) - { - LLNotificationsUtil::add("SaveScriptFailObjectNotFound"); - return; - } - - delete mLiveFile; // deletes file - - // Save the script to a temporary file. - std::string filename = getTmpFileName(); - writeToFile(filename); - - // Start watching file changes. - mLiveFile = new LLLiveLSLFile(filename, this); - mLiveFile->addToEventTimer(); - - // Open it in external editor. - { - LLExternalEditor ed; - - if (!ed.setCommand("LL_SCRIPT_EDITOR")) - { - std::string msg = "Select an editor by setting the environment variable LL_SCRIPT_EDITOR " - "or the ExternalEditor setting"; // *TODO: localize - LLNotificationsUtil::add("GenericAlert", LLSD().with("MESSAGE", msg)); - return; - } - - ed.run(filename); - } -} - -bool LLLiveLSLEditor::writeToFile(const std::string& filename) -{ - LLFILE* fp = LLFile::fopen(filename, "wb"); - if (!fp) - { - llwarns << "Unable to write to " << filename << llendl; - - LLSD row; - row["columns"][0]["value"] = "Error writing to local file. Is your hard drive full?"; - row["columns"][0]["font"] = "SANSSERIF_SMALL"; - mScriptEd->mErrorList->addElement(row); - return false; - } - - std::string utf8text = mScriptEd->mEditor->getText(); - - // Special case for a completely empty script - stuff in one space so it can store properly. See SL-46889 - if (utf8text.size() == 0) - { - utf8text = " "; - } - - fputs(utf8text.c_str(), fp); - fclose(fp); - return true; -} - -std::string LLLiveLSLEditor::getTmpFileName() -{ - // Take script inventory item id (within the object inventory) - // to consideration so that it's possible to edit multiple scripts - // in the same object inventory simultaneously (STORM-781). - std::string script_id = mObjectUUID.asString() + "_" + mItemUUID.asString(); - - // Use MD5 sum to make the file name shorter and not exceed maximum path length. - char script_id_hash_str[33]; /* Flawfinder: ignore */ - LLMD5 script_id_hash((const U8 *)script_id.c_str()); - script_id_hash.hex_digest(script_id_hash_str); - - return std::string(LLFile::tmpdir()) + "sl_script_" + script_id_hash_str + ".lsl"; -} - void LLLiveLSLEditor::uploadAssetViaCaps(const std::string& url, const std::string& filename, const LLUUID& task_id, @@ -2270,13 +2268,6 @@ void LLLiveLSLEditor::onSave(void* userdata, BOOL close_after_save) } -// static -void LLLiveLSLEditor::onEdit(void* userdata) -{ - LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata; - self->openExternalEditor(); -} - // static void LLLiveLSLEditor::processScriptRunningReply(LLMessageSystem* msg, void**) { -- cgit v1.2.3 From eef9b265b951337d0633d18186dad2b734b30d5a Mon Sep 17 00:00:00 2001 From: Vadim ProductEngine Date: Mon, 7 Mar 2011 19:18:31 +0200 Subject: STORM-1018 FIXED Improved error messaging for the External Editor feature. Let the user know what's wrong with external editor. Added meaningful messages for the following errors: * Editor not specified. * Error parsing command line. * Specified binary not found. * Editor failed to run. All the messages are translatable. --- indra/newview/llpreviewscript.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'indra/newview/llpreviewscript.cpp') diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 22ff362b5a..b19bf5d234 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -956,16 +956,31 @@ void LLScriptEdCore::openInExternalEditor() // Open it in external editor. { LLExternalEditor ed; + LLExternalEditor::EErrorCode status; + std::string msg; - if (!ed.setCommand("LL_SCRIPT_EDITOR")) + status = ed.setCommand("LL_SCRIPT_EDITOR"); + if (status != LLExternalEditor::EC_SUCCESS) { - std::string msg = "Select an editor by setting the environment variable LL_SCRIPT_EDITOR " - "or the ExternalEditor setting"; // *TODO: localize + if (status == LLExternalEditor::EC_NOT_SPECIFIED) // Use custom message for this error. + { + msg = getString("external_editor_not_set"); + } + else + { + msg = LLExternalEditor::getErrorMessage(status); + } + LLNotificationsUtil::add("GenericAlert", LLSD().with("MESSAGE", msg)); return; } - ed.run(filename); + status = ed.run(filename); + if (status != LLExternalEditor::EC_SUCCESS) + { + msg = LLExternalEditor::getErrorMessage(status); + LLNotificationsUtil::add("GenericAlert", LLSD().with("MESSAGE", msg)); + } } } -- cgit v1.2.3