Merge branch 'master' of git://github.com/lkalif/SingularityViewer
This commit is contained in:
@@ -117,7 +117,7 @@ LLDir_Linux::LLDir_Linux()
|
||||
mOSUserAppDir = "";
|
||||
mLindenUserDir = "";
|
||||
|
||||
char path [32]; /* Flawfinder: ignore */
|
||||
char path [MAX_PATH]; /* Flawfinder: ignore */
|
||||
|
||||
// *NOTE: /proc/%d/exe doesn't work on FreeBSD. But that's ok,
|
||||
// because this is the linux implementation.
|
||||
|
||||
@@ -165,6 +165,7 @@ set(viewer_SOURCE_FILES
|
||||
lleventinfo.cpp
|
||||
lleventnotifier.cpp
|
||||
lleventpoll.cpp
|
||||
llexternaleditor.cpp
|
||||
llface.cpp
|
||||
llfasttimerview.cpp
|
||||
llfeaturemanager.cpp
|
||||
@@ -643,6 +644,7 @@ set(viewer_HEADER_FILES
|
||||
lleventinfo.h
|
||||
lleventnotifier.h
|
||||
lleventpoll.h
|
||||
llexternaleditor.h
|
||||
llface.h
|
||||
llfasttimerview.h
|
||||
llfeaturemanager.h
|
||||
|
||||
@@ -14261,6 +14261,17 @@
|
||||
<key>Value</key>
|
||||
<real>150000.0</real>
|
||||
</map>
|
||||
<key>ExternalEditor</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Path to program used to edit LSL scripts and XUI files, e.g.: /usr/bin/gedit --new-window "%s"</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<string />
|
||||
</map>
|
||||
<key>YawFromMousePosition</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
||||
208
indra/newview/llexternaleditor.cpp
Normal file
208
indra/newview/llexternaleditor.cpp
Normal file
@@ -0,0 +1,208 @@
|
||||
/**
|
||||
* @file llexternaleditor.cpp
|
||||
* @brief A convenient class to run external editor.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
#include "llexternaleditor.h"
|
||||
|
||||
#include "lltrans.h"
|
||||
#include "llui.h"
|
||||
|
||||
// static
|
||||
const std::string LLExternalEditor::sFilenameMarker = "%s";
|
||||
|
||||
// static
|
||||
const std::string LLExternalEditor::sSetting = "ExternalEditor";
|
||||
|
||||
LLExternalEditor::EErrorCode LLExternalEditor::setCommand(const std::string& env_var, const std::string& override)
|
||||
{
|
||||
std::string cmd = findCommand(env_var, override);
|
||||
if (cmd.empty())
|
||||
{
|
||||
llwarns << "Editor command is empty or not set" << llendl;
|
||||
return EC_NOT_SPECIFIED;
|
||||
}
|
||||
|
||||
// Add the filename marker if missing.
|
||||
if (cmd.find(sFilenameMarker) == std::string::npos)
|
||||
{
|
||||
cmd += " \"" + sFilenameMarker + "\"";
|
||||
llinfos << "Adding the filename marker (" << sFilenameMarker << ")" << llendl;
|
||||
}
|
||||
|
||||
string_vec_t tokens;
|
||||
if (tokenize(tokens, cmd) < 2) // 2 = bin + at least one arg (%s)
|
||||
{
|
||||
llwarns << "Error parsing editor command" << llendl;
|
||||
return EC_PARSE_ERROR;
|
||||
}
|
||||
|
||||
// Check executable for existence.
|
||||
std::string bin_path = tokens[0];
|
||||
if (!LLFile::isfile(bin_path))
|
||||
{
|
||||
llwarns << "Editor binary [" << bin_path << "] not found" << llendl;
|
||||
return EC_BINARY_NOT_FOUND;
|
||||
}
|
||||
|
||||
// Save command.
|
||||
mProcess.setExecutable(bin_path);
|
||||
mArgs.clear();
|
||||
for (size_t i = 1; i < tokens.size(); ++i)
|
||||
{
|
||||
if (i > 1) mArgs += " ";
|
||||
mArgs += "\"" + tokens[i] + "\"";
|
||||
}
|
||||
llinfos << "Setting command [" << bin_path << " " << mArgs << "]" << llendl;
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
LLExternalEditor::EErrorCode LLExternalEditor::run(const std::string& file_path)
|
||||
{
|
||||
std::string args = mArgs;
|
||||
if (mProcess.getExecutable().empty() || args.empty())
|
||||
{
|
||||
llwarns << "Editor command not set" << llendl;
|
||||
return EC_NOT_SPECIFIED;
|
||||
}
|
||||
|
||||
// Substitute the filename marker in the command with the actual passed file name.
|
||||
LLStringUtil::replaceString(args, sFilenameMarker, file_path);
|
||||
|
||||
// Split command into separate tokens.
|
||||
string_vec_t tokens;
|
||||
tokenize(tokens, args);
|
||||
|
||||
// Set process arguments taken from the command.
|
||||
mProcess.clearArguments();
|
||||
for (string_vec_t::const_iterator arg_it = tokens.begin(); arg_it != tokens.end(); ++arg_it)
|
||||
{
|
||||
mProcess.addArgument(*arg_it);
|
||||
}
|
||||
|
||||
// Run the editor.
|
||||
llinfos << "Running editor command [" << mProcess.getExecutable() + " " + args << "]" << llendl;
|
||||
int result = mProcess.launch();
|
||||
if (result == 0)
|
||||
{
|
||||
// Prevent killing the process in destructor (will add it to the zombies list).
|
||||
mProcess.orphan();
|
||||
}
|
||||
|
||||
return result == 0 ? EC_SUCCESS : EC_FAILED_TO_RUN;
|
||||
}
|
||||
|
||||
// static
|
||||
std::string LLExternalEditor::getErrorMessage(EErrorCode code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case EC_SUCCESS: return LLTrans::getString("ok");
|
||||
case EC_NOT_SPECIFIED: return LLTrans::getString("ExternalEditorNotSet");
|
||||
case EC_PARSE_ERROR: return LLTrans::getString("ExternalEditorCommandParseError");
|
||||
case EC_BINARY_NOT_FOUND: return LLTrans::getString("ExternalEditorNotFound");
|
||||
case EC_FAILED_TO_RUN: return LLTrans::getString("ExternalEditorFailedToRun");
|
||||
}
|
||||
|
||||
return LLTrans::getString("Unknown");
|
||||
}
|
||||
|
||||
// static
|
||||
size_t LLExternalEditor::tokenize(string_vec_t& tokens, const std::string& str)
|
||||
{
|
||||
tokens.clear();
|
||||
|
||||
// Split the argument string into separate strings for each argument
|
||||
typedef boost::tokenizer< boost::char_separator<char> > tokenizer;
|
||||
boost::char_separator<char> sep("", "\" ", boost::drop_empty_tokens);
|
||||
|
||||
tokenizer tokens_list(str, sep);
|
||||
tokenizer::iterator token_iter;
|
||||
BOOL inside_quotes = FALSE;
|
||||
BOOL last_was_space = FALSE;
|
||||
for (token_iter = tokens_list.begin(); token_iter != tokens_list.end(); ++token_iter)
|
||||
{
|
||||
if (!strncmp("\"",(*token_iter).c_str(),2))
|
||||
{
|
||||
inside_quotes = !inside_quotes;
|
||||
}
|
||||
else if (!strncmp(" ",(*token_iter).c_str(),2))
|
||||
{
|
||||
if(inside_quotes)
|
||||
{
|
||||
tokens.back().append(std::string(" "));
|
||||
last_was_space = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string to_push = *token_iter;
|
||||
if (last_was_space)
|
||||
{
|
||||
tokens.back().append(to_push);
|
||||
last_was_space = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
tokens.push_back(to_push);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tokens.size();
|
||||
}
|
||||
|
||||
// static
|
||||
std::string LLExternalEditor::findCommand(
|
||||
const std::string& env_var,
|
||||
const std::string& override)
|
||||
{
|
||||
std::string cmd;
|
||||
|
||||
// Get executable path.
|
||||
if (!override.empty()) // try the supplied override first
|
||||
{
|
||||
cmd = override;
|
||||
llinfos << "Using override" << llendl;
|
||||
}
|
||||
else if (!gSavedSettings.getString(sSetting).empty())
|
||||
{
|
||||
cmd = gSavedSettings.getString(sSetting);
|
||||
llinfos << "Using setting" << llendl;
|
||||
}
|
||||
else // otherwise use the path specified by the environment variable
|
||||
{
|
||||
char* env_var_val = getenv(env_var.c_str());
|
||||
if (env_var_val)
|
||||
{
|
||||
cmd = env_var_val;
|
||||
llinfos << "Using env var " << env_var << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
llinfos << "Found command [" << cmd << "]" << llendl;
|
||||
return cmd;
|
||||
}
|
||||
105
indra/newview/llexternaleditor.h
Normal file
105
indra/newview/llexternaleditor.h
Normal file
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* @file llexternaleditor.h
|
||||
* @brief A convenient class to run external editor.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLEXTERNALEDITOR_H
|
||||
#define LL_LLEXTERNALEDITOR_H
|
||||
|
||||
#include <llprocesslauncher.h>
|
||||
|
||||
/**
|
||||
* Usage:
|
||||
* LLExternalEditor ed;
|
||||
* ed.setCommand("MY_EXTERNAL_EDITOR_VAR");
|
||||
* ed.run("/path/to/file1");
|
||||
* ed.run("/other/path/to/file2");
|
||||
*/
|
||||
class LLExternalEditor
|
||||
{
|
||||
typedef std::vector<std::string> string_vec_t;
|
||||
|
||||
public:
|
||||
|
||||
typedef enum e_error_code {
|
||||
EC_SUCCESS, /// No error.
|
||||
EC_NOT_SPECIFIED, /// Editor path not specified.
|
||||
EC_PARSE_ERROR, /// Editor command parsing error.
|
||||
EC_BINARY_NOT_FOUND, /// Could find the editor binary (missing or not quoted).
|
||||
EC_FAILED_TO_RUN, /// Could not execute the editor binary.
|
||||
} EErrorCode;
|
||||
|
||||
/**
|
||||
* Set editor command.
|
||||
*
|
||||
* @param env_var Environment variable of the same purpose.
|
||||
* @param override Optional override.
|
||||
*
|
||||
* First tries the override, then a predefined setting (sSetting),
|
||||
* then the environment variable.
|
||||
*
|
||||
* @return EC_SUCCESS if command is valid and refers to an existing executable,
|
||||
* EC_NOT_SPECIFIED or EC_FAILED_TO_RUNan on error.
|
||||
*
|
||||
* @see sSetting
|
||||
*/
|
||||
EErrorCode setCommand(const std::string& env_var, const std::string& override = LLStringUtil::null);
|
||||
|
||||
/**
|
||||
* Run the editor with the given file.
|
||||
*
|
||||
* @param file_path File to edit.
|
||||
* @return EC_SUCCESS on success, error code on error.
|
||||
*/
|
||||
EErrorCode run(const std::string& file_path);
|
||||
|
||||
/**
|
||||
* Get a meaningful error message for the given status code.
|
||||
*/
|
||||
static std::string getErrorMessage(EErrorCode code);
|
||||
|
||||
private:
|
||||
|
||||
static std::string findCommand(
|
||||
const std::string& env_var,
|
||||
const std::string& override);
|
||||
|
||||
static size_t tokenize(string_vec_t& tokens, const std::string& str);
|
||||
|
||||
/**
|
||||
* Filename placeholder that gets replaced with an actual file name.
|
||||
*/
|
||||
static const std::string sFilenameMarker;
|
||||
|
||||
/**
|
||||
* Setting that can specify the editor command.
|
||||
*/
|
||||
static const std::string sSetting;
|
||||
|
||||
|
||||
std::string mArgs;
|
||||
LLProcessLauncher mProcess;
|
||||
};
|
||||
|
||||
#endif // LL_LLEXTERNALEDITOR_H
|
||||
@@ -45,6 +45,8 @@
|
||||
#include "llkeyboard.h"
|
||||
#include "lllineeditor.h"
|
||||
|
||||
#include "lllivefile.h"
|
||||
#include "llexternaleditor.h"
|
||||
#include "llnotificationsutil.h"
|
||||
#include "llresmgr.h"
|
||||
#include "llscrollbar.h"
|
||||
@@ -147,6 +149,50 @@ static bool have_script_upload_cap(LLUUID& object_id)
|
||||
return object && (! object->getRegion()->getCapability("UpdateScriptTask").empty());
|
||||
}
|
||||
|
||||
/// ---------------------------------------------------------------------------
|
||||
/// LLLiveLSLFile
|
||||
/// ---------------------------------------------------------------------------
|
||||
class LLLiveLSLFile : public LLLiveFile
|
||||
{
|
||||
public:
|
||||
typedef boost::function<bool (const std::string& filename)> change_callback_t;
|
||||
|
||||
LLLiveLSLFile(std::string file_path, change_callback_t change_cb);
|
||||
~LLLiveLSLFile();
|
||||
|
||||
void ignoreNextUpdate() { mIgnoreNextUpdate = true; }
|
||||
|
||||
protected:
|
||||
/*virtual*/ bool loadFile();
|
||||
|
||||
change_callback_t mOnChangeCallback;
|
||||
bool mIgnoreNextUpdate;
|
||||
};
|
||||
|
||||
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()
|
||||
{
|
||||
LLFile::remove(filename());
|
||||
}
|
||||
|
||||
bool LLLiveLSLFile::loadFile()
|
||||
{
|
||||
if (mIgnoreNextUpdate)
|
||||
{
|
||||
mIgnoreNextUpdate = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return mOnChangeCallback(filename());
|
||||
}
|
||||
|
||||
/// ---------------------------------------------------------------------------
|
||||
/// LLScriptEdCore
|
||||
/// ---------------------------------------------------------------------------
|
||||
@@ -169,6 +215,8 @@ LLScriptEdCore::LLScriptEdCore(
|
||||
void (*save_callback)(void*, BOOL),
|
||||
void (*search_replace_callback) (void* userdata),
|
||||
void* userdata,
|
||||
LLUUID objectUUID,
|
||||
LLUUID itemUUID,
|
||||
S32 bottom_pad)
|
||||
:
|
||||
LLPanel( std::string("name"), rect ),
|
||||
@@ -183,8 +231,11 @@ LLScriptEdCore::LLScriptEdCore(
|
||||
mLastHelpToken(NULL),
|
||||
mLiveHelpHistorySize(0),
|
||||
mEnableSave(FALSE),
|
||||
mLiveFile(NULL),
|
||||
mHasScriptData(FALSE),
|
||||
LLEventTimer(60)
|
||||
LLEventTimer(60),
|
||||
mObjectUUID(objectUUID),
|
||||
mItemUUID(itemUUID)
|
||||
{
|
||||
setFollowsAll();
|
||||
setBorderVisible(FALSE);
|
||||
@@ -275,6 +326,7 @@ LLScriptEdCore::LLScriptEdCore(
|
||||
|
||||
childSetCommitCallback("lsl errors", &LLScriptEdCore::onErrorList, this);
|
||||
childSetAction("Save_btn", onBtnSave,this);
|
||||
childSetAction("Edit_btn", openInExternalEditor, this);
|
||||
|
||||
initMenu();
|
||||
|
||||
@@ -290,6 +342,7 @@ LLScriptEdCore::LLScriptEdCore(
|
||||
LLScriptEdCore::~LLScriptEdCore()
|
||||
{
|
||||
deleteBridges();
|
||||
delete mLiveFile;
|
||||
}
|
||||
|
||||
BOOL LLScriptEdCore::tick()
|
||||
@@ -359,6 +412,106 @@ 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 = getTmpFileName();
|
||||
llstat s;
|
||||
if (LLFile::stat(tmp_file, &s) == 0) // file exists
|
||||
{
|
||||
if (mLiveFile) mLiveFile->ignoreNextUpdate();
|
||||
writeToFile(tmp_file);
|
||||
}
|
||||
}
|
||||
|
||||
std::string LLScriptEdCore::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 LLScriptEdCore::onExternalChange(const std::string& filename)
|
||||
{
|
||||
if (!loadScriptText(filename))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Avoid recursive save/compile loop
|
||||
doSave(this, false, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOL LLScriptEdCore::hasChanged(void* userdata)
|
||||
{
|
||||
LLScriptEdCore* self = (LLScriptEdCore*)userdata;
|
||||
@@ -752,7 +905,7 @@ void LLScriptEdCore::onBtnInsertFunction(LLUICtrl *ui, void* userdata)
|
||||
}
|
||||
|
||||
// static
|
||||
void LLScriptEdCore::doSave( void* userdata, BOOL close_after_save )
|
||||
void LLScriptEdCore::doSave( void* userdata, BOOL close_after_save, BOOL sync_external_editor)
|
||||
{
|
||||
LLViewerStats::getInstance()->incStat( LLViewerStats::ST_LSL_SAVE_COUNT );
|
||||
|
||||
@@ -762,6 +915,56 @@ void LLScriptEdCore::doSave( void* userdata, BOOL close_after_save )
|
||||
{
|
||||
self->mSaveCallback( self->mUserdata, close_after_save );
|
||||
}
|
||||
if ( sync_external_editor )
|
||||
{
|
||||
self->sync();
|
||||
}
|
||||
}
|
||||
|
||||
void LLScriptEdCore::openInExternalEditor(void *userdata)
|
||||
{
|
||||
LLScriptEdCore* self = (LLScriptEdCore*) userdata;
|
||||
|
||||
delete self->mLiveFile; // deletes file
|
||||
|
||||
// Save the script to a temporary file.
|
||||
std::string filename = self->getTmpFileName();
|
||||
self->writeToFile(filename);
|
||||
|
||||
// Start watching file changes.
|
||||
self->mLiveFile = new LLLiveLSLFile(filename, boost::bind(&LLScriptEdCore::onExternalChange, self, _1));
|
||||
self->mLiveFile->ignoreNextUpdate();
|
||||
self->mLiveFile->addToEventTimer();
|
||||
|
||||
// Open it in external editor.
|
||||
{
|
||||
LLExternalEditor ed;
|
||||
LLExternalEditor::EErrorCode status;
|
||||
std::string msg;
|
||||
|
||||
status = ed.setCommand("LL_SCRIPT_EDITOR");
|
||||
if (status != LLExternalEditor::EC_SUCCESS)
|
||||
{
|
||||
if (status == LLExternalEditor::EC_NOT_SPECIFIED) // Use custom message for this error.
|
||||
{
|
||||
msg = "External editor not set";
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = LLExternalEditor::getErrorMessage(status);
|
||||
}
|
||||
|
||||
LLNotificationsUtil::add("GenericAlert", LLSD().with("MESSAGE", msg));
|
||||
return;
|
||||
}
|
||||
|
||||
status = ed.run(filename);
|
||||
if (status != LLExternalEditor::EC_SUCCESS)
|
||||
{
|
||||
msg = LLExternalEditor::getErrorMessage(status);
|
||||
LLNotificationsUtil::add("GenericAlert", LLSD().with("MESSAGE", msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -1038,6 +1241,8 @@ void* LLPreviewLSL::createScriptEdPanel(void* userdata)
|
||||
LLPreviewLSL::onSave,
|
||||
LLPreviewLSL::onSearchReplace,
|
||||
self,
|
||||
self->mObjectID,
|
||||
self->mItemUUID,
|
||||
0);
|
||||
|
||||
return self->mScriptEd;
|
||||
@@ -1602,6 +1807,8 @@ void* LLLiveLSLEditor::createScriptEdPanel(void* userdata)
|
||||
&LLLiveLSLEditor::onSave,
|
||||
&LLLiveLSLEditor::onSearchReplace,
|
||||
self,
|
||||
self->mObjectID,
|
||||
self->mItemUUID,
|
||||
0);
|
||||
|
||||
return self->mScriptEd;
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
#include "llframetimer.h"
|
||||
#include "lleventtimer.h"
|
||||
|
||||
|
||||
class LLLiveLSLFile;
|
||||
class LLMessageSystem;
|
||||
class LLTextEditor;
|
||||
class LLButton;
|
||||
@@ -72,6 +72,8 @@ public:
|
||||
void (*save_callback)(void* userdata, BOOL close_after_save),
|
||||
void (*search_replace_callback)(void* userdata),
|
||||
void* userdata,
|
||||
LLUUID objectUUID,
|
||||
LLUUID itemUUID,
|
||||
S32 bottom_pad = 0); // pad below bottom row of buttons
|
||||
~LLScriptEdCore();
|
||||
|
||||
@@ -82,6 +84,12 @@ public:
|
||||
BOOL canClose();
|
||||
|
||||
void setScriptText(const std::string& text, BOOL is_valid);
|
||||
bool loadScriptText(const std::string& filename);
|
||||
bool writeToFile(const std::string& filename);
|
||||
void sync();
|
||||
std::string getTmpFileName();
|
||||
static void openInExternalEditor(void* userdata);
|
||||
bool onExternalChange(const std::string& filename);
|
||||
|
||||
bool handleSaveChangesDialog(const LLSD& notification, const LLSD& response);
|
||||
bool handleReloadFromServerDialog(const LLSD& notification, const LLSD& response);
|
||||
@@ -95,7 +103,7 @@ public:
|
||||
static void onClickForward(void* userdata);
|
||||
static void onBtnInsertSample(void*);
|
||||
static void onBtnInsertFunction(LLUICtrl*, void*);
|
||||
static void doSave( void* userdata, BOOL close_after_save );
|
||||
static void doSave( void* userdata, BOOL close_after_save, BOOL sync_external_editor = TRUE );
|
||||
static void onBtnSave(void*);
|
||||
static void onBtnUndoChanges(void*);
|
||||
static void onSearchMenu(void* userdata);
|
||||
@@ -158,6 +166,9 @@ private:
|
||||
S32 mLiveHelpHistorySize;
|
||||
BOOL mEnableSave;
|
||||
BOOL mHasScriptData;
|
||||
LLLiveLSLFile* mLiveFile;
|
||||
LLUUID mObjectUUID;
|
||||
LLUUID mItemUUID;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,10 @@
|
||||
word_wrap="true" show_line_numbers="true">
|
||||
Loading...
|
||||
</text_editor>
|
||||
<button bottom="-499" enabled="true" follows="right|bottom" font="SansSerif"
|
||||
<button bottom="-499" enabled="true" follows="right|bottom" font="SansSerif"
|
||||
halign="center" height="20" label="Edit..." label_selected="Edit..." left="230"
|
||||
mouse_opaque="true" name="Edit_btn" width="128" />
|
||||
<button bottom="-499" enabled="true" follows="right|bottom" font="SansSerif"
|
||||
halign="center" height="20" label="Save" label_selected="Save" left="360"
|
||||
mouse_opaque="true" name="Save_btn" width="128" />
|
||||
<scroll_list background_visible="true" bottom="-457" column_padding="5" draw_border="true"
|
||||
|
||||
Reference in New Issue
Block a user