Branch merge

meow-7.2.2
Arrehn 2010-11-17 10:39:47 -08:00
commit b1e83df9ba
19 changed files with 754 additions and 323 deletions

View File

@ -170,6 +170,7 @@ Boroondas Gupte
SNOW-610
SNOW-624
SNOW-737
STORM-318
VWR-233
VWR-20583
VWR-20891
@ -750,6 +751,8 @@ WolfPup Lowenhar
STORM-102
STORM-103
STORM-143
STORM-535
STORM-544
VWR-20741
VWR-20933
Zai Lynch

View File

@ -7,8 +7,9 @@ macro (check_message_template _target)
TARGET ${_target}
POST_BUILD
COMMAND ${PYTHON_EXECUTABLE}
ARGS ${SCRIPTS_DIR}/template_verifier.py
--mode=development --cache_master
COMMENT "Verifying message template"
ARGS ${SCRIPTS_DIR}/md5check.py
3f19d130400c547de36278a6b6f9b028
${SCRIPTS_DIR}/messages/message_template.msg
COMMENT "Verifying message template - See http://wiki.secondlife.com/wiki/Template_verifier.py"
)
endmacro (check_message_template)

View File

@ -58,6 +58,11 @@ void LLProcessLauncher::setWorkingDirectory(const std::string &dir)
mWorkingDir = dir;
}
const std::string& LLProcessLauncher::getExecutable() const
{
return mExecutable;
}
void LLProcessLauncher::clearArguments()
{
mLaunchArguments.clear();

View File

@ -47,6 +47,8 @@ public:
void setExecutable(const std::string &executable);
void setWorkingDirectory(const std::string &dir);
const std::string& getExecutable() const;
void clearArguments();
void addArgument(const std::string &arg);
void addArgument(const char *arg);

View File

@ -143,6 +143,7 @@ set(viewer_SOURCE_FILES
lleventnotifier.cpp
lleventpoll.cpp
llexpandabletextbox.cpp
llexternaleditor.cpp
llface.cpp
llfasttimerview.cpp
llfavoritesbar.cpp
@ -682,6 +683,7 @@ set(viewer_HEADER_FILES
lleventnotifier.h
lleventpoll.h
llexpandabletextbox.h
llexternaleditor.h
llface.h
llfasttimerview.h
llfavoritesbar.h

View File

@ -12059,10 +12059,10 @@
<key>Value</key>
<real>150000.0</real>
</map>
<key>XUIEditor</key>
<key>ExternalEditor</key>
<map>
<key>Comment</key>
<string>Path to program used to edit XUI files</string>
<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>

View File

@ -825,9 +825,14 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
// [/RLVa:KB]
{
LLStyle::Params link_params(style_params);
link_params.overwriteFrom(LLStyleMap::instance().lookupAgent(chat.mFromID));
// Setting is_link = true for agent SLURL to avoid applying default style to it.
// See LLTextBase::appendTextImpl().
link_params.is_link = true;
link_params.link_href = LLSLURL("agent", chat.mFromID, "inspect").getSLURLString();
// Add link to avatar's inspector and delimiter to message.
mEditor->appendText(link_params.link_href, false, style_params);
mEditor->appendText(chat.mFromName, false, link_params);
mEditor->appendText(delimiter, false, style_params);
}
else

View File

@ -31,6 +31,7 @@
#include "llchatmsgbox.h"
#include "llavatariconctrl.h"
#include "llcommandhandler.h"
#include "llfloaterreg.h"
#include "lllocalcliprect.h"
#include "lltrans.h"
@ -40,14 +41,44 @@
#include "llslurl.h"
// [RLVa:KB] - Checked: 2010-04-21 (RLVa-1.2.0f)
#include "rlvhandler.h"
// [/RLVa:KB]
static const S32 msg_left_offset = 10;
static const S32 msg_right_offset = 10;
static const S32 msg_height_pad = 5;
//*******************************************************************************************************************
// LLObjectHandler
//*******************************************************************************************************************
// handle secondlife:///app/object/<ID>/inspect SLURLs
class LLObjectHandler : public LLCommandHandler
{
public:
LLObjectHandler() : LLCommandHandler("object", UNTRUSTED_BLOCK) { }
bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
{
if (params.size() < 2) return false;
LLUUID object_id;
if (!object_id.set(params[0], FALSE))
{
return false;
}
const std::string verb = params[1].asString();
if (verb == "inspect")
{
LLFloaterReg::showInstance("inspect_object", LLSD().with("object_id", object_id));
return true;
}
return false;
}
};
LLObjectHandler gObjectHandler;
//*******************************************************************************************************************
//LLNearbyChatToastPanel
//*******************************************************************************************************************
@ -145,11 +176,7 @@ void LLNearbyChatToastPanel::init(LLSD& notification)
std::string fromName = notification["from"].asString(); // agent or object name
mFromID = notification["from_id"].asUUID(); // agent id or object id
mFromName = fromName;
// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
mShowIconTooltip = notification.has("show_icon_tooltip") ? notification["show_icon_tooltip"].asBoolean() : true;
// [/RLVa:KB]
int sType = notification["source"].asInteger();
mSourceType = (EChatSourceType)sType;
@ -177,17 +204,26 @@ void LLNearbyChatToastPanel::init(LLSD& notification)
{
std::string str_sender;
str_sender = "<nolink>"; // disable parsing URLs in object names (STORM-358)
str_sender += fromName;
str_sender += "</nolink>";
str_sender = fromName;
str_sender+=" ";
//append user name
//append sender name
if (mSourceType == CHAT_SOURCE_AGENT || mSourceType == CHAT_SOURCE_OBJECT)
{
LLStyle::Params style_params_name;
LLColor4 userNameColor = LLUIColorTable::instance().getColor("ChatToastAgentNameColor");
std::string href;
if (mSourceType == CHAT_SOURCE_AGENT)
{
href = LLSLURL("agent", mFromID, "about").getSLURLString();
}
else
{
href = LLSLURL("object", mFromID, "inspect").getSLURLString();
}
style_params_name.color(userNameColor);
@ -196,11 +232,16 @@ void LLNearbyChatToastPanel::init(LLSD& notification)
style_params_name.font.name(font_name);
style_params_name.font.size(font_style_size);
style_params_name.link_href = LLSLURL("agent",mFromID,"about").getSLURLString();
style_params_name.link_href = href;
style_params_name.is_link = true;
msg_text->appendText(str_sender, FALSE, style_params_name);
}
else
{
msg_text->appendText(str_sender, false);
}
}
//append text
@ -329,10 +370,7 @@ void LLNearbyChatToastPanel::draw()
LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon", false);
if(icon)
{
// icon->setDrawTooltip(mSourceType == CHAT_SOURCE_AGENT);
// [RLVa:KB] - Checked: 2010-04-200 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
icon->setDrawTooltip( (mShowIconTooltip) && (mSourceType == CHAT_SOURCE_AGENT) );
// [/RLVa:KB]
icon->setDrawTooltip(mSourceType == CHAT_SOURCE_AGENT);
if(mSourceType == CHAT_SOURCE_OBJECT)
icon->setValue(LLSD("OBJECT_Icon"));
else if(mSourceType == CHAT_SOURCE_SYSTEM)

View File

@ -0,0 +1,192 @@
/**
* @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 "llui.h"
// static
const std::string LLExternalEditor::sFilenameMarker = "%s";
// static
const std::string LLExternalEditor::sSetting = "ExternalEditor";
bool LLExternalEditor::setCommand(const std::string& env_var, const std::string& override)
{
std::string cmd = findCommand(env_var, override);
if (cmd.empty())
{
llwarns << "Empty editor command" << llendl;
return false;
}
// 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 false;
}
// Check executable for existence.
std::string bin_path = tokens[0];
if (!LLFile::isfile(bin_path))
{
llwarns << "Editor binary [" << bin_path << "] not found" << llendl;
return false;
}
// 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 true;
}
bool LLExternalEditor::run(const std::string& file_path)
{
std::string args = mArgs;
if (mProcess.getExecutable().empty() || args.empty())
{
llwarns << "Editor command not set" << llendl;
return false;
}
// 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;
}
// 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 (!LLUI::sSettingGroups["config"]->getString(sSetting).empty())
{
cmd = LLUI::sSettingGroups["config"]->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;
}

View File

@ -0,0 +1,91 @@
/**
* @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:
/**
* 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 Command if found, empty string otherwise.
*
* @see sSetting
*/
bool 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 true on success, false on error.
*/
bool run(const std::string& file_path);
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

View File

@ -36,6 +36,7 @@
// Internal utility
#include "lleventtimer.h"
#include "llexternaleditor.h"
#include "llrender.h"
#include "llsdutil.h"
#include "llxmltree.h"
@ -160,6 +161,8 @@ public:
DiffMap mDiffsMap; // map, of filename to pair of list of changed element paths and list of errors
private:
LLExternalEditor mExternalEditor;
// XUI elements for this floater
LLScrollListCtrl* mFileList; // scroll list control for file list
LLLineEditor* mEditorPathTextBox; // text field for path to editor executable
@ -185,7 +188,7 @@ private:
std::string mSavedDiffPath; // stored diff file path so closing this floater doesn't reset it
// Internal functionality
static void popupAndPrintWarning(std::string& warning); // pop up a warning
static void popupAndPrintWarning(const std::string& warning); // pop up a warning
std::string getLocalizedDirectory(); // build and return the path to the XUI directory for the currently-selected localization
void scanDiffFile(LLXmlTreeNode* file_node); // scan a given XML node for diff entries and highlight them in its associated file
void highlightChangedElements(); // look up the list of elements to highlight and highlight them in the current floater
@ -597,7 +600,7 @@ void LLFloaterUIPreview::onClose(bool app_quitting)
// Error handling (to avoid code repetition)
// *TODO: this is currently unlocalized. Add to alerts/notifications.xml, someday, maybe.
void LLFloaterUIPreview::popupAndPrintWarning(std::string& warning)
void LLFloaterUIPreview::popupAndPrintWarning(const std::string& warning)
{
llwarns << warning << llendl;
LLSD args;
@ -998,190 +1001,55 @@ void LLFloaterUIPreview::displayFloater(BOOL click, S32 ID, bool save)
// Respond to button click to edit currently-selected floater
void LLFloaterUIPreview::onClickEditFloater()
{
std::string file_name = mFileList->getSelectedItemLabel(1); // get the file name of the currently-selected floater
if(std::string("") == file_name) // if no item is selected
// Determine file to edit.
std::string file_path;
{
return; // ignore click
}
std::string path = getLocalizedDirectory() + file_name;
std::string file_name = mFileList->getSelectedItemLabel(1); // get the file name of the currently-selected floater
if (file_name.empty()) // if no item is selected
{
llwarns << "No file selected" << llendl;
return; // ignore click
}
file_path = getLocalizedDirectory() + file_name;
// stat file to see if it exists (some localized versions may not have it there are no diffs, and then we try to open an nonexistent file)
llstat dummy;
if(LLFile::stat(path.c_str(), &dummy)) // if the file does not exist
{
std::string warning = "No file for this floater exists in the selected localization. Opening the EN version instead.";
popupAndPrintWarning(warning);
path = get_xui_dir() + mDelim + "en" + mDelim + file_name; // open the en version instead, by default
// stat file to see if it exists (some localized versions may not have it there are no diffs, and then we try to open an nonexistent file)
llstat dummy;
if(LLFile::stat(file_path.c_str(), &dummy)) // if the file does not exist
{
popupAndPrintWarning("No file for this floater exists in the selected localization. Opening the EN version instead.");
file_path = get_xui_dir() + mDelim + "en" + mDelim + file_name; // open the en version instead, by default
}
}
// get executable path
const char* exe_path_char;
std::string path_in_textfield = mEditorPathTextBox->getText();
if(std::string("") != path_in_textfield) // if the text field is not emtpy, use its path
// Set the editor command.
std::string cmd_override;
{
exe_path_char = path_in_textfield.c_str();
}
else if (!LLUI::sSettingGroups["config"]->getString("XUIEditor").empty())
{
exe_path_char = LLUI::sSettingGroups["config"]->getString("XUIEditor").c_str();
}
else // otherwise use the path specified by the environment variable
{
exe_path_char = getenv("LL_XUI_EDITOR");
}
std::string bin = mEditorPathTextBox->getText();
if (!bin.empty())
{
// surround command with double quotes for the case if the path contains spaces
if (bin.find("\"") == std::string::npos)
{
bin = "\"" + bin + "\"";
}
// error check executable path
if(NULL == exe_path_char)
std::string args = mEditorArgsTextBox->getText();
cmd_override = bin + " " + args;
}
}
if (!mExternalEditor.setCommand("LL_XUI_EDITOR", cmd_override))
{
std::string warning = "Select an editor by setting the environment variable LL_XUI_EDITOR or specifying its path in the \"Editor Path\" field.";
std::string warning = "Select an editor by setting the environment variable LL_XUI_EDITOR "
"or the ExternalEditor setting or specifying its path in the \"Editor Path\" field.";
popupAndPrintWarning(warning);
return;
}
std::string exe_path = exe_path_char; // do this after error check, otherwise internal strlen call fails on bad char*
// remove any quotes; they're added back in later where necessary
int found_at;
while((found_at = exe_path.find("\"")) != -1 || (found_at = exe_path.find("'")) != -1)
// Run the editor.
if (!mExternalEditor.run(file_path))
{
exe_path.erase(found_at,1);
}
llstat s;
if(!LLFile::stat(exe_path.c_str(), &s)) // If the executable exists
{
// build paths and arguments
std::string quote = std::string("\"");
std::string args;
std::string custom_args = mEditorArgsTextBox->getText();
int position_of_file = custom_args.find(std::string("%FILE%"), 0); // prepare to replace %FILE% with actual file path
std::string first_part_of_args = "";
std::string second_part_of_args = "";
if(-1 == position_of_file) // default: Executable.exe File.xml
{
args = quote + path + quote; // execute the command Program.exe "File.xml"
}
else // use advanced command-line arguments, e.g. "Program.exe -safe File.xml" -windowed for "-safe %FILE% -windowed"
{
first_part_of_args = custom_args.substr(0,position_of_file); // get part of args before file name
second_part_of_args = custom_args.substr(position_of_file+6,custom_args.length()); // get part of args after file name
custom_args = first_part_of_args + std::string("\"") + path + std::string("\"") + second_part_of_args; // replace %FILE% with "<file path>" and put back together
args = custom_args; // and save in the variable that is actually used
}
// find directory in which executable resides by taking everything after last slash
int last_slash_position = exe_path.find_last_of(mDelim);
if(-1 == last_slash_position)
{
std::string warning = std::string("Unable to find a valid path to the specified executable for XUI XML editing: ") + exe_path;
popupAndPrintWarning(warning);
return;
}
std::string exe_dir = exe_path.substr(0,last_slash_position); // strip executable off, e.g. get "C:\Program Files\TextPad 5" (with or without trailing slash)
#if LL_WINDOWS
PROCESS_INFORMATION pinfo;
STARTUPINFOA sinfo;
memset(&sinfo, 0, sizeof(sinfo));
memset(&pinfo, 0, sizeof(pinfo));
std::string exe_name = exe_path.substr(last_slash_position+1);
args = quote + exe_name + quote + std::string(" ") + args; // and prepend the executable name, so we get 'Program.exe "Arg1"'
char *args2 = new char[args.size() + 1]; // Windows requires that the second parameter to CreateProcessA be a writable (non-const) string...
strcpy(args2, args.c_str());
// we don't want the current directory to be the executable directory, since the file path is now relative. By using
// NULL for the current directory instead of exe_dir.c_str(), the path to the target file will work.
if(!CreateProcessA(exe_path.c_str(), args2, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo))
{
// DWORD dwErr = GetLastError();
std::string warning = "Creating editor process failed!";
popupAndPrintWarning(warning);
}
else
{
// foo = pinfo.dwProcessId; // get your pid here if you want to use it later on
// sGatewayHandle = pinfo.hProcess;
CloseHandle(pinfo.hThread); // stops leaks - nothing else
}
delete[] args2;
#else // if !LL_WINDOWS
// This code was copied from the code to run SLVoice, with some modification; should work in UNIX (Mac/Darwin or Linux)
{
std::vector<std::string> arglist;
arglist.push_back(exe_path.c_str());
// 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(args, sep);
tokenizer::iterator token_iter;
BOOL inside_quotes = FALSE;
BOOL last_was_space = FALSE;
for(token_iter = tokens.begin(); token_iter != tokens.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)
{
arglist.back().append(std::string(" "));
last_was_space = TRUE;
}
}
else
{
std::string to_push = *token_iter;
if(last_was_space)
{
arglist.back().append(to_push);
last_was_space = FALSE;
}
else
{
arglist.push_back(to_push);
}
}
}
// create an argv vector for the child process
char **fakeargv = new char*[arglist.size() + 1];
int i;
for(i=0; i < arglist.size(); i++)
fakeargv[i] = const_cast<char*>(arglist[i].c_str());
fakeargv[i] = NULL;
fflush(NULL); // flush all buffers before the child inherits them
pid_t id = vfork();
if(id == 0)
{
// child
execv(exe_path.c_str(), fakeargv);
// If we reach this point, the exec failed.
// Use _exit() instead of exit() per the vfork man page.
std::string warning = "Creating editor process failed (vfork/execv)!";
popupAndPrintWarning(warning);
_exit(0);
}
// parent
delete[] fakeargv;
// sGatewayPID = id;
}
#endif // LL_WINDOWS
}
else
{
std::string warning = "Unable to find path to external XML editor for XUI preview tool";
popupAndPrintWarning(warning);
popupAndPrintWarning("Failed to run editor");
return;
}
}

View File

@ -733,8 +733,6 @@ void LLIMFloater::updateMessages()
if (messages.size())
{
// LLUIColor chat_color = LLUIColorTable::instance().getColor("IMChatColor");
LLSD chat_args;
chat_args["use_plain_text_chat_history"] = use_plain_text_chat_history;

View File

@ -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"
@ -118,6 +120,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
/// ---------------------------------------------------------------------------
@ -284,6 +334,7 @@ LLScriptEdCore::LLScriptEdCore(
const LLHandle<LLFloater>& 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)
@ -293,6 +344,7 @@ LLScriptEdCore::LLScriptEdCore(
mEditor( NULL ),
mLoadCallback( load_callback ),
mSaveCallback( save_callback ),
mEditCallback( edit_callback ),
mSearchReplaceCallback( search_replace_callback ),
mUserdata( userdata ),
mForceClose( FALSE ),
@ -332,6 +384,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();
@ -812,6 +865,13 @@ void LLScriptEdCore::doSave( BOOL close_after_save )
}
}
void LLScriptEdCore::onEditButtonClick()
{
if (mEditCallback)
{
mEditCallback(mUserdata);
}
}
void LLScriptEdCore::onBtnUndoChanges()
{
@ -952,6 +1012,7 @@ void* LLPreviewLSL::createScriptEdPanel(void* userdata)
self->getHandle(),
LLPreviewLSL::onLoad,
LLPreviewLSL::onSave,
NULL, // no edit callback
LLPreviewLSL::onSearchReplace,
self,
0);
@ -1420,6 +1481,7 @@ void* LLLiveLSLEditor::createScriptEdPanel(void* userdata)
self->getHandle(),
&LLLiveLSLEditor::onLoad,
&LLLiveLSLEditor::onSave,
&LLLiveLSLEditor::onEdit,
&LLLiveLSLEditor::onSearchReplace,
self,
0);
@ -1436,6 +1498,7 @@ LLLiveLSLEditor::LLLiveLSLEditor(const LLSD& key) :
mCloseAfterSave(FALSE),
mPendingUploads(0),
mIsModifiable(FALSE),
mLiveFile(NULL),
mIsNew(false)
{
mFactoryMap["script ed panel"] = LLCallbackMap(LLLiveLSLEditor::createScriptEdPanel, this);
@ -1461,6 +1524,7 @@ BOOL LLLiveLSLEditor::postBuild()
LLLiveLSLEditor::~LLLiveLSLEditor()
{
delete mLiveFile;
}
// virtual
@ -1642,38 +1706,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)
{
@ -1842,9 +1907,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)
{
@ -1894,29 +1958,19 @@ void LLLiveLSLEditor::saveIfNeeded()
mItem->setAssetUUID(asset_id);
mItem->setTransactionID(tid);
// write out the data, and store it in the asset database
LLFILE* fp = LLFile::fopen(filename, "wb");
if(!fp)
writeToFile(filename);
if (sync)
{
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;
// 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);
}
}
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);
fp = NULL;
// save it out to asset server
std::string url = object->getRegion()->getCapability("UpdateScriptTask");
@ -1933,6 +1987,73 @@ void LLLiveLSLEditor::saveIfNeeded()
}
}
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()
{
return std::string(LLFile::tmpdir()) + "sl_script_" + mObjectUUID.asString() + ".lsl";
}
void LLLiveLSLEditor::uploadAssetViaCaps(const std::string& url,
const std::string& filename,
const LLUUID& task_id,
@ -2164,6 +2285,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**)
{

View File

@ -35,6 +35,7 @@
#include "lliconctrl.h"
#include "llframetimer.h"
class LLLiveLSLFile;
class LLMessageSystem;
class LLTextEditor;
class LLButton;
@ -62,6 +63,7 @@ public:
const LLHandle<LLFloater>& floater_handle,
void (*load_callback)(void* userdata),
void (*save_callback)(void* userdata, BOOL close_after_save),
void (*edit_callback)(void*),
void (*search_replace_callback)(void* userdata),
void* userdata,
S32 bottom_pad = 0); // pad below bottom row of buttons
@ -80,6 +82,8 @@ public:
bool handleSaveChangesDialog(const LLSD& notification, const LLSD& response);
bool handleReloadFromServerDialog(const LLSD& notification, const LLSD& response);
void onEditButtonClick();
static void onCheckLock(LLUICtrl*, void*);
static void onHelpComboCommit(LLUICtrl* ctrl, void* userdata);
static void onClickBack(void* userdata);
@ -114,6 +118,7 @@ private:
LLTextEditor* mEditor;
void (*mLoadCallback)(void* userdata);
void (*mSaveCallback)(void* userdata, BOOL close_after_save);
void (*mEditCallback)(void* userdata);
void (*mSearchReplaceCallback) (void* userdata);
void* mUserdata;
LLComboBox *mFunctions;
@ -179,6 +184,7 @@ protected:
// Used to view and edit an LSL that is attached to an object.
class LLLiveLSLEditor : public LLPreview
{
friend class LLLiveLSLFile;
public:
LLLiveLSLEditor(const LLSD& key);
~LLLiveLSLEditor();
@ -202,7 +208,10 @@ private:
virtual void loadAsset();
void loadAsset(BOOL is_new);
void saveIfNeeded();
void saveIfNeeded(bool sync = true);
void openExternalEditor();
std::string getTmpFileName();
bool writeToFile(const std::string& filename);
void uploadAssetViaCaps(const std::string& url,
const std::string& filename,
const LLUUID& task_id,
@ -218,6 +227,7 @@ private:
static void onSearchReplace(void* userdata);
static void onLoad(void* userdata);
static void onSave(void* userdata, BOOL close_after_save);
static void onEdit(void* userdata);
static void onLoadComplete(LLVFS *vfs, const LLUUID& asset_uuid,
LLAssetType::EType type,
@ -227,7 +237,7 @@ private:
static void onRunningCheckboxClicked(LLUICtrl*, void* userdata);
static void onReset(void* userdata);
// void loadScriptText(const std::string& filename); // unused
bool loadScriptText(const std::string& filename);
void loadScriptText(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type);
static void onErrorList(LLUICtrl*, void* user_data);
@ -253,6 +263,7 @@ private:
LLCheckBoxCtrl* mMonoCheckbox;
BOOL mIsModifiable;
LLLiveLSLFile* mLiveFile;
};
#endif // LL_LLPREVIEWSCRIPT_H

View File

@ -399,9 +399,6 @@
<color
name="HighlightParentColor"
value="0.67 0.83 0.96 1" />
<color
name="IMChatColor"
reference="LtGray" />
<color
name="IMHistoryBgColor"
reference="Unused?" />
@ -766,9 +763,6 @@
<color
name="SysWellItemSelected"
value="0.3 0.3 0.3 1.0" />
<color
name="ChatToastAgentNameColor"
reference="EmphasisColor" />
<color
name="ColorSwatchBorderColor"
value="0.45098 0.517647 0.607843 1"/>

View File

@ -359,6 +359,18 @@
<menu_item_check.on_check
control="NavBarShowParcelProperties" />
</menu_item_check>
<menu_item_separator />
<menu_item_check
label="Advanced Menu"
name="Show Advanced Menu"
shortcut="control|alt|shift|D">
<on_check
function="CheckControl"
parameter="UseDebugMenus" />
<on_click
function="ToggleControl"
parameter="UseDebugMenus" />
</menu_item_check>
</menu>
<menu_item_separator/>
@ -1642,6 +1654,18 @@
<menu_item_call.on_click
function="View.DefaultUISize" />
</menu_item_call>
<!-- This second, alternative shortcut for Show Advanced Menu is for backward compatibility. The main shortcut has been changed so it's Linux-friendly, where the old shortcut is typically eaten by the window manager. -->
<menu_item_check
label="Show Advanced Menu - legacy shortcut"
name="Show Advanced Menu - legacy shortcut"
shortcut="control|alt|D">
<on_check
function="CheckControl"
parameter="UseDebugMenus" />
<on_click
function="ToggleControl"
parameter="UseDebugMenus" />
</menu_item_check>
<menu_item_separator/>
@ -1809,23 +1833,6 @@
<menu_item_call.on_click
function="View.ZoomOut" />
</menu_item_call>
<menu_item_separator
visible="false"/>
<!-- Made invisible to avoid a dissonance: menu item toggles the menu where it is located. EXT-8069.
Can't be removed, to keep shortcut workable.
-->
<menu_item_check
label="Show Advanced Menu"
name="Show Advanced Menu"
shortcut="control|alt|D"
visible="false">
<on_check
function="CheckControl"
parameter="UseDebugMenus" />
<on_click
function="ToggleControl"
parameter="UseDebugMenus" />
</menu_item_check>
</menu> <!--Shortcuts-->
<menu_item_separator/>
@ -1855,7 +1862,6 @@
function="ToggleControl"
parameter="QAMode" />
</menu_item_check>
</menu>
<menu
create_jump_keys="true"

View File

@ -113,22 +113,22 @@
</text>
<color_swatch
can_apply_immediately="true"
color="LtGray"
color="EmphasisColor_35"
follows="left|top"
height="24"
label_height="0"
label_width="60"
layout="topleft"
left="360"
name="im"
name="objects"
top_pad="-15"
width="44">
<color_swatch.init_callback
function="Pref.getUIColor"
parameter="IMChatColor" />
parameter="ObjectChatColor" />
<color_swatch.commit_callback
function="Pref.applyUIColor"
parameter="IMChatColor" />
parameter="ObjectChatColor" />
</color_swatch>
<text
type="string"
@ -141,7 +141,7 @@
name="text_box3"
top_delta="5"
width="95">
IM
Objects
</text>
<color_swatch
can_apply_immediately="true"
@ -206,37 +206,6 @@
width="95">
Errors
</text>
<color_swatch
can_apply_immediately="true"
color="EmphasisColor_35"
follows="left|top"
height="24"
label_height="0"
layout="topleft"
left="360"
name="objects"
top_pad="-15"
width="44" >
<color_swatch.init_callback
function="Pref.getUIColor"
parameter="ObjectChatColor" />
<color_swatch.commit_callback
function="Pref.applyUIColor"
parameter="ObjectChatColor" />
</color_swatch>
<text
type="string"
length="1"
follows="left|top"
height="10"
layout="topleft"
left_pad="5"
mouse_opaque="false"
name="text_box6"
top_delta="5"
width="95">
Objects
</text>
<color_swatch
can_apply_immediately="true"
color="LtYellow"
@ -305,7 +274,7 @@
left="30"
height="12"
name="bubble_chat"
top_pad="28"
top_pad="20"
width="120"
>
Bubble chat:
@ -336,11 +305,58 @@
height="16"
increment="0.05"
initial_value="1"
label="Opacity"
label="Opacity:"
layout="topleft"
left_pad="15"
label_width="56"
left_pad="10"
label_width="70"
name="bubble_chat_opacity"
top_delta = "6"
width="347" />
width="378" />
<text
follows="left|top"
layout="topleft"
left="30"
height="12"
name="bubble_chat"
top_pad="15"
width="120"
>
Floater Opacity:
</text>
<slider
can_edit_text="false"
control_name="ActiveFloaterTransparency"
decimal_digits="2"
follows="left|top"
height="16"
increment="0.01"
initial_value="0.8"
layout="topleft"
label_width="115"
label="Active :"
left="50"
max_val="1.00"
min_val="0.00"
name="active"
show_text="true"
top_pad="5"
width="415" />
<slider
can_edit_text="false"
control_name="InactiveFloaterTransparency"
decimal_digits="2"
follows="left|top"
height="16"
increment="0.01"
initial_value="0.5"
layout="topleft"
label_width="115"
label="Inctive :"
left="50"
max_val="1.00"
min_val="0.00"
name="active"
show_text="true"
top_pad="5"
width="415" />
</panel>

View File

@ -179,4 +179,13 @@
right="487"
name="Save_btn"
width="81" />
<button
follows="right|bottom"
height="23"
label="Edit..."
layout="topleft"
top_pad="-23"
right="400"
name="Edit_btn"
width="81" />
</panel>

61
scripts/md5check.py Executable file
View File

@ -0,0 +1,61 @@
#!/usr/bin/python
"""\
@file md5check.py
@brief Replacement for message template compatibility verifier.
$LicenseInfo:firstyear=20i10&license=viewergpl$
Copyright (c) 2010, Linden Research, Inc.
Second Life Viewer Source Code
The source code in this file ("Source Code") is provided by Linden Lab
to you under the terms of the GNU General Public License, version 2.0
("GPL"), unless you have obtained a separate licensing agreement
("Other License"), formally executed by you and Linden Lab. Terms of
the GPL can be found in doc/GPL-license.txt in this distribution, or
online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
There are special exceptions to the terms and conditions of the GPL as
it is applied to this Source Code. View the full text of the exception
in the file doc/FLOSS-exception.txt in this software distribution, or
online at
http://secondlifegrid.net/programs/open_source/licensing/flossexception
By copying, modifying or distributing this software, you acknowledge
that you have read and understood your obligations described above,
and agree to abide by those obligations.
ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
COMPLETENESS OR PERFORMANCE.
$/LicenseInfo$
"""
import sys
import hashlib
if len(sys.argv) != 3:
print """Usage: %s --create|<hash-digest> <file>
Creates an md5sum hash digest of the specified file content
and compares it with the given hash digest.
If --create is used instead of a hash digest, it will simply
print out the hash digest of specified file content.
""" % sys.argv[0]
sys.exit(1)
if sys.argv[2] == '-':
fh = sys.stdin
filename = "<stdin>"
else:
filename = sys.argv[2]
fh = open(filename)
hexdigest = hashlib.md5(fh.read()).hexdigest()
if sys.argv[1] == '--create':
print hexdigest
elif hexdigest == sys.argv[1]:
print "md5sum check passed:", filename
else:
print "md5sum check FAILED:", filename
sys.exit(1)