From 057da807ac55f9b0583ff334cd12b3568ab81a18 Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Fri, 20 Jan 2012 13:51:46 -0800 Subject: removed LLXUIXML library moved LLInitParam, and LLRegistry to llcommon moved LLUIColor, LLTrans, and LLXUIParser to llui reviewed by Nat --- indra/llui/CMakeLists.txt | 8 +- indra/llui/lltrans.cpp | 295 ++++++ indra/llui/lltrans.h | 133 +++ indra/llui/lluicolor.cpp | 87 ++ indra/llui/lluicolor.h | 71 ++ indra/llui/llxuiparser.cpp | 1756 ++++++++++++++++++++++++++++++++++ indra/llui/llxuiparser.h | 242 +++++ indra/llui/tests/llurlentry_stub.cpp | 22 - indra/llui/tests/llurlentry_test.cpp | 15 - indra/llui/tests/llurlmatch_test.cpp | 34 - 10 files changed, 2590 insertions(+), 73 deletions(-) create mode 100644 indra/llui/lltrans.cpp create mode 100644 indra/llui/lltrans.h create mode 100644 indra/llui/lluicolor.cpp create mode 100644 indra/llui/lluicolor.h create mode 100644 indra/llui/llxuiparser.cpp create mode 100644 indra/llui/llxuiparser.h (limited to 'indra/llui') diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 772f173f17..9226f36e73 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -12,7 +12,6 @@ include(LLRender) include(LLWindow) include(LLVFS) include(LLXML) -include(LLXUIXML) include_directories( ${LLCOMMON_INCLUDE_DIRS} @@ -24,7 +23,6 @@ include_directories( ${LLWINDOW_INCLUDE_DIRS} ${LLVFS_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} - ${LLXUIXML_INCLUDE_DIRS} ) set(llui_SOURCE_FILES @@ -100,11 +98,13 @@ set(llui_SOURCE_FILES lltextutil.cpp lltextvalidate.cpp lltimectrl.cpp + lltrans.cpp lltransutil.cpp lltoggleablemenu.cpp lltoolbar.cpp lltooltip.cpp llui.cpp + lluicolor.cpp lluicolortable.cpp lluictrl.cpp lluictrlfactory.cpp @@ -121,6 +121,7 @@ set(llui_SOURCE_FILES llview.cpp llviewquery.cpp llwindowshade.cpp + llxuiparser.cpp ) set(llui_HEADER_FILES @@ -208,6 +209,7 @@ set(llui_HEADER_FILES lltoggleablemenu.h lltoolbar.h lltooltip.h + lltrans.h lltransutil.h lluicolortable.h lluiconstants.h @@ -215,6 +217,7 @@ set(llui_HEADER_FILES lluictrl.h lluifwd.h llui.h + lluicolor.h lluiimage.h lluistring.h llundo.h @@ -228,6 +231,7 @@ set(llui_HEADER_FILES llview.h llviewquery.h llwindowshade.h + llxuiparser.h ) set_source_files_properties(${llui_HEADER_FILES} diff --git a/indra/llui/lltrans.cpp b/indra/llui/lltrans.cpp new file mode 100644 index 0000000000..5388069c24 --- /dev/null +++ b/indra/llui/lltrans.cpp @@ -0,0 +1,295 @@ +/** + * @file lltrans.cpp + * @brief LLTrans implementation + * + * $LicenseInfo:firstyear=2000&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 "linden_common.h" + +#include "lltrans.h" + +#include "llfasttimer.h" // for call count statistics +#include "llxuiparser.h" +#include "llsd.h" +#include "llxmlnode.h" + +#include + +LLTrans::template_map_t LLTrans::sStringTemplates; +LLStringUtil::format_map_t LLTrans::sDefaultArgs; + +struct StringDef : public LLInitParam::Block +{ + Mandatory name; + Mandatory value; + + StringDef() + : name("name"), + value("value") + {} +}; + +struct StringTable : public LLInitParam::Block +{ + Multiple strings; + StringTable() + : strings("string") + {} +}; + +//static +bool LLTrans::parseStrings(LLXMLNodePtr &root, const std::set& default_args) +{ + std::string xml_filename = "(strings file)"; + if (!root->hasName("strings")) + { + llerrs << "Invalid root node name in " << xml_filename + << ": was " << root->getName() << ", expected \"strings\"" << llendl; + } + + StringTable string_table; + LLXUIParser parser; + parser.readXUI(root, string_table, xml_filename); + + if (!string_table.validateBlock()) + { + llerrs << "Problem reading strings: " << xml_filename << llendl; + return false; + } + + sStringTemplates.clear(); + sDefaultArgs.clear(); + + for(LLInitParam::ParamIterator::const_iterator it = string_table.strings.begin(); + it != string_table.strings.end(); + ++it) + { + LLTransTemplate xml_template(it->name, it->value); + sStringTemplates[xml_template.mName] = xml_template; + + std::set::const_iterator iter = default_args.find(xml_template.mName); + if (iter != default_args.end()) + { + std::string name = *iter; + if (name[0] != '[') + name = llformat("[%s]",name.c_str()); + sDefaultArgs[name] = xml_template.mText; + } + } + + return true; +} + + +//static +bool LLTrans::parseLanguageStrings(LLXMLNodePtr &root) +{ + std::string xml_filename = "(language strings file)"; + if (!root->hasName("strings")) + { + llerrs << "Invalid root node name in " << xml_filename + << ": was " << root->getName() << ", expected \"strings\"" << llendl; + } + + StringTable string_table; + LLXUIParser parser; + parser.readXUI(root, string_table, xml_filename); + + if (!string_table.validateBlock()) + { + llerrs << "Problem reading strings: " << xml_filename << llendl; + return false; + } + + for(LLInitParam::ParamIterator::const_iterator it = string_table.strings.begin(); + it != string_table.strings.end(); + ++it) + { + // share the same map with parseStrings() so we can search the strings using the same getString() function.- angela + LLTransTemplate xml_template(it->name, it->value); + sStringTemplates[xml_template.mName] = xml_template; + } + + return true; +} + + + +static LLFastTimer::DeclareTimer FTM_GET_TRANS("Translate string"); + +//static +std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::format_map_t& msg_args) +{ + // Don't care about time as much as call count. Make sure we're not + // calling LLTrans::getString() in an inner loop. JC + LLFastTimer timer(FTM_GET_TRANS); + + template_map_t::iterator iter = sStringTemplates.find(xml_desc); + if (iter != sStringTemplates.end()) + { + std::string text = iter->second.mText; + LLStringUtil::format_map_t args = sDefaultArgs; + args.insert(msg_args.begin(), msg_args.end()); + LLStringUtil::format(text, args); + + return text; + } + else + { + LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL; + return "MissingString("+xml_desc+")"; + } +} + +//static +std::string LLTrans::getString(const std::string &xml_desc, const LLSD& msg_args) +{ + // Don't care about time as much as call count. Make sure we're not + // calling LLTrans::getString() in an inner loop. JC + LLFastTimer timer(FTM_GET_TRANS); + + template_map_t::iterator iter = sStringTemplates.find(xml_desc); + if (iter != sStringTemplates.end()) + { + std::string text = iter->second.mText; + LLStringUtil::format(text, msg_args); + return text; + } + else + { + LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL; + return "MissingString("+xml_desc+")"; + } +} + +//static +bool LLTrans::findString(std::string &result, const std::string &xml_desc, const LLStringUtil::format_map_t& msg_args) +{ + LLFastTimer timer(FTM_GET_TRANS); + + template_map_t::iterator iter = sStringTemplates.find(xml_desc); + if (iter != sStringTemplates.end()) + { + std::string text = iter->second.mText; + LLStringUtil::format_map_t args = sDefaultArgs; + args.insert(msg_args.begin(), msg_args.end()); + LLStringUtil::format(text, args); + result = text; + return true; + } + else + { + LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL; + return false; + } +} + +//static +bool LLTrans::findString(std::string &result, const std::string &xml_desc, const LLSD& msg_args) +{ + LLFastTimer timer(FTM_GET_TRANS); + + template_map_t::iterator iter = sStringTemplates.find(xml_desc); + if (iter != sStringTemplates.end()) + { + std::string text = iter->second.mText; + LLStringUtil::format(text, msg_args); + result = text; + return true; + } + else + { + LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL; + return false; + } +} + +//static +std::string LLTrans::getCountString(const std::string& language, const std::string& xml_desc, S32 count) +{ + // Compute which string identifier to use + const char* form = ""; + if (language == "ru") // Russian + { + // From GNU ngettext() + // Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; + if (count % 10 == 1 + && count % 100 != 11) + { + // singular, "1 item" + form = "A"; + } + else if (count % 10 >= 2 + && count % 10 <= 4 + && (count % 100 < 10 || count % 100 >= 20) ) + { + // special case "2 items", "23 items", but not "13 items" + form = "B"; + } + else + { + // English-style plural, "5 items" + form = "C"; + } + } + else if (language == "fr" || language == "pt") // French, Brazilian Portuguese + { + // French and Portuguese treat zero as a singular "0 item" not "0 items" + if (count == 0 || count == 1) + { + form = "A"; + } + else + { + // English-style plural + form = "B"; + } + } + else // default + { + // languages like English with 2 forms, singular and plural + if (count == 1) + { + // "1 item" + form = "A"; + } + else + { + // "2 items", also use plural for "0 items" + form = "B"; + } + } + + // Translate that string + LLStringUtil::format_map_t args; + args["[COUNT]"] = llformat("%d", count); + + // Look up "AgeYearsB" or "AgeWeeksC" including the "form" + std::string key = llformat("%s%s", xml_desc.c_str(), form); + return getString(key, args); +} + +void LLTrans::setDefaultArg(const std::string& name, const std::string& value) +{ + sDefaultArgs[name] = value; +} diff --git a/indra/llui/lltrans.h b/indra/llui/lltrans.h new file mode 100644 index 0000000000..128b51d383 --- /dev/null +++ b/indra/llui/lltrans.h @@ -0,0 +1,133 @@ +/** + * @file lltrans.h + * @brief LLTrans definition + * + * $LicenseInfo:firstyear=2000&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_TRANS_H +#define LL_TRANS_H + +#include + +#include "llpointer.h" +#include "llstring.h" + +class LLXMLNode; + +class LLSD; + +/** + * @brief String template loaded from strings.xml + */ +class LLTransTemplate +{ +public: + LLTransTemplate(const std::string& name = LLStringUtil::null, const std::string& text = LLStringUtil::null) : mName(name), mText(text) {} + + std::string mName; + std::string mText; +}; + +/** + * @brief Localized strings class + * This class is used to retrieve translations of strings used to build larger ones, as well as + * strings with a general usage that don't belong to any specific floater. For example, + * "Owner:", "Retrieving..." used in the place of a not yet known name, etc. + */ +class LLTrans +{ +public: + LLTrans(); + + /** + * @brief Parses the xml root that holds the strings. Used once on startup +// *FIXME * @param xml_filename Filename to parse + * @param default_args Set of strings (expected to be in the file) to use as default replacement args, e.g. "SECOND_LIFE" + * @returns true if the file was parsed successfully, true if something went wrong + */ + static bool parseStrings(LLPointer & root, const std::set& default_args); + + static bool parseLanguageStrings(LLPointer & root); + + /** + * @brief Returns a translated string + * @param xml_desc String's description + * @param args A list of substrings to replace in the string + * @returns Translated string + */ + static std::string getString(const std::string &xml_desc, const LLStringUtil::format_map_t& args); + static std::string getString(const std::string &xml_desc, const LLSD& args); + static bool findString(std::string &result, const std::string &xml_desc, const LLStringUtil::format_map_t& args); + static bool findString(std::string &result, const std::string &xml_desc, const LLSD& args); + + // Returns translated string with [COUNT] replaced with a number, following + // special per-language logic for plural nouns. For example, some languages + // may have different plurals for 0, 1, 2 and > 2. + // See "AgeWeeksA", "AgeWeeksB", etc. in strings.xml for examples. + static std::string getCountString(const std::string& language, const std::string& xml_desc, S32 count); + + /** + * @brief Returns a translated string + * @param xml_desc String's description + * @returns Translated string + */ + static std::string getString(const std::string &xml_desc) + { + LLStringUtil::format_map_t empty; + return getString(xml_desc, empty); + } + + static bool findString(std::string &result, const std::string &xml_desc) + { + LLStringUtil::format_map_t empty; + return findString(result, xml_desc, empty); + } + + static std::string getKeyboardString(const char* keystring) + { + std::string key_str(keystring); + std::string trans_str; + return findString(trans_str, key_str) ? trans_str : key_str; + } + + // get the default args + static const LLStringUtil::format_map_t& getDefaultArgs() + { + return sDefaultArgs; + } + + static void setDefaultArg(const std::string& name, const std::string& value); + + // insert default args into an arg list + static void getArgs(LLStringUtil::format_map_t& args) + { + args.insert(sDefaultArgs.begin(), sDefaultArgs.end()); + } + +private: + typedef std::map template_map_t; + static template_map_t sStringTemplates; + static LLStringUtil::format_map_t sDefaultArgs; +}; + +#endif diff --git a/indra/llui/lluicolor.cpp b/indra/llui/lluicolor.cpp new file mode 100644 index 0000000000..f9bb80f8c5 --- /dev/null +++ b/indra/llui/lluicolor.cpp @@ -0,0 +1,87 @@ +/** + * @file lluicolor.cpp + * @brief brief LLUIColor class implementation file + * + * $LicenseInfo:firstyear=2009&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 "linden_common.h" + +#include "lluicolor.h" + +LLUIColor::LLUIColor() + :mColorPtr(NULL) +{ +} + + +LLUIColor::LLUIColor(const LLColor4& color) +: mColor(color), + mColorPtr(NULL) +{ +} + +LLUIColor::LLUIColor(const LLUIColor* color) +: mColorPtr(color) +{ +} + +void LLUIColor::set(const LLColor4& color) +{ + mColor = color; + mColorPtr = NULL; +} + +void LLUIColor::set(const LLUIColor* color) +{ + mColorPtr = color; +} + +const LLColor4& LLUIColor::get() const +{ + return (mColorPtr == NULL ? mColor : mColorPtr->get()); +} + +LLUIColor::operator const LLColor4& () const +{ + return get(); +} + +const LLColor4& LLUIColor::operator()() const +{ + return get(); +} + +bool LLUIColor::isReference() const +{ + return mColorPtr != NULL; +} + +namespace LLInitParam +{ + // used to detect equivalence with default values on export + bool ParamCompare::equals(const LLUIColor &a, const LLUIColor &b) + { + // do not detect value equivalence, treat pointers to colors as distinct from color values + return (a.mColorPtr == NULL && b.mColorPtr == NULL ? a.mColor == b.mColor : a.mColorPtr == b.mColorPtr); + } +} diff --git a/indra/llui/lluicolor.h b/indra/llui/lluicolor.h new file mode 100644 index 0000000000..97ebea854a --- /dev/null +++ b/indra/llui/lluicolor.h @@ -0,0 +1,71 @@ +/** + * @file lluicolor.h + * @brief brief LLUIColor class header file + * + * $LicenseInfo:firstyear=2009&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_LLUICOLOR_H_ +#define LL_LLUICOLOR_H_ + +#include "v4color.h" + +namespace LLInitParam +{ + template + struct ParamCompare; +} + +class LLUIColor +{ +public: + LLUIColor(); + LLUIColor(const LLColor4& color); + LLUIColor(const LLUIColor* color); + + void set(const LLColor4& color); + void set(const LLUIColor* color); + + const LLColor4& get() const; + + operator const LLColor4& () const; + const LLColor4& operator()() const; + + bool isReference() const; + +private: + friend struct LLInitParam::ParamCompare; + + const LLUIColor* mColorPtr; + LLColor4 mColor; +}; + +namespace LLInitParam +{ + template<> + struct ParamCompare + { + static bool equals(const LLUIColor& a, const LLUIColor& b); + }; +} + +#endif diff --git a/indra/llui/llxuiparser.cpp b/indra/llui/llxuiparser.cpp new file mode 100644 index 0000000000..afc76024d1 --- /dev/null +++ b/indra/llui/llxuiparser.cpp @@ -0,0 +1,1756 @@ +/** + * @file llxuiparser.cpp + * @brief Utility functions for handling XUI structures in XML + * + * $LicenseInfo:firstyear=2003&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 "linden_common.h" + +#include "llxuiparser.h" + +#include "llxmlnode.h" + +#ifdef LL_STANDALONE +#include +#else +#include "expat/expat.h" +#endif + +#include +#include +//#include +#include + +#include "lluicolor.h" + +using namespace BOOST_SPIRIT_CLASSIC_NS; + +const S32 MAX_STRING_ATTRIBUTE_SIZE = 40; + +static LLInitParam::Parser::parser_read_func_map_t sXSDReadFuncs; +static LLInitParam::Parser::parser_write_func_map_t sXSDWriteFuncs; +static LLInitParam::Parser::parser_inspect_func_map_t sXSDInspectFuncs; + +static LLInitParam::Parser::parser_read_func_map_t sSimpleXUIReadFuncs; +static LLInitParam::Parser::parser_write_func_map_t sSimpleXUIWriteFuncs; +static LLInitParam::Parser::parser_inspect_func_map_t sSimpleXUIInspectFuncs; + +const char* NO_VALUE_MARKER = "no_value"; + +const S32 LINE_NUMBER_HERE = 0; + +struct MaxOccursValues : public LLInitParam::TypeValuesHelper +{ + static void declareValues() + { + declare("unbounded", U32_MAX); + } +}; + +struct Occurs : public LLInitParam::Block +{ + Optional minOccurs; + Optional maxOccurs; + + Occurs() + : minOccurs("minOccurs", 0), + maxOccurs("maxOccurs", U32_MAX) + + {} +}; + + +typedef enum +{ + USE_REQUIRED, + USE_OPTIONAL +} EUse; + +namespace LLInitParam +{ + template<> + struct TypeValues : public TypeValuesHelper + { + static void declareValues() + { + declare("required", USE_REQUIRED); + declare("optional", USE_OPTIONAL); + } + }; +} + +struct Element; +struct Group; +struct Choice; +struct Sequence; +struct Any; + +struct Attribute : public LLInitParam::Block +{ + Mandatory name; + Mandatory type; + Mandatory use; + + Attribute() + : name("name"), + type("type"), + use("use") + {} +}; + +struct Any : public LLInitParam::Block +{ + Optional _namespace; + + Any() + : _namespace("namespace") + {} +}; + +struct All : public LLInitParam::Block +{ + Multiple< Lazy > elements; + + All() + : elements("element") + { + maxOccurs = 1; + } +}; + +struct Choice : public LLInitParam::ChoiceBlock +{ + Alternative< Lazy > element; + Alternative< Lazy > group; + Alternative< Lazy > choice; + Alternative< Lazy > sequence; + Alternative< Lazy > any; + + Choice() + : element("element"), + group("group"), + choice("choice"), + sequence("sequence"), + any("any") + {} + +}; + +struct Sequence : public LLInitParam::ChoiceBlock +{ + Alternative< Lazy > element; + Alternative< Lazy > group; + Alternative< Lazy > choice; + Alternative< Lazy > sequence; + Alternative< Lazy > any; +}; + +struct GroupContents : public LLInitParam::ChoiceBlock +{ + Alternative all; + Alternative choice; + Alternative sequence; + + GroupContents() + : all("all"), + choice("choice"), + sequence("sequence") + {} +}; + +struct Group : public LLInitParam::Block +{ + Optional name, + ref; + + Group() + : name("name"), + ref("ref") + {} +}; + +struct Restriction : public LLInitParam::Block +{ +}; + +struct Extension : public LLInitParam::Block +{ +}; + +struct SimpleContent : public LLInitParam::ChoiceBlock +{ + Alternative restriction; + Alternative extension; + + SimpleContent() + : restriction("restriction"), + extension("extension") + {} +}; + +struct SimpleType : public LLInitParam::Block +{ + // TODO +}; + +struct ComplexContent : public LLInitParam::Block +{ + Optional mixed; + + ComplexContent() + : mixed("mixed", true) + {} +}; + +struct ComplexTypeContents : public LLInitParam::ChoiceBlock +{ + Alternative simple_content; + Alternative complex_content; + Alternative group; + Alternative all; + Alternative choice; + Alternative sequence; + + ComplexTypeContents() + : simple_content("simpleContent"), + complex_content("complexContent"), + group("group"), + all("all"), + choice("choice"), + sequence("sequence") + {} +}; + +struct ComplexType : public LLInitParam::Block +{ + Optional name; + Optional mixed; + + Multiple attribute; + Multiple< Lazy > elements; + + ComplexType() + : name("name"), + attribute("xs:attribute"), + elements("xs:element"), + mixed("mixed") + { + } +}; + +struct ElementContents : public LLInitParam::ChoiceBlock +{ + Alternative simpleType; + Alternative complexType; + + ElementContents() + : simpleType("simpleType"), + complexType("complexType") + {} +}; + +struct Element : public LLInitParam::Block +{ + Optional name, + ref, + type; + + Element() + : name("xs:name"), + ref("xs:ref"), + type("xs:type") + {} +}; + +struct Schema : public LLInitParam::Block +{ +private: + Mandatory targetNamespace, + xmlns, + xs; + +public: + Optional attributeFormDefault, + elementFormDefault; + + Mandatory root_element; + + void setNameSpace(const std::string& ns) {targetNamespace = ns; xmlns = ns;} + + Schema(const std::string& ns = LLStringUtil::null) + : attributeFormDefault("attributeFormDefault"), + elementFormDefault("elementFormDefault"), + xs("xmlns:xs"), + targetNamespace("targetNamespace"), + xmlns("xmlns"), + root_element("xs:element") + { + attributeFormDefault = "unqualified"; + elementFormDefault = "qualified"; + xs = "http://www.w3.org/2001/XMLSchema"; + if (!ns.empty()) + { + setNameSpace(ns); + }; + } + +}; + +// +// LLXSDWriter +// +LLXSDWriter::LLXSDWriter() +: Parser(sXSDReadFuncs, sXSDWriteFuncs, sXSDInspectFuncs) +{ + registerInspectFunc(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:boolean", _1, _2, _3, _4)); + registerInspectFunc(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); + registerInspectFunc(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedByte", _1, _2, _3, _4)); + registerInspectFunc(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:signedByte", _1, _2, _3, _4)); + registerInspectFunc(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedShort", _1, _2, _3, _4)); + registerInspectFunc(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:signedShort", _1, _2, _3, _4)); + registerInspectFunc(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedInt", _1, _2, _3, _4)); + registerInspectFunc(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:integer", _1, _2, _3, _4)); + registerInspectFunc(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:float", _1, _2, _3, _4)); + registerInspectFunc(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:double", _1, _2, _3, _4)); + registerInspectFunc(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); + registerInspectFunc(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); + registerInspectFunc(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); + registerInspectFunc(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); +} + +void LLXSDWriter::writeXSD(const std::string& type_name, LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const std::string& xml_namespace) +{ + Schema schema(xml_namespace); + + schema.root_element.name = type_name; + Choice& choice = schema.root_element.complexType.choice; + + choice.minOccurs = 0; + choice.maxOccurs = "unbounded"; + + mSchemaNode = node; + //node->setName("xs:schema"); + //node->createChild("attributeFormDefault", true)->setStringValue("unqualified"); + //node->createChild("elementFormDefault", true)->setStringValue("qualified"); + //node->createChild("targetNamespace", true)->setStringValue(xml_namespace); + //node->createChild("xmlns:xs", true)->setStringValue("http://www.w3.org/2001/XMLSchema"); + //node->createChild("xmlns", true)->setStringValue(xml_namespace); + + //node = node->createChild("xs:complexType", false); + //node->createChild("name", true)->setStringValue(type_name); + //node->createChild("mixed", true)->setStringValue("true"); + + //mAttributeNode = node; + //mElementNode = node->createChild("xs:choice", false); + //mElementNode->createChild("minOccurs", true)->setStringValue("0"); + //mElementNode->createChild("maxOccurs", true)->setStringValue("unbounded"); + block.inspectBlock(*this); + + // duplicate element choices + LLXMLNodeList children; + mElementNode->getChildren("xs:element", children, FALSE); + for (LLXMLNodeList::iterator child_it = children.begin(); child_it != children.end(); ++child_it) + { + LLXMLNodePtr child_copy = child_it->second->deepCopy(); + std::string child_name; + child_copy->getAttributeString("name", child_name); + child_copy->setAttributeString("name", type_name + "." + child_name); + mElementNode->addChild(child_copy); + } + + LLXMLNodePtr element_declaration_node = mSchemaNode->createChild("xs:element", false); + element_declaration_node->createChild("name", true)->setStringValue(type_name); + element_declaration_node->createChild("type", true)->setStringValue(type_name); +} + +void LLXSDWriter::writeAttribute(const std::string& type, const Parser::name_stack_t& stack, S32 min_count, S32 max_count, const std::vector* possible_values) +{ + name_stack_t non_empty_names; + std::string attribute_name; + for (name_stack_t::const_iterator it = stack.begin(); + it != stack.end(); + ++it) + { + const std::string& name = it->first; + if (!name.empty()) + { + non_empty_names.push_back(*it); + } + } + + for (name_stack_t::const_iterator it = non_empty_names.begin(); + it != non_empty_names.end(); + ++it) + { + if (!attribute_name.empty()) + { + attribute_name += "."; + } + attribute_name += it->first; + } + + // only flag non-nested attributes as mandatory, nested attributes have variant syntax + // that can't be properly constrained in XSD + // e.g. vs + bool attribute_mandatory = min_count == 1 && max_count == 1 && non_empty_names.size() == 1; + + // don't bother supporting "Multiple" params as xml attributes + if (max_count <= 1) + { + // add compound attribute to root node + addAttributeToSchema(mAttributeNode, attribute_name, type, attribute_mandatory, possible_values); + } + + // now generated nested elements for compound attributes + if (non_empty_names.size() > 1 && !attribute_mandatory) + { + std::string element_name; + + // traverse all but last element, leaving that as an attribute name + name_stack_t::const_iterator end_it = non_empty_names.end(); + end_it--; + + for (name_stack_t::const_iterator it = non_empty_names.begin(); + it != end_it; + ++it) + { + if (it != non_empty_names.begin()) + { + element_name += "."; + } + element_name += it->first; + } + + std::string short_attribute_name = non_empty_names.back().first; + + LLXMLNodePtr complex_type_node; + + // find existing element node here, starting at tail of child list + if (mElementNode->mChildren.notNull()) + { + for(LLXMLNodePtr element = mElementNode->mChildren->tail; + element.notNull(); + element = element->mPrev) + { + std::string name; + if(element->getAttributeString("name", name) && name == element_name) + { + complex_type_node = element->mChildren->head; + break; + } + } + } + //create complex_type node + // + // + // + // + // + if(complex_type_node.isNull()) + { + complex_type_node = mElementNode->createChild("xs:element", false); + + complex_type_node->createChild("minOccurs", true)->setIntValue(min_count); + complex_type_node->createChild("maxOccurs", true)->setIntValue(max_count); + complex_type_node->createChild("name", true)->setStringValue(element_name); + complex_type_node = complex_type_node->createChild("xs:complexType", false); + } + + addAttributeToSchema(complex_type_node, short_attribute_name, type, false, possible_values); + } +} + +void LLXSDWriter::addAttributeToSchema(LLXMLNodePtr type_declaration_node, const std::string& attribute_name, const std::string& type, bool mandatory, const std::vector* possible_values) +{ + if (!attribute_name.empty()) + { + LLXMLNodePtr new_enum_type_node; + if (possible_values != NULL) + { + // custom attribute type, for example + // + // + // + // + // + // + new_enum_type_node = new LLXMLNode("xs:simpleType", false); + + LLXMLNodePtr restriction_node = new_enum_type_node->createChild("xs:restriction", false); + restriction_node->createChild("base", true)->setStringValue("xs:string"); + + for (std::vector::const_iterator it = possible_values->begin(); + it != possible_values->end(); + ++it) + { + LLXMLNodePtr enum_node = restriction_node->createChild("xs:enumeration", false); + enum_node->createChild("value", true)->setStringValue(*it); + } + } + + string_set_t& attributes_written = mAttributesWritten[type_declaration_node]; + + string_set_t::iterator found_it = attributes_written.lower_bound(attribute_name); + + // attribute not yet declared + if (found_it == attributes_written.end() || attributes_written.key_comp()(attribute_name, *found_it)) + { + attributes_written.insert(found_it, attribute_name); + + LLXMLNodePtr attribute_node = type_declaration_node->createChild("xs:attribute", false); + + // attribute name + attribute_node->createChild("name", true)->setStringValue(attribute_name); + + if (new_enum_type_node.notNull()) + { + attribute_node->addChild(new_enum_type_node); + } + else + { + // simple attribute type + attribute_node->createChild("type", true)->setStringValue(type); + } + + // required or optional + attribute_node->createChild("use", true)->setStringValue(mandatory ? "required" : "optional"); + } + // attribute exists...handle collision of same name attributes with potentially different types + else + { + LLXMLNodePtr attribute_declaration; + if (type_declaration_node.notNull()) + { + for(LLXMLNodePtr node = type_declaration_node->mChildren->tail; + node.notNull(); + node = node->mPrev) + { + std::string name; + if (node->getAttributeString("name", name) && name == attribute_name) + { + attribute_declaration = node; + break; + } + } + } + + bool new_type_is_enum = new_enum_type_node.notNull(); + bool existing_type_is_enum = !attribute_declaration->hasAttribute("type"); + + // either type is enum, revert to string in collision + // don't bother to check for enum equivalence + if (new_type_is_enum || existing_type_is_enum) + { + if (attribute_declaration->hasAttribute("type")) + { + attribute_declaration->setAttributeString("type", "xs:string"); + } + else + { + attribute_declaration->createChild("type", true)->setStringValue("xs:string"); + } + attribute_declaration->deleteChildren("xs:simpleType"); + } + else + { + // check for collision of different standard types + std::string existing_type; + attribute_declaration->getAttributeString("type", existing_type); + // if current type is not the same as the new type, revert to strnig + if (existing_type != type) + { + // ...than use most general type, string + attribute_declaration->setAttributeString("type", "string"); + } + } + } + } +} + +// +// LLXUIXSDWriter +// +void LLXUIXSDWriter::writeXSD(const std::string& type_name, const std::string& path, const LLInitParam::BaseBlock& block) +{ + std::string file_name(path); + file_name += type_name + ".xsd"; + LLXMLNodePtr root_nodep = new LLXMLNode(); + + LLXSDWriter::writeXSD(type_name, root_nodep, block, "http://www.lindenlab.com/xui"); + + // add includes for all possible children + const std::type_info* type = *LLWidgetTypeRegistry::instance().getValue(type_name); + const widget_registry_t* widget_registryp = LLChildRegistryRegistry::instance().getValue(type); + + // add choices for valid children + if (widget_registryp) + { + // add include declarations for all valid children + for (widget_registry_t::Registrar::registry_map_t::const_iterator it = widget_registryp->currentRegistrar().beginItems(); + it != widget_registryp->currentRegistrar().endItems(); + ++it) + { + std::string widget_name = it->first; + if (widget_name == type_name) + { + continue; + } + LLXMLNodePtr nodep = new LLXMLNode("xs:include", false); + nodep->createChild("schemaLocation", true)->setStringValue(widget_name + ".xsd"); + + // add to front of schema + mSchemaNode->addChild(nodep, mSchemaNode); + } + + for (widget_registry_t::Registrar::registry_map_t::const_iterator it = widget_registryp->currentRegistrar().beginItems(); + it != widget_registryp->currentRegistrar().endItems(); + ++it) + { + std::string widget_name = it->first; + // + LLXMLNodePtr widget_node = mElementNode->createChild("xs:element", false); + widget_node->createChild("name", true)->setStringValue(widget_name); + widget_node->createChild("type", true)->setStringValue(widget_name); + } + } + + LLFILE* xsd_file = LLFile::fopen(file_name.c_str(), "w"); + LLXMLNode::writeHeaderToFile(xsd_file); + root_nodep->writeToFile(xsd_file); + fclose(xsd_file); +} + +static LLInitParam::Parser::parser_read_func_map_t sXUIReadFuncs; +static LLInitParam::Parser::parser_write_func_map_t sXUIWriteFuncs; +static LLInitParam::Parser::parser_inspect_func_map_t sXUIInspectFuncs; + +// +// LLXUIParser +// +LLXUIParser::LLXUIParser() +: Parser(sXUIReadFuncs, sXUIWriteFuncs, sXUIInspectFuncs), + mCurReadDepth(0) +{ + if (sXUIReadFuncs.empty()) + { + registerParserFuncs(readFlag, writeFlag); + registerParserFuncs(readBoolValue, writeBoolValue); + registerParserFuncs(readStringValue, writeStringValue); + registerParserFuncs(readU8Value, writeU8Value); + registerParserFuncs(readS8Value, writeS8Value); + registerParserFuncs(readU16Value, writeU16Value); + registerParserFuncs(readS16Value, writeS16Value); + registerParserFuncs(readU32Value, writeU32Value); + registerParserFuncs(readS32Value, writeS32Value); + registerParserFuncs(readF32Value, writeF32Value); + registerParserFuncs(readF64Value, writeF64Value); + registerParserFuncs(readColor4Value, writeColor4Value); + registerParserFuncs(readUIColorValue, writeUIColorValue); + registerParserFuncs(readUUIDValue, writeUUIDValue); + registerParserFuncs(readSDValue, writeSDValue); + } +} + +static LLFastTimer::DeclareTimer FTM_PARSE_XUI("XUI Parsing"); +const LLXMLNodePtr DUMMY_NODE = new LLXMLNode(); + +void LLXUIParser::readXUI(LLXMLNodePtr node, LLInitParam::BaseBlock& block, const std::string& filename, bool silent) +{ + LLFastTimer timer(FTM_PARSE_XUI); + mNameStack.clear(); + mRootNodeName = node->getName()->mString; + mCurFileName = filename; + mCurReadDepth = 0; + setParseSilently(silent); + + if (node.isNull()) + { + parserWarning("Invalid node"); + } + else + { + readXUIImpl(node, block); + } +} + +bool LLXUIParser::readXUIImpl(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block) +{ + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("."); + + bool values_parsed = false; + bool silent = mCurReadDepth > 0; + + if (nodep->getFirstChild().isNull() + && nodep->mAttributes.empty() + && nodep->getSanitizedValue().empty()) + { + // empty node, just parse as flag + mCurReadNode = DUMMY_NODE; + return block.submitValue(mNameStack, *this, silent); + } + + // submit attributes for current node + values_parsed |= readAttributes(nodep, block); + + // treat text contents of xml node as "value" parameter + std::string text_contents = nodep->getSanitizedValue(); + if (!text_contents.empty()) + { + mCurReadNode = nodep; + mNameStack.push_back(std::make_pair(std::string("value"), true)); + // child nodes are not necessarily valid parameters (could be a child widget) + // so don't complain once we've recursed + if (!block.submitValue(mNameStack, *this, true)) + { + mNameStack.pop_back(); + block.submitValue(mNameStack, *this, silent); + } + else + { + mNameStack.pop_back(); + } + } + + // then traverse children + // child node must start with last name of parent node (our "scope") + // for example: "" + // which equates to the following nesting: + // button + // param + // nested_param1 + // nested_param2 + // nested_param3 + mCurReadDepth++; + for(LLXMLNodePtr childp = nodep->getFirstChild(); childp.notNull();) + { + std::string child_name(childp->getName()->mString); + S32 num_tokens_pushed = 0; + + // for non "dotted" child nodes check to see if child node maps to another widget type + // and if not, treat as a child element of the current node + // e.g. will interpret as "button.rect" + // since there is no widget named "rect" + if (child_name.find(".") == std::string::npos) + { + mNameStack.push_back(std::make_pair(child_name, true)); + num_tokens_pushed++; + } + else + { + // parse out "dotted" name into individual tokens + tokenizer name_tokens(child_name, sep); + + tokenizer::iterator name_token_it = name_tokens.begin(); + if(name_token_it == name_tokens.end()) + { + childp = childp->getNextSibling(); + continue; + } + + // check for proper nesting + if (mNameStack.empty()) + { + if (*name_token_it != mRootNodeName) + { + childp = childp->getNextSibling(); + continue; + } + } + else if(mNameStack.back().first != *name_token_it) + { + childp = childp->getNextSibling(); + continue; + } + + // now ignore first token + ++name_token_it; + + // copy remaining tokens on to our running token list + for(tokenizer::iterator token_to_push = name_token_it; token_to_push != name_tokens.end(); ++token_to_push) + { + mNameStack.push_back(std::make_pair(*token_to_push, true)); + num_tokens_pushed++; + } + } + + // recurse and visit children XML nodes + if(readXUIImpl(childp, block)) + { + // child node successfully parsed, remove from DOM + + values_parsed = true; + LLXMLNodePtr node_to_remove = childp; + childp = childp->getNextSibling(); + + nodep->deleteChild(node_to_remove); + } + else + { + childp = childp->getNextSibling(); + } + + while(num_tokens_pushed-- > 0) + { + mNameStack.pop_back(); + } + } + mCurReadDepth--; + return values_parsed; +} + +bool LLXUIParser::readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block) +{ + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("."); + + bool any_parsed = false; + bool silent = mCurReadDepth > 0; + + for(LLXMLAttribList::const_iterator attribute_it = nodep->mAttributes.begin(); + attribute_it != nodep->mAttributes.end(); + ++attribute_it) + { + S32 num_tokens_pushed = 0; + std::string attribute_name(attribute_it->first->mString); + mCurReadNode = attribute_it->second; + + tokenizer name_tokens(attribute_name, sep); + // copy remaining tokens on to our running token list + for(tokenizer::iterator token_to_push = name_tokens.begin(); token_to_push != name_tokens.end(); ++token_to_push) + { + mNameStack.push_back(std::make_pair(*token_to_push, true)); + num_tokens_pushed++; + } + + // child nodes are not necessarily valid attributes, so don't complain once we've recursed + any_parsed |= block.submitValue(mNameStack, *this, silent); + + while(num_tokens_pushed-- > 0) + { + mNameStack.pop_back(); + } + } + + return any_parsed; +} + +void LLXUIParser::writeXUI(LLXMLNodePtr node, const LLInitParam::BaseBlock &block, const LLInitParam::BaseBlock* diff_block) +{ + mWriteRootNode = node; + name_stack_t name_stack = Parser::name_stack_t(); + block.serializeBlock(*this, name_stack, diff_block); + mOutNodes.clear(); +} + +// go from a stack of names to a specific XML node +LLXMLNodePtr LLXUIParser::getNode(name_stack_t& stack) +{ + LLXMLNodePtr out_node = mWriteRootNode; + + name_stack_t::iterator next_it = stack.begin(); + for (name_stack_t::iterator it = stack.begin(); + it != stack.end(); + it = next_it) + { + ++next_it; + if (it->first.empty()) + { + it->second = false; + continue; + } + + out_nodes_t::iterator found_it = mOutNodes.find(it->first); + + // node with this name not yet written + if (found_it == mOutNodes.end() || it->second) + { + // make an attribute if we are the last element on the name stack + bool is_attribute = next_it == stack.end(); + LLXMLNodePtr new_node = new LLXMLNode(it->first.c_str(), is_attribute); + out_node->addChild(new_node); + mOutNodes[it->first] = new_node; + out_node = new_node; + it->second = false; + } + else + { + out_node = found_it->second; + } + } + + return (out_node == mWriteRootNode ? LLXMLNodePtr(NULL) : out_node); +} + +bool LLXUIParser::readFlag(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + return self.mCurReadNode == DUMMY_NODE; +} + +bool LLXUIParser::writeFlag(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + // just create node + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + return node.notNull(); +} + +bool LLXUIParser::readBoolValue(Parser& parser, void* val_ptr) +{ + S32 value; + LLXUIParser& self = static_cast(parser); + bool success = self.mCurReadNode->getBoolValue(1, &value); + *((bool*)val_ptr) = (value != FALSE); + return success; +} + +bool LLXUIParser::writeBoolValue(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setBoolValue(*((bool*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readStringValue(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + *((std::string*)val_ptr) = self.mCurReadNode->getSanitizedValue(); + return true; +} + +bool LLXUIParser::writeStringValue(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + const std::string* string_val = reinterpret_cast(val_ptr); + if (string_val->find('\n') != std::string::npos + || string_val->size() > MAX_STRING_ATTRIBUTE_SIZE) + { + // don't write strings with newlines into attributes + std::string attribute_name = node->getName()->mString; + LLXMLNodePtr parent_node = node->mParent; + parent_node->deleteChild(node); + // write results in text contents of node + if (attribute_name == "value") + { + // "value" is implicit, just write to parent + node = parent_node; + } + else + { + // create a child that is not an attribute, but with same name + node = parent_node->createChild(attribute_name.c_str(), false); + } + } + node->setStringValue(*string_val); + return true; + } + return false; +} + +bool LLXUIParser::readU8Value(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + return self.mCurReadNode->getByteValue(1, (U8*)val_ptr); +} + +bool LLXUIParser::writeU8Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setUnsignedValue(*((U8*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readS8Value(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + S32 value; + if(self.mCurReadNode->getIntValue(1, &value)) + { + *((S8*)val_ptr) = value; + return true; + } + return false; +} + +bool LLXUIParser::writeS8Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setIntValue(*((S8*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readU16Value(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + U32 value; + if(self.mCurReadNode->getUnsignedValue(1, &value)) + { + *((U16*)val_ptr) = value; + return true; + } + return false; +} + +bool LLXUIParser::writeU16Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setUnsignedValue(*((U16*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readS16Value(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + S32 value; + if(self.mCurReadNode->getIntValue(1, &value)) + { + *((S16*)val_ptr) = value; + return true; + } + return false; +} + +bool LLXUIParser::writeS16Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setIntValue(*((S16*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readU32Value(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + return self.mCurReadNode->getUnsignedValue(1, (U32*)val_ptr); +} + +bool LLXUIParser::writeU32Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setUnsignedValue(*((U32*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readS32Value(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + return self.mCurReadNode->getIntValue(1, (S32*)val_ptr); +} + +bool LLXUIParser::writeS32Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setIntValue(*((S32*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readF32Value(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + return self.mCurReadNode->getFloatValue(1, (F32*)val_ptr); +} + +bool LLXUIParser::writeF32Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setFloatValue(*((F32*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readF64Value(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + return self.mCurReadNode->getDoubleValue(1, (F64*)val_ptr); +} + +bool LLXUIParser::writeF64Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setDoubleValue(*((F64*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readColor4Value(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + LLColor4* colorp = (LLColor4*)val_ptr; + if(self.mCurReadNode->getFloatValue(4, colorp->mV) >= 3) + { + return true; + } + + return false; +} + +bool LLXUIParser::writeColor4Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + LLColor4 color = *((LLColor4*)val_ptr); + node->setFloatValue(4, color.mV); + return true; + } + return false; +} + +bool LLXUIParser::readUIColorValue(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + LLUIColor* param = (LLUIColor*)val_ptr; + LLColor4 color; + bool success = self.mCurReadNode->getFloatValue(4, color.mV) >= 3; + if (success) + { + param->set(color); + return true; + } + return false; +} + +bool LLXUIParser::writeUIColorValue(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + LLUIColor color = *((LLUIColor*)val_ptr); + //RN: don't write out the color that is represented by a function + // rely on param block exporting to get the reference to the color settings + if (color.isReference()) return false; + node->setFloatValue(4, color.get().mV); + return true; + } + return false; +} + +bool LLXUIParser::readUUIDValue(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + LLUUID temp_id; + // LLUUID::set is destructive, so use temporary value + if (temp_id.set(self.mCurReadNode->getSanitizedValue())) + { + *(LLUUID*)(val_ptr) = temp_id; + return true; + } + return false; +} + +bool LLXUIParser::writeUUIDValue(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setStringValue(((LLUUID*)val_ptr)->asString()); + return true; + } + return false; +} + +bool LLXUIParser::readSDValue(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + *((LLSD*)val_ptr) = LLSD(self.mCurReadNode->getSanitizedValue()); + return true; +} + +bool LLXUIParser::writeSDValue(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + std::string string_val = ((LLSD*)val_ptr)->asString(); + if (string_val.find('\n') != std::string::npos || string_val.size() > MAX_STRING_ATTRIBUTE_SIZE) + { + // don't write strings with newlines into attributes + std::string attribute_name = node->getName()->mString; + LLXMLNodePtr parent_node = node->mParent; + parent_node->deleteChild(node); + // write results in text contents of node + if (attribute_name == "value") + { + // "value" is implicit, just write to parent + node = parent_node; + } + else + { + node = parent_node->createChild(attribute_name.c_str(), false); + } + } + + node->setStringValue(string_val); + return true; + } + return false; +} + +/*virtual*/ std::string LLXUIParser::getCurrentElementName() +{ + std::string full_name; + for (name_stack_t::iterator it = mNameStack.begin(); + it != mNameStack.end(); + ++it) + { + full_name += it->first + "."; // build up dotted names: "button.param.nestedparam." + } + + return full_name; +} + +void LLXUIParser::parserWarning(const std::string& message) +{ +#ifdef LL_WINDOWS + // use Visual Studo friendly formatting of output message for easy access to originating xml + llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", mCurFileName.c_str(), mCurReadNode->getLineNumber(), message.c_str()).c_str()); + utf16str += '\n'; + OutputDebugString(utf16str.c_str()); +#else + Parser::parserWarning(message); +#endif +} + +void LLXUIParser::parserError(const std::string& message) +{ +#ifdef LL_WINDOWS + llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", mCurFileName.c_str(), mCurReadNode->getLineNumber(), message.c_str()).c_str()); + utf16str += '\n'; + OutputDebugString(utf16str.c_str()); +#else + Parser::parserError(message); +#endif +} + + +// +// LLSimpleXUIParser +// + +struct ScopedFile +{ + ScopedFile( const std::string& filename, const char* accessmode ) + { + mFile = LLFile::fopen(filename, accessmode); + } + + ~ScopedFile() + { + fclose(mFile); + mFile = NULL; + } + + S32 getRemainingBytes() + { + if (!isOpen()) return 0; + + S32 cur_pos = ftell(mFile); + fseek(mFile, 0L, SEEK_END); + S32 file_size = ftell(mFile); + fseek(mFile, cur_pos, SEEK_SET); + return file_size - cur_pos; + } + + bool isOpen() { return mFile != NULL; } + + LLFILE* mFile; +}; +LLSimpleXUIParser::LLSimpleXUIParser(LLSimpleXUIParser::element_start_callback_t element_cb) +: Parser(sSimpleXUIReadFuncs, sSimpleXUIWriteFuncs, sSimpleXUIInspectFuncs), + mCurReadDepth(0), + mElementCB(element_cb) +{ + if (sSimpleXUIReadFuncs.empty()) + { + registerParserFuncs(readFlag); + registerParserFuncs(readBoolValue); + registerParserFuncs(readStringValue); + registerParserFuncs(readU8Value); + registerParserFuncs(readS8Value); + registerParserFuncs(readU16Value); + registerParserFuncs(readS16Value); + registerParserFuncs(readU32Value); + registerParserFuncs(readS32Value); + registerParserFuncs(readF32Value); + registerParserFuncs(readF64Value); + registerParserFuncs(readColor4Value); + registerParserFuncs(readUIColorValue); + registerParserFuncs(readUUIDValue); + registerParserFuncs(readSDValue); + } +} + +LLSimpleXUIParser::~LLSimpleXUIParser() +{ +} + + +bool LLSimpleXUIParser::readXUI(const std::string& filename, LLInitParam::BaseBlock& block, bool silent) +{ + LLFastTimer timer(FTM_PARSE_XUI); + + mParser = XML_ParserCreate(NULL); + XML_SetUserData(mParser, this); + XML_SetElementHandler( mParser, startElementHandler, endElementHandler); + XML_SetCharacterDataHandler( mParser, characterDataHandler); + + mOutputStack.push_back(std::make_pair(&block, 0)); + mNameStack.clear(); + mCurFileName = filename; + mCurReadDepth = 0; + setParseSilently(silent); + + ScopedFile file(filename, "rb"); + if( !file.isOpen() ) + { + LL_WARNS("ReadXUI") << "Unable to open file " << filename << LL_ENDL; + XML_ParserFree( mParser ); + return false; + } + + S32 bytes_read = 0; + + S32 buffer_size = file.getRemainingBytes(); + void* buffer = XML_GetBuffer(mParser, buffer_size); + if( !buffer ) + { + LL_WARNS("ReadXUI") << "Unable to allocate XML buffer while reading file " << filename << LL_ENDL; + XML_ParserFree( mParser ); + return false; + } + + bytes_read = (S32)fread(buffer, 1, buffer_size, file.mFile); + if( bytes_read <= 0 ) + { + LL_WARNS("ReadXUI") << "Error while reading file " << filename << LL_ENDL; + XML_ParserFree( mParser ); + return false; + } + + mEmptyLeafNode.push_back(false); + + if( !XML_ParseBuffer(mParser, bytes_read, TRUE ) ) + { + LL_WARNS("ReadXUI") << "Error while parsing file " << filename << LL_ENDL; + XML_ParserFree( mParser ); + return false; + } + + mEmptyLeafNode.pop_back(); + + XML_ParserFree( mParser ); + return true; +} + +void LLSimpleXUIParser::startElementHandler(void *userData, const char *name, const char **atts) +{ + LLSimpleXUIParser* self = reinterpret_cast(userData); + self->startElement(name, atts); +} + +void LLSimpleXUIParser::endElementHandler(void *userData, const char *name) +{ + LLSimpleXUIParser* self = reinterpret_cast(userData); + self->endElement(name); +} + +void LLSimpleXUIParser::characterDataHandler(void *userData, const char *s, int len) +{ + LLSimpleXUIParser* self = reinterpret_cast(userData); + self->characterData(s, len); +} + +void LLSimpleXUIParser::characterData(const char *s, int len) +{ + mTextContents += std::string(s, len); +} + +void LLSimpleXUIParser::startElement(const char *name, const char **atts) +{ + processText(); + + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("."); + + if (mElementCB) + { + LLInitParam::BaseBlock* blockp = mElementCB(*this, name); + if (blockp) + { + mOutputStack.push_back(std::make_pair(blockp, 0)); + } + } + + mOutputStack.back().second++; + S32 num_tokens_pushed = 0; + std::string child_name(name); + + if (mOutputStack.back().second == 1) + { // root node for this block + mScope.push_back(child_name); + } + else + { // compound attribute + if (child_name.find(".") == std::string::npos) + { + mNameStack.push_back(std::make_pair(child_name, true)); + num_tokens_pushed++; + mScope.push_back(child_name); + } + else + { + // parse out "dotted" name into individual tokens + tokenizer name_tokens(child_name, sep); + + tokenizer::iterator name_token_it = name_tokens.begin(); + if(name_token_it == name_tokens.end()) + { + return; + } + + // check for proper nesting + if(!mScope.empty() && *name_token_it != mScope.back()) + { + return; + } + + // now ignore first token + ++name_token_it; + + // copy remaining tokens on to our running token list + for(tokenizer::iterator token_to_push = name_token_it; token_to_push != name_tokens.end(); ++token_to_push) + { + mNameStack.push_back(std::make_pair(*token_to_push, true)); + num_tokens_pushed++; + } + mScope.push_back(mNameStack.back().first); + } + } + + // parent node is not empty + mEmptyLeafNode.back() = false; + // we are empty if we have no attributes + mEmptyLeafNode.push_back(atts[0] == NULL); + + mTokenSizeStack.push_back(num_tokens_pushed); + readAttributes(atts); + +} + +void LLSimpleXUIParser::endElement(const char *name) +{ + bool has_text = processText(); + + // no text, attributes, or children + if (!has_text && mEmptyLeafNode.back()) + { + // submit this as a valueless name (even though there might be text contents we haven't seen yet) + mCurAttributeValueBegin = NO_VALUE_MARKER; + mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently); + } + + if (--mOutputStack.back().second == 0) + { + if (mOutputStack.empty()) + { + LL_ERRS("ReadXUI") << "Parameter block output stack popped while empty." << LL_ENDL; + } + mOutputStack.pop_back(); + } + + S32 num_tokens_to_pop = mTokenSizeStack.back(); + mTokenSizeStack.pop_back(); + while(num_tokens_to_pop-- > 0) + { + mNameStack.pop_back(); + } + mScope.pop_back(); + mEmptyLeafNode.pop_back(); +} + +bool LLSimpleXUIParser::readAttributes(const char **atts) +{ + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("."); + + bool any_parsed = false; + for(S32 i = 0; atts[i] && atts[i+1]; i += 2 ) + { + std::string attribute_name(atts[i]); + mCurAttributeValueBegin = atts[i+1]; + + S32 num_tokens_pushed = 0; + tokenizer name_tokens(attribute_name, sep); + // copy remaining tokens on to our running token list + for(tokenizer::iterator token_to_push = name_tokens.begin(); token_to_push != name_tokens.end(); ++token_to_push) + { + mNameStack.push_back(std::make_pair(*token_to_push, true)); + num_tokens_pushed++; + } + + // child nodes are not necessarily valid attributes, so don't complain once we've recursed + any_parsed |= mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently); + + while(num_tokens_pushed-- > 0) + { + mNameStack.pop_back(); + } + } + return any_parsed; +} + +bool LLSimpleXUIParser::processText() +{ + if (!mTextContents.empty()) + { + LLStringUtil::trim(mTextContents); + if (!mTextContents.empty()) + { + mNameStack.push_back(std::make_pair(std::string("value"), true)); + mCurAttributeValueBegin = mTextContents.c_str(); + mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently); + mNameStack.pop_back(); + } + mTextContents.clear(); + return true; + } + return false; +} + +/*virtual*/ std::string LLSimpleXUIParser::getCurrentElementName() +{ + std::string full_name; + for (name_stack_t::iterator it = mNameStack.begin(); + it != mNameStack.end(); + ++it) + { + full_name += it->first + "."; // build up dotted names: "button.param.nestedparam." + } + + return full_name; +} + +void LLSimpleXUIParser::parserWarning(const std::string& message) +{ +#ifdef LL_WINDOWS + // use Visual Studo friendly formatting of output message for easy access to originating xml + llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", mCurFileName.c_str(), LINE_NUMBER_HERE, message.c_str()).c_str()); + utf16str += '\n'; + OutputDebugString(utf16str.c_str()); +#else + Parser::parserWarning(message); +#endif +} + +void LLSimpleXUIParser::parserError(const std::string& message) +{ +#ifdef LL_WINDOWS + llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", mCurFileName.c_str(), LINE_NUMBER_HERE, message.c_str()).c_str()); + utf16str += '\n'; + OutputDebugString(utf16str.c_str()); +#else + Parser::parserError(message); +#endif +} + +bool LLSimpleXUIParser::readFlag(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + return self.mCurAttributeValueBegin == NO_VALUE_MARKER; +} + +bool LLSimpleXUIParser::readBoolValue(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + if (!strcmp(self.mCurAttributeValueBegin, "true")) + { + *((bool*)val_ptr) = true; + return true; + } + else if (!strcmp(self.mCurAttributeValueBegin, "false")) + { + *((bool*)val_ptr) = false; + return true; + } + + return false; +} + +bool LLSimpleXUIParser::readStringValue(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + *((std::string*)val_ptr) = self.mCurAttributeValueBegin; + return true; +} + +bool LLSimpleXUIParser::readU8Value(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U8*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readS8Value(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S8*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readU16Value(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U16*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readS16Value(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S16*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readU32Value(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U32*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readS32Value(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S32*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readF32Value(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F32*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readF64Value(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F64*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readColor4Value(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + LLColor4 value; + + if (parse(self.mCurAttributeValueBegin, real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full) + { + *(LLColor4*)(val_ptr) = value; + return true; + } + return false; +} + +bool LLSimpleXUIParser::readUIColorValue(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + LLColor4 value; + LLUIColor* colorp = (LLUIColor*)val_ptr; + + if (parse(self.mCurAttributeValueBegin, real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full) + { + colorp->set(value); + return true; + } + return false; +} + +bool LLSimpleXUIParser::readUUIDValue(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + LLUUID temp_id; + // LLUUID::set is destructive, so use temporary value + if (temp_id.set(std::string(self.mCurAttributeValueBegin))) + { + *(LLUUID*)(val_ptr) = temp_id; + return true; + } + return false; +} + +bool LLSimpleXUIParser::readSDValue(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + *((LLSD*)val_ptr) = LLSD(self.mCurAttributeValueBegin); + return true; +} diff --git a/indra/llui/llxuiparser.h b/indra/llui/llxuiparser.h new file mode 100644 index 0000000000..d7cd256967 --- /dev/null +++ b/indra/llui/llxuiparser.h @@ -0,0 +1,242 @@ +/** + * @file llxuiparser.h + * @brief Utility functions for handling XUI structures in XML + * + * $LicenseInfo:firstyear=2003&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 LLXUIPARSER_H +#define LLXUIPARSER_H + +#include "llinitparam.h" +#include "llregistry.h" +#include "llpointer.h" + +#include +#include +#include +#include + + + +class LLView; + + +typedef LLPointer LLXMLNodePtr; + + +// lookup widget type by name +class LLWidgetTypeRegistry +: public LLRegistrySingleton +{}; + + +// global static instance for registering all widget types +typedef boost::function LLWidgetCreatorFunc; + +typedef LLRegistry widget_registry_t; + +class LLChildRegistryRegistry +: public LLRegistrySingleton +{}; + + + +class LLXSDWriter : public LLInitParam::Parser +{ + LOG_CLASS(LLXSDWriter); +public: + void writeXSD(const std::string& name, LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const std::string& xml_namespace); + + /*virtual*/ std::string getCurrentElementName() { return LLStringUtil::null; } + + LLXSDWriter(); + +protected: + void writeAttribute(const std::string& type, const Parser::name_stack_t&, S32 min_count, S32 max_count, const std::vector* possible_values); + void addAttributeToSchema(LLXMLNodePtr nodep, const std::string& attribute_name, const std::string& type, bool mandatory, const std::vector* possible_values); + LLXMLNodePtr mAttributeNode; + LLXMLNodePtr mElementNode; + LLXMLNodePtr mSchemaNode; + + typedef std::set string_set_t; + typedef std::map attributes_map_t; + attributes_map_t mAttributesWritten; +}; + + + +// NOTE: DOES NOT WORK YET +// should support child widgets for XUI +class LLXUIXSDWriter : public LLXSDWriter +{ +public: + void writeXSD(const std::string& name, const std::string& path, const LLInitParam::BaseBlock& block); +}; + + +class LLXUIParserImpl; + +class LLXUIParser : public LLInitParam::Parser +{ +LOG_CLASS(LLXUIParser); + +public: + LLXUIParser(); + typedef LLInitParam::Parser::name_stack_t name_stack_t; + + /*virtual*/ std::string getCurrentElementName(); + /*virtual*/ void parserWarning(const std::string& message); + /*virtual*/ void parserError(const std::string& message); + + void readXUI(LLXMLNodePtr node, LLInitParam::BaseBlock& block, const std::string& filename = LLStringUtil::null, bool silent=false); + void writeXUI(LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const LLInitParam::BaseBlock* diff_block = NULL); + +private: + bool readXUIImpl(LLXMLNodePtr node, LLInitParam::BaseBlock& block); + bool readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block); + + //reader helper functions + static bool readFlag(Parser& parser, void* val_ptr); + static bool readBoolValue(Parser& parser, void* val_ptr); + static bool readStringValue(Parser& parser, void* val_ptr); + static bool readU8Value(Parser& parser, void* val_ptr); + static bool readS8Value(Parser& parser, void* val_ptr); + static bool readU16Value(Parser& parser, void* val_ptr); + static bool readS16Value(Parser& parser, void* val_ptr); + static bool readU32Value(Parser& parser, void* val_ptr); + static bool readS32Value(Parser& parser, void* val_ptr); + static bool readF32Value(Parser& parser, void* val_ptr); + static bool readF64Value(Parser& parser, void* val_ptr); + static bool readColor4Value(Parser& parser, void* val_ptr); + static bool readUIColorValue(Parser& parser, void* val_ptr); + static bool readUUIDValue(Parser& parser, void* val_ptr); + static bool readSDValue(Parser& parser, void* val_ptr); + + //writer helper functions + static bool writeFlag(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeBoolValue(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeStringValue(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeU8Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeS8Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeU16Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeS16Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeU32Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeS32Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeF32Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeF64Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeColor4Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeUIColorValue(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeUUIDValue(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeSDValue(Parser& parser, const void* val_ptr, name_stack_t&); + + LLXMLNodePtr getNode(name_stack_t& stack); + +private: + Parser::name_stack_t mNameStack; + LLXMLNodePtr mCurReadNode; + // Root of the widget XML sub-tree, for example, "line_editor" + LLXMLNodePtr mWriteRootNode; + + typedef std::map out_nodes_t; + out_nodes_t mOutNodes; + LLXMLNodePtr mLastWrittenChild; + S32 mCurReadDepth; + std::string mCurFileName; + std::string mRootNodeName; +}; + +// LLSimpleXUIParser is a streamlined SAX-based XUI parser that does not support localization +// or parsing of a tree of independent param blocks, such as child widgets. +// Use this for reading non-localized files that only need a single param block as a result. +// +// NOTE: In order to support nested block parsing, we need callbacks for start element that +// push new blocks contexts on the mScope stack. +// NOTE: To support localization without building a DOM, we need to enforce consistent +// ordering of child elements from base file to localized diff file. Then we can use a pair +// of coroutines to perform matching of xml nodes during parsing. Not sure if the overhead +// of coroutines would offset the gain from SAX parsing +class LLSimpleXUIParserImpl; + +class LLSimpleXUIParser : public LLInitParam::Parser +{ +LOG_CLASS(LLSimpleXUIParser); +public: + typedef LLInitParam::Parser::name_stack_t name_stack_t; + typedef LLInitParam::BaseBlock* (*element_start_callback_t)(LLSimpleXUIParser&, const char* block_name); + + LLSimpleXUIParser(element_start_callback_t element_cb = NULL); + virtual ~LLSimpleXUIParser(); + + /*virtual*/ std::string getCurrentElementName(); + /*virtual*/ void parserWarning(const std::string& message); + /*virtual*/ void parserError(const std::string& message); + + bool readXUI(const std::string& filename, LLInitParam::BaseBlock& block, bool silent=false); + + +private: + //reader helper functions + static bool readFlag(Parser&, void* val_ptr); + static bool readBoolValue(Parser&, void* val_ptr); + static bool readStringValue(Parser&, void* val_ptr); + static bool readU8Value(Parser&, void* val_ptr); + static bool readS8Value(Parser&, void* val_ptr); + static bool readU16Value(Parser&, void* val_ptr); + static bool readS16Value(Parser&, void* val_ptr); + static bool readU32Value(Parser&, void* val_ptr); + static bool readS32Value(Parser&, void* val_ptr); + static bool readF32Value(Parser&, void* val_ptr); + static bool readF64Value(Parser&, void* val_ptr); + static bool readColor4Value(Parser&, void* val_ptr); + static bool readUIColorValue(Parser&, void* val_ptr); + static bool readUUIDValue(Parser&, void* val_ptr); + static bool readSDValue(Parser&, void* val_ptr); + +private: + static void startElementHandler(void *userData, const char *name, const char **atts); + static void endElementHandler(void *userData, const char *name); + static void characterDataHandler(void *userData, const char *s, int len); + + void startElement(const char *name, const char **atts); + void endElement(const char *name); + void characterData(const char *s, int len); + bool readAttributes(const char **atts); + bool processText(); + + Parser::name_stack_t mNameStack; + struct XML_ParserStruct* mParser; + LLXMLNodePtr mLastWrittenChild; + S32 mCurReadDepth; + std::string mCurFileName; + std::string mTextContents; + const char* mCurAttributeValueBegin; + std::vector mTokenSizeStack; + std::vector mScope; + std::vector mEmptyLeafNode; + element_start_callback_t mElementCB; + + std::vector > mOutputStack; +}; + + +#endif //LLXUIPARSER_H diff --git a/indra/llui/tests/llurlentry_stub.cpp b/indra/llui/tests/llurlentry_stub.cpp index c75df86891..cb3b7abb14 100644 --- a/indra/llui/tests/llurlentry_stub.cpp +++ b/indra/llui/tests/llurlentry_stub.cpp @@ -105,28 +105,6 @@ LLStyle::Params::Params() namespace LLInitParam { - Param::Param(BaseBlock* enclosing_block) - : mIsProvided(false) - { - const U8* my_addr = reinterpret_cast(this); - const U8* block_addr = reinterpret_cast(enclosing_block); - mEnclosingBlockOffset = (U16)(my_addr - block_addr); - } - - void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptorPtr in_param, const char* char_name){} - void BaseBlock::addSynonym(Param& param, const std::string& synonym) {} - param_handle_t BaseBlock::getHandleFromParam(const Param* param) const {return 0;} - - void BaseBlock::init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size) - { - descriptor.mCurrentBlockPtr = this; - } - bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, bool new_name){ return true; } - void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const LLInitParam::BaseBlock* diff_block) const {} - bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_value, S32 max_value) const { return true; } - bool BaseBlock::mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) { return true; } - bool BaseBlock::validateBlock(bool emit_errors) const { return true; } - ParamValue >::ParamValue(const LLUIColor& color) : super_t(color) {} diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp index c1fb050206..8f0a48018f 100644 --- a/indra/llui/tests/llurlentry_test.cpp +++ b/indra/llui/tests/llurlentry_test.cpp @@ -70,21 +70,6 @@ S32 LLUIImage::getHeight() const return 0; } -namespace LLInitParam -{ - BlockDescriptor::BlockDescriptor() {} - ParamDescriptor::ParamDescriptor(param_handle_t p, - merge_func_t merge_func, - deserialize_func_t deserialize_func, - serialize_func_t serialize_func, - validation_func_t validation_func, - inspect_func_t inspect_func, - S32 min_count, - S32 max_count){} - ParamDescriptor::~ParamDescriptor() {} - -} - namespace tut { struct LLUrlEntryData diff --git a/indra/llui/tests/llurlmatch_test.cpp b/indra/llui/tests/llurlmatch_test.cpp index 7183413463..963473c92a 100644 --- a/indra/llui/tests/llurlmatch_test.cpp +++ b/indra/llui/tests/llurlmatch_test.cpp @@ -63,40 +63,6 @@ S32 LLUIImage::getHeight() const namespace LLInitParam { - BlockDescriptor::BlockDescriptor() {} - ParamDescriptor::ParamDescriptor(param_handle_t p, - merge_func_t merge_func, - deserialize_func_t deserialize_func, - serialize_func_t serialize_func, - validation_func_t validation_func, - inspect_func_t inspect_func, - S32 min_count, - S32 max_count){} - ParamDescriptor::~ParamDescriptor() {} - - void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptorPtr in_param, const char* char_name){} - param_handle_t BaseBlock::getHandleFromParam(const Param* param) const {return 0;} - void BaseBlock::addSynonym(Param& param, const std::string& synonym) {} - - void BaseBlock::init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size) - { - descriptor.mCurrentBlockPtr = this; - } - - Param::Param(BaseBlock* enclosing_block) - : mIsProvided(false) - { - const U8* my_addr = reinterpret_cast(this); - const U8* block_addr = reinterpret_cast(enclosing_block); - mEnclosingBlockOffset = 0x7FFFffff & ((U32)(my_addr - block_addr)); - } - - bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, bool new_name){ return true; } - void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const LLInitParam::BaseBlock* diff_block) const {} - bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_count, S32 max_count) const { return true; } - bool BaseBlock::mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) { return true; } - bool BaseBlock::validateBlock(bool emit_errors) const { return true; } - ParamValue >::ParamValue(const LLUIColor& color) : super_t(color) {} -- cgit v1.3 From 4287dcaacf0804a5a73dbf37c629471e2855733c Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Fri, 20 Jan 2012 14:55:39 -0800 Subject: moved LLSDParam to llcommon so that LLSD<->Param Block conversion are usable by everyone --- indra/llcommon/CMakeLists.txt | 2 + indra/llcommon/llinitparam.h | 4 +- indra/llcommon/llsdparam.cpp | 342 ++++++++++++++++++++++++++++++++++++++++++ indra/llcommon/llsdparam.h | 126 ++++++++++++++++ indra/llui/CMakeLists.txt | 2 - indra/llui/llsdparam.cpp | 342 ------------------------------------------ indra/llui/llsdparam.h | 126 ---------------- 7 files changed, 472 insertions(+), 472 deletions(-) create mode 100644 indra/llcommon/llsdparam.cpp create mode 100644 indra/llcommon/llsdparam.h delete mode 100644 indra/llui/llsdparam.cpp delete mode 100644 indra/llui/llsdparam.h (limited to 'indra/llui') diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 72b1d363b0..a1aa887d3a 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -82,6 +82,7 @@ set(llcommon_SOURCE_FILES llrefcount.cpp llrun.cpp llsd.cpp + llsdparam.cpp llsdserialize.cpp llsdserialize_xml.cpp llsdutil.cpp @@ -211,6 +212,7 @@ set(llcommon_HEADER_FILES llrefcount.h llsafehandle.h llsd.h + llsdparam.h llsdserialize.h llsdserialize_xml.h llsdutil.h diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h index 550e1608cc..beaf07e56b 100644 --- a/indra/llcommon/llinitparam.h +++ b/indra/llcommon/llinitparam.h @@ -2057,8 +2057,8 @@ namespace LLInitParam // block param interface - bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name); - void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const; + LL_COMMON_API bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name); + LL_COMMON_API void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const; bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const { //TODO: implement LLSD params as schema type Any diff --git a/indra/llcommon/llsdparam.cpp b/indra/llcommon/llsdparam.cpp new file mode 100644 index 0000000000..0e29873bb0 --- /dev/null +++ b/indra/llcommon/llsdparam.cpp @@ -0,0 +1,342 @@ +/** + * @file llsdparam.cpp + * @brief parameter block abstraction for creating complex objects and + * parsing construction parameters from xml and LLSD + * + * $LicenseInfo:firstyear=2008&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 "linden_common.h" + +// Project includes +#include "llsdparam.h" +#include "llsdutil.h" + +static LLInitParam::Parser::parser_read_func_map_t sReadFuncs; +static LLInitParam::Parser::parser_write_func_map_t sWriteFuncs; +static LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs; +static const LLSD NO_VALUE_MARKER; + +LLFastTimer::DeclareTimer FTM_SD_PARAM_ADAPTOR("LLSD to LLInitParam conversion"); + +// +// LLParamSDParser +// +LLParamSDParser::LLParamSDParser() +: Parser(sReadFuncs, sWriteFuncs, sInspectFuncs) +{ + using boost::bind; + + if (sReadFuncs.empty()) + { + registerParserFuncs(readFlag, &LLParamSDParser::writeFlag); + registerParserFuncs(readS32, &LLParamSDParser::writeTypedValue); + registerParserFuncs(readU32, &LLParamSDParser::writeU32Param); + registerParserFuncs(readF32, &LLParamSDParser::writeTypedValue); + registerParserFuncs(readF64, &LLParamSDParser::writeTypedValue); + registerParserFuncs(readBool, &LLParamSDParser::writeTypedValue); + registerParserFuncs(readString, &LLParamSDParser::writeTypedValue); + registerParserFuncs(readUUID, &LLParamSDParser::writeTypedValue); + registerParserFuncs(readDate, &LLParamSDParser::writeTypedValue); + registerParserFuncs(readURI, &LLParamSDParser::writeTypedValue); + registerParserFuncs(readSD, &LLParamSDParser::writeTypedValue); + } +} + +// special case handling of U32 due to ambiguous LLSD::assign overload +bool LLParamSDParser::writeU32Param(LLParamSDParser::parser_t& parser, const void* val_ptr, parser_t::name_stack_t& name_stack) +{ + LLParamSDParser& sdparser = static_cast(parser); + if (!sdparser.mWriteRootSD) return false; + + parser_t::name_stack_range_t range(name_stack.begin(), name_stack.end()); + LLSD& sd_to_write = LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); + sd_to_write.assign((S32)*((const U32*)val_ptr)); + + return true; +} + +bool LLParamSDParser::writeFlag(LLParamSDParser::parser_t& parser, const void* val_ptr, parser_t::name_stack_t& name_stack) +{ + LLParamSDParser& sdparser = static_cast(parser); + if (!sdparser.mWriteRootSD) return false; + + parser_t::name_stack_range_t range(name_stack.begin(), name_stack.end()); + LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); + + return true; +} + +void LLParamSDParser::submit(LLInitParam::BaseBlock& block, const LLSD& sd, LLInitParam::Parser::name_stack_t& name_stack) +{ + mCurReadSD = &sd; + block.submitValue(name_stack, *this); +} + +void LLParamSDParser::readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent) +{ + mCurReadSD = NULL; + mNameStack.clear(); + setParseSilently(silent); + + LLParamSDParserUtilities::readSDValues(boost::bind(&LLParamSDParser::submit, this, boost::ref(block), _1, _2), sd, mNameStack); + //readSDValues(sd, block); +} + +void LLParamSDParser::writeSD(LLSD& sd, const LLInitParam::BaseBlock& block) +{ + mNameStack.clear(); + mWriteRootSD = &sd; + + name_stack_t name_stack; + block.serializeBlock(*this, name_stack); +} + +/*virtual*/ std::string LLParamSDParser::getCurrentElementName() +{ + std::string full_name = "sd"; + for (name_stack_t::iterator it = mNameStack.begin(); + it != mNameStack.end(); + ++it) + { + full_name += llformat("[%s]", it->first.c_str()); + } + + return full_name; +} + + +bool LLParamSDParser::readFlag(Parser& parser, void* val_ptr) +{ + LLParamSDParser& self = static_cast(parser); + return self.mCurReadSD == &NO_VALUE_MARKER; +} + + +bool LLParamSDParser::readS32(Parser& parser, void* val_ptr) +{ + LLParamSDParser& self = static_cast(parser); + + *((S32*)val_ptr) = self.mCurReadSD->asInteger(); + return true; +} + +bool LLParamSDParser::readU32(Parser& parser, void* val_ptr) +{ + LLParamSDParser& self = static_cast(parser); + + *((U32*)val_ptr) = self.mCurReadSD->asInteger(); + return true; +} + +bool LLParamSDParser::readF32(Parser& parser, void* val_ptr) +{ + LLParamSDParser& self = static_cast(parser); + + *((F32*)val_ptr) = self.mCurReadSD->asReal(); + return true; +} + +bool LLParamSDParser::readF64(Parser& parser, void* val_ptr) +{ + LLParamSDParser& self = static_cast(parser); + + *((F64*)val_ptr) = self.mCurReadSD->asReal(); + return true; +} + +bool LLParamSDParser::readBool(Parser& parser, void* val_ptr) +{ + LLParamSDParser& self = static_cast(parser); + + *((bool*)val_ptr) = self.mCurReadSD->asBoolean(); + return true; +} + +bool LLParamSDParser::readString(Parser& parser, void* val_ptr) +{ + LLParamSDParser& self = static_cast(parser); + + *((std::string*)val_ptr) = self.mCurReadSD->asString(); + return true; +} + +bool LLParamSDParser::readUUID(Parser& parser, void* val_ptr) +{ + LLParamSDParser& self = static_cast(parser); + + *((LLUUID*)val_ptr) = self.mCurReadSD->asUUID(); + return true; +} + +bool LLParamSDParser::readDate(Parser& parser, void* val_ptr) +{ + LLParamSDParser& self = static_cast(parser); + + *((LLDate*)val_ptr) = self.mCurReadSD->asDate(); + return true; +} + +bool LLParamSDParser::readURI(Parser& parser, void* val_ptr) +{ + LLParamSDParser& self = static_cast(parser); + + *((LLURI*)val_ptr) = self.mCurReadSD->asURI(); + return true; +} + +bool LLParamSDParser::readSD(Parser& parser, void* val_ptr) +{ + LLParamSDParser& self = static_cast(parser); + + *((LLSD*)val_ptr) = *self.mCurReadSD; + return true; +} + +// static +LLSD& LLParamSDParserUtilities::getSDWriteNode(LLSD& input, LLInitParam::Parser::name_stack_range_t& name_stack_range) +{ + LLSD* sd_to_write = &input; + + for (LLInitParam::Parser::name_stack_t::iterator it = name_stack_range.first; + it != name_stack_range.second; + ++it) + { + bool new_traversal = it->second; + + LLSD* child_sd = it->first.empty() ? sd_to_write : &(*sd_to_write)[it->first]; + + if (child_sd->isArray()) + { + if (new_traversal) + { + // write to new element at end + sd_to_write = &(*child_sd)[child_sd->size()]; + } + else + { + // write to last of existing elements, or first element if empty + sd_to_write = &(*child_sd)[llmax(0, child_sd->size() - 1)]; + } + } + else + { + if (new_traversal + && child_sd->isDefined() + && !child_sd->isArray()) + { + // copy child contents into first element of an array + LLSD new_array = LLSD::emptyArray(); + new_array.append(*child_sd); + // assign array to slot that previously held the single value + *child_sd = new_array; + // return next element in that array + sd_to_write = &((*child_sd)[1]); + } + else + { + sd_to_write = child_sd; + } + } + it->second = false; + } + + return *sd_to_write; +} + +//static +void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd, LLInitParam::Parser::name_stack_t& stack) +{ + if (sd.isMap()) + { + for (LLSD::map_const_iterator it = sd.beginMap(); + it != sd.endMap(); + ++it) + { + stack.push_back(make_pair(it->first, true)); + readSDValues(cb, it->second, stack); + stack.pop_back(); + } + } + else if (sd.isArray()) + { + for (LLSD::array_const_iterator it = sd.beginArray(); + it != sd.endArray(); + ++it) + { + stack.back().second = true; + readSDValues(cb, *it, stack); + } + } + else if (sd.isUndefined()) + { + if (!cb.empty()) + { + cb(NO_VALUE_MARKER, stack); + } + } + else + { + if (!cb.empty()) + { + cb(sd, stack); + } + } +} + +//static +void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd) +{ + LLInitParam::Parser::name_stack_t stack = LLInitParam::Parser::name_stack_t(); + readSDValues(cb, sd, stack); +} +namespace LLInitParam +{ + // LLSD specialization + // block param interface + bool ParamValue, false>::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, bool new_name) + { + LLSD& sd = LLParamSDParserUtilities::getSDWriteNode(mValue, name_stack); + + LLSD::String string; + + if (p.readValue(string)) + { + sd = string; + return true; + } + return false; + } + + //static + void ParamValue, false>::serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack) + { + p.writeValue(sd.asString(), name_stack); + } + + void ParamValue, false>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block) const + { + // read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc) + Parser::name_stack_t stack; + LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, stack); + } +} diff --git a/indra/llcommon/llsdparam.h b/indra/llcommon/llsdparam.h new file mode 100644 index 0000000000..6ef5debd7b --- /dev/null +++ b/indra/llcommon/llsdparam.h @@ -0,0 +1,126 @@ +/** + * @file llsdparam.h + * @brief parameter block abstraction for creating complex objects and + * parsing construction parameters from xml and LLSD + * + * $LicenseInfo:firstyear=2008&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_LLSDPARAM_H +#define LL_LLSDPARAM_H + +#include "llinitparam.h" +#include "boost/function.hpp" + +struct LL_COMMON_API LLParamSDParserUtilities +{ + static LLSD& getSDWriteNode(LLSD& input, LLInitParam::Parser::name_stack_range_t& name_stack_range); + + typedef boost::function read_sd_cb_t; + static void readSDValues(read_sd_cb_t cb, const LLSD& sd, LLInitParam::Parser::name_stack_t& stack); + static void readSDValues(read_sd_cb_t cb, const LLSD& sd); +}; + +class LL_COMMON_API LLParamSDParser +: public LLInitParam::Parser +{ +LOG_CLASS(LLParamSDParser); + +typedef LLInitParam::Parser parser_t; + +public: + LLParamSDParser(); + void readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent = false); + void writeSD(LLSD& sd, const LLInitParam::BaseBlock& block); + + /*virtual*/ std::string getCurrentElementName(); + +private: + void submit(LLInitParam::BaseBlock& block, const LLSD& sd, LLInitParam::Parser::name_stack_t& name_stack); + + template + static bool writeTypedValue(Parser& parser, const void* val_ptr, parser_t::name_stack_t& name_stack) + { + LLParamSDParser& sdparser = static_cast(parser); + if (!sdparser.mWriteRootSD) return false; + + LLInitParam::Parser::name_stack_range_t range(name_stack.begin(), name_stack.end()); + LLSD& sd_to_write = LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); + + sd_to_write.assign(*((const T*)val_ptr)); + return true; + } + + static bool writeU32Param(Parser& parser, const void* value_ptr, parser_t::name_stack_t& name_stack); + static bool writeFlag(Parser& parser, const void* value_ptr, parser_t::name_stack_t& name_stack); + + static bool readFlag(Parser& parser, void* val_ptr); + static bool readS32(Parser& parser, void* val_ptr); + static bool readU32(Parser& parser, void* val_ptr); + static bool readF32(Parser& parser, void* val_ptr); + static bool readF64(Parser& parser, void* val_ptr); + static bool readBool(Parser& parser, void* val_ptr); + static bool readString(Parser& parser, void* val_ptr); + static bool readUUID(Parser& parser, void* val_ptr); + static bool readDate(Parser& parser, void* val_ptr); + static bool readURI(Parser& parser, void* val_ptr); + static bool readSD(Parser& parser, void* val_ptr); + + Parser::name_stack_t mNameStack; + const LLSD* mCurReadSD; + LLSD* mWriteRootSD; + LLSD* mCurWriteSD; +}; + + +extern LL_COMMON_API LLFastTimer::DeclareTimer FTM_SD_PARAM_ADAPTOR; +template +class LLSDParamAdapter : public T +{ +public: + LLSDParamAdapter() {} + LLSDParamAdapter(const LLSD& sd) + { + LLFastTimer _(FTM_SD_PARAM_ADAPTOR); + LLParamSDParser parser; + // don't spam for implicit parsing of LLSD, as we want to allow arbitrary freeform data and ignore most of it + bool parse_silently = true; + parser.readSD(sd, *this, parse_silently); + } + + operator LLSD() const + { + LLParamSDParser parser; + LLSD sd; + parser.writeSD(sd, *this); + return sd; + } + + LLSDParamAdapter(const T& val) + : T(val) + { + T::operator=(val); + } +}; + +#endif // LL_LLSDPARAM_H + diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 9226f36e73..20c3456a56 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -81,7 +81,6 @@ set(llui_SOURCE_FILES llscrolllistcolumn.cpp llscrolllistctrl.cpp llscrolllistitem.cpp - llsdparam.cpp llsearcheditor.cpp llslider.cpp llsliderctrl.cpp @@ -190,7 +189,6 @@ set(llui_HEADER_FILES llscrolllistcolumn.h llscrolllistctrl.h llscrolllistitem.h - llsdparam.h llsliderctrl.h llslider.h llspinctrl.h diff --git a/indra/llui/llsdparam.cpp b/indra/llui/llsdparam.cpp deleted file mode 100644 index 0e29873bb0..0000000000 --- a/indra/llui/llsdparam.cpp +++ /dev/null @@ -1,342 +0,0 @@ -/** - * @file llsdparam.cpp - * @brief parameter block abstraction for creating complex objects and - * parsing construction parameters from xml and LLSD - * - * $LicenseInfo:firstyear=2008&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 "linden_common.h" - -// Project includes -#include "llsdparam.h" -#include "llsdutil.h" - -static LLInitParam::Parser::parser_read_func_map_t sReadFuncs; -static LLInitParam::Parser::parser_write_func_map_t sWriteFuncs; -static LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs; -static const LLSD NO_VALUE_MARKER; - -LLFastTimer::DeclareTimer FTM_SD_PARAM_ADAPTOR("LLSD to LLInitParam conversion"); - -// -// LLParamSDParser -// -LLParamSDParser::LLParamSDParser() -: Parser(sReadFuncs, sWriteFuncs, sInspectFuncs) -{ - using boost::bind; - - if (sReadFuncs.empty()) - { - registerParserFuncs(readFlag, &LLParamSDParser::writeFlag); - registerParserFuncs(readS32, &LLParamSDParser::writeTypedValue); - registerParserFuncs(readU32, &LLParamSDParser::writeU32Param); - registerParserFuncs(readF32, &LLParamSDParser::writeTypedValue); - registerParserFuncs(readF64, &LLParamSDParser::writeTypedValue); - registerParserFuncs(readBool, &LLParamSDParser::writeTypedValue); - registerParserFuncs(readString, &LLParamSDParser::writeTypedValue); - registerParserFuncs(readUUID, &LLParamSDParser::writeTypedValue); - registerParserFuncs(readDate, &LLParamSDParser::writeTypedValue); - registerParserFuncs(readURI, &LLParamSDParser::writeTypedValue); - registerParserFuncs(readSD, &LLParamSDParser::writeTypedValue); - } -} - -// special case handling of U32 due to ambiguous LLSD::assign overload -bool LLParamSDParser::writeU32Param(LLParamSDParser::parser_t& parser, const void* val_ptr, parser_t::name_stack_t& name_stack) -{ - LLParamSDParser& sdparser = static_cast(parser); - if (!sdparser.mWriteRootSD) return false; - - parser_t::name_stack_range_t range(name_stack.begin(), name_stack.end()); - LLSD& sd_to_write = LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); - sd_to_write.assign((S32)*((const U32*)val_ptr)); - - return true; -} - -bool LLParamSDParser::writeFlag(LLParamSDParser::parser_t& parser, const void* val_ptr, parser_t::name_stack_t& name_stack) -{ - LLParamSDParser& sdparser = static_cast(parser); - if (!sdparser.mWriteRootSD) return false; - - parser_t::name_stack_range_t range(name_stack.begin(), name_stack.end()); - LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); - - return true; -} - -void LLParamSDParser::submit(LLInitParam::BaseBlock& block, const LLSD& sd, LLInitParam::Parser::name_stack_t& name_stack) -{ - mCurReadSD = &sd; - block.submitValue(name_stack, *this); -} - -void LLParamSDParser::readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent) -{ - mCurReadSD = NULL; - mNameStack.clear(); - setParseSilently(silent); - - LLParamSDParserUtilities::readSDValues(boost::bind(&LLParamSDParser::submit, this, boost::ref(block), _1, _2), sd, mNameStack); - //readSDValues(sd, block); -} - -void LLParamSDParser::writeSD(LLSD& sd, const LLInitParam::BaseBlock& block) -{ - mNameStack.clear(); - mWriteRootSD = &sd; - - name_stack_t name_stack; - block.serializeBlock(*this, name_stack); -} - -/*virtual*/ std::string LLParamSDParser::getCurrentElementName() -{ - std::string full_name = "sd"; - for (name_stack_t::iterator it = mNameStack.begin(); - it != mNameStack.end(); - ++it) - { - full_name += llformat("[%s]", it->first.c_str()); - } - - return full_name; -} - - -bool LLParamSDParser::readFlag(Parser& parser, void* val_ptr) -{ - LLParamSDParser& self = static_cast(parser); - return self.mCurReadSD == &NO_VALUE_MARKER; -} - - -bool LLParamSDParser::readS32(Parser& parser, void* val_ptr) -{ - LLParamSDParser& self = static_cast(parser); - - *((S32*)val_ptr) = self.mCurReadSD->asInteger(); - return true; -} - -bool LLParamSDParser::readU32(Parser& parser, void* val_ptr) -{ - LLParamSDParser& self = static_cast(parser); - - *((U32*)val_ptr) = self.mCurReadSD->asInteger(); - return true; -} - -bool LLParamSDParser::readF32(Parser& parser, void* val_ptr) -{ - LLParamSDParser& self = static_cast(parser); - - *((F32*)val_ptr) = self.mCurReadSD->asReal(); - return true; -} - -bool LLParamSDParser::readF64(Parser& parser, void* val_ptr) -{ - LLParamSDParser& self = static_cast(parser); - - *((F64*)val_ptr) = self.mCurReadSD->asReal(); - return true; -} - -bool LLParamSDParser::readBool(Parser& parser, void* val_ptr) -{ - LLParamSDParser& self = static_cast(parser); - - *((bool*)val_ptr) = self.mCurReadSD->asBoolean(); - return true; -} - -bool LLParamSDParser::readString(Parser& parser, void* val_ptr) -{ - LLParamSDParser& self = static_cast(parser); - - *((std::string*)val_ptr) = self.mCurReadSD->asString(); - return true; -} - -bool LLParamSDParser::readUUID(Parser& parser, void* val_ptr) -{ - LLParamSDParser& self = static_cast(parser); - - *((LLUUID*)val_ptr) = self.mCurReadSD->asUUID(); - return true; -} - -bool LLParamSDParser::readDate(Parser& parser, void* val_ptr) -{ - LLParamSDParser& self = static_cast(parser); - - *((LLDate*)val_ptr) = self.mCurReadSD->asDate(); - return true; -} - -bool LLParamSDParser::readURI(Parser& parser, void* val_ptr) -{ - LLParamSDParser& self = static_cast(parser); - - *((LLURI*)val_ptr) = self.mCurReadSD->asURI(); - return true; -} - -bool LLParamSDParser::readSD(Parser& parser, void* val_ptr) -{ - LLParamSDParser& self = static_cast(parser); - - *((LLSD*)val_ptr) = *self.mCurReadSD; - return true; -} - -// static -LLSD& LLParamSDParserUtilities::getSDWriteNode(LLSD& input, LLInitParam::Parser::name_stack_range_t& name_stack_range) -{ - LLSD* sd_to_write = &input; - - for (LLInitParam::Parser::name_stack_t::iterator it = name_stack_range.first; - it != name_stack_range.second; - ++it) - { - bool new_traversal = it->second; - - LLSD* child_sd = it->first.empty() ? sd_to_write : &(*sd_to_write)[it->first]; - - if (child_sd->isArray()) - { - if (new_traversal) - { - // write to new element at end - sd_to_write = &(*child_sd)[child_sd->size()]; - } - else - { - // write to last of existing elements, or first element if empty - sd_to_write = &(*child_sd)[llmax(0, child_sd->size() - 1)]; - } - } - else - { - if (new_traversal - && child_sd->isDefined() - && !child_sd->isArray()) - { - // copy child contents into first element of an array - LLSD new_array = LLSD::emptyArray(); - new_array.append(*child_sd); - // assign array to slot that previously held the single value - *child_sd = new_array; - // return next element in that array - sd_to_write = &((*child_sd)[1]); - } - else - { - sd_to_write = child_sd; - } - } - it->second = false; - } - - return *sd_to_write; -} - -//static -void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd, LLInitParam::Parser::name_stack_t& stack) -{ - if (sd.isMap()) - { - for (LLSD::map_const_iterator it = sd.beginMap(); - it != sd.endMap(); - ++it) - { - stack.push_back(make_pair(it->first, true)); - readSDValues(cb, it->second, stack); - stack.pop_back(); - } - } - else if (sd.isArray()) - { - for (LLSD::array_const_iterator it = sd.beginArray(); - it != sd.endArray(); - ++it) - { - stack.back().second = true; - readSDValues(cb, *it, stack); - } - } - else if (sd.isUndefined()) - { - if (!cb.empty()) - { - cb(NO_VALUE_MARKER, stack); - } - } - else - { - if (!cb.empty()) - { - cb(sd, stack); - } - } -} - -//static -void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd) -{ - LLInitParam::Parser::name_stack_t stack = LLInitParam::Parser::name_stack_t(); - readSDValues(cb, sd, stack); -} -namespace LLInitParam -{ - // LLSD specialization - // block param interface - bool ParamValue, false>::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, bool new_name) - { - LLSD& sd = LLParamSDParserUtilities::getSDWriteNode(mValue, name_stack); - - LLSD::String string; - - if (p.readValue(string)) - { - sd = string; - return true; - } - return false; - } - - //static - void ParamValue, false>::serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack) - { - p.writeValue(sd.asString(), name_stack); - } - - void ParamValue, false>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block) const - { - // read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc) - Parser::name_stack_t stack; - LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, stack); - } -} diff --git a/indra/llui/llsdparam.h b/indra/llui/llsdparam.h deleted file mode 100644 index 3dfc6d020e..0000000000 --- a/indra/llui/llsdparam.h +++ /dev/null @@ -1,126 +0,0 @@ -/** - * @file llsdparam.h - * @brief parameter block abstraction for creating complex objects and - * parsing construction parameters from xml and LLSD - * - * $LicenseInfo:firstyear=2008&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_LLSDPARAM_H -#define LL_LLSDPARAM_H - -#include "llinitparam.h" -#include "boost/function.hpp" - -struct LLParamSDParserUtilities -{ - static LLSD& getSDWriteNode(LLSD& input, LLInitParam::Parser::name_stack_range_t& name_stack_range); - - typedef boost::function read_sd_cb_t; - static void readSDValues(read_sd_cb_t cb, const LLSD& sd, LLInitParam::Parser::name_stack_t& stack); - static void readSDValues(read_sd_cb_t cb, const LLSD& sd); -}; - -class LLParamSDParser -: public LLInitParam::Parser -{ -LOG_CLASS(LLParamSDParser); - -typedef LLInitParam::Parser parser_t; - -public: - LLParamSDParser(); - void readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent = false); - void writeSD(LLSD& sd, const LLInitParam::BaseBlock& block); - - /*virtual*/ std::string getCurrentElementName(); - -private: - void submit(LLInitParam::BaseBlock& block, const LLSD& sd, LLInitParam::Parser::name_stack_t& name_stack); - - template - static bool writeTypedValue(Parser& parser, const void* val_ptr, parser_t::name_stack_t& name_stack) - { - LLParamSDParser& sdparser = static_cast(parser); - if (!sdparser.mWriteRootSD) return false; - - LLInitParam::Parser::name_stack_range_t range(name_stack.begin(), name_stack.end()); - LLSD& sd_to_write = LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); - - sd_to_write.assign(*((const T*)val_ptr)); - return true; - } - - static bool writeU32Param(Parser& parser, const void* value_ptr, parser_t::name_stack_t& name_stack); - static bool writeFlag(Parser& parser, const void* value_ptr, parser_t::name_stack_t& name_stack); - - static bool readFlag(Parser& parser, void* val_ptr); - static bool readS32(Parser& parser, void* val_ptr); - static bool readU32(Parser& parser, void* val_ptr); - static bool readF32(Parser& parser, void* val_ptr); - static bool readF64(Parser& parser, void* val_ptr); - static bool readBool(Parser& parser, void* val_ptr); - static bool readString(Parser& parser, void* val_ptr); - static bool readUUID(Parser& parser, void* val_ptr); - static bool readDate(Parser& parser, void* val_ptr); - static bool readURI(Parser& parser, void* val_ptr); - static bool readSD(Parser& parser, void* val_ptr); - - Parser::name_stack_t mNameStack; - const LLSD* mCurReadSD; - LLSD* mWriteRootSD; - LLSD* mCurWriteSD; -}; - - -extern LLFastTimer::DeclareTimer FTM_SD_PARAM_ADAPTOR; -template -class LLSDParamAdapter : public T -{ -public: - LLSDParamAdapter() {} - LLSDParamAdapter(const LLSD& sd) - { - LLFastTimer _(FTM_SD_PARAM_ADAPTOR); - LLParamSDParser parser; - // don't spam for implicit parsing of LLSD, as we want to allow arbitrary freeform data and ignore most of it - bool parse_silently = true; - parser.readSD(sd, *this, parse_silently); - } - - operator LLSD() const - { - LLParamSDParser parser; - LLSD sd; - parser.writeSD(sd, *this); - return sd; - } - - LLSDParamAdapter(const T& val) - : T(val) - { - T::operator=(val); - } -}; - -#endif // LL_LLSDPARAM_H - -- cgit v1.3 From c1636911c84f948e542f445d3c7495e6df185912 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Wed, 1 Feb 2012 19:09:29 -0800 Subject: EXP-1862 : Make LLClipboard an LLSingleton and clean up the internals (set up for toolbar and never used) --- indra/llui/llclipboard.cpp | 6 ------ indra/llui/llclipboard.h | 15 ++++----------- indra/llui/lllineeditor.cpp | 14 +++++++------- indra/llui/llscrolllistctrl.cpp | 2 +- indra/llui/lltexteditor.cpp | 14 +++++++------- indra/newview/llfavoritesbar.cpp | 2 +- indra/newview/llfloatergesture.cpp | 2 +- indra/newview/llpanelteleporthistory.cpp | 2 +- indra/newview/llpaneltopinfobar.cpp | 2 +- indra/newview/llpanelwearing.cpp | 2 +- indra/newview/lltoolbarview.cpp | 15 ++++++++++++++- indra/newview/lltoolbarview.h | 3 +++ indra/newview/lltooldraganddrop.cpp | 3 ++- indra/newview/llurllineeditorctrl.cpp | 2 +- 14 files changed, 44 insertions(+), 40 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llclipboard.cpp b/indra/llui/llclipboard.cpp index 6910b962a1..984c4ec5fb 100644 --- a/indra/llui/llclipboard.cpp +++ b/indra/llui/llclipboard.cpp @@ -40,7 +40,6 @@ LLClipboard gClipboard; LLClipboard::LLClipboard() { - mSourceItem = NULL; } @@ -135,8 +134,3 @@ BOOL LLClipboard::canPastePrimaryString() const { return LLView::getWindow()->isPrimaryTextAvailable(); } - -void LLClipboard::setSourceObject(const LLUUID& source_id, LLAssetType::EType type) -{ - mSourceItem = new LLInventoryObject (source_id, LLUUID::null, type, ""); -} diff --git a/indra/llui/llclipboard.h b/indra/llui/llclipboard.h index 9371b94284..2567eaab48 100644 --- a/indra/llui/llclipboard.h +++ b/indra/llui/llclipboard.h @@ -31,10 +31,10 @@ #include "llstring.h" #include "lluuid.h" #include "stdenums.h" +#include "llsingleton.h" #include "llinventory.h" - -class LLClipboard +class LLClipboard : public LLSingleton { public: LLClipboard(); @@ -54,19 +54,12 @@ public: BOOL canPastePrimaryString() const; const LLWString& getPastePrimaryWString(LLUUID* source_id = NULL); - // Support clipboard for object known only by their uuid and asset type - void setSourceObject(const LLUUID& source_id, LLAssetType::EType type); - const LLInventoryObject* getSourceObject() { return mSourceItem; } + // Support clipboard for object known only by their uuid + void setSourceObject(const LLUUID& source_id) { mSourceID = source_id; } private: LLUUID mSourceID; LLWString mString; - LLInventoryObject* mSourceItem; }; - -// Global singleton -extern LLClipboard gClipboard; - - #endif // LL_LLCLIPBOARD_H diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 06dfc90d83..9292158b7c 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -1047,7 +1047,7 @@ void LLLineEditor::cut() // Prepare for possible rollback LLLineEditorRollback rollback( this ); - gClipboard.copyFromSubstring( mText.getWString(), left_pos, length ); + LLClipboard::getInstance()->copyFromSubstring( mText.getWString(), left_pos, length ); deleteSelection(); // Validate new string and rollback the if needed. @@ -1078,13 +1078,13 @@ void LLLineEditor::copy() { S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); S32 length = llabs( mSelectionStart - mSelectionEnd ); - gClipboard.copyFromSubstring( mText.getWString(), left_pos, length ); + LLClipboard::getInstance()->copyFromSubstring( mText.getWString(), left_pos, length ); } } BOOL LLLineEditor::canPaste() const { - return !mReadOnly && gClipboard.canPasteString(); + return !mReadOnly && LLClipboard::getInstance()->canPasteString(); } void LLLineEditor::paste() @@ -1117,11 +1117,11 @@ void LLLineEditor::pasteHelper(bool is_primary) LLWString paste; if (is_primary) { - paste = gClipboard.getPastePrimaryWString(); + paste = LLClipboard::getInstance()->getPastePrimaryWString(); } else { - paste = gClipboard.getPasteWString(); + paste = LLClipboard::getInstance()->getPasteWString(); } if (!paste.empty()) @@ -1209,13 +1209,13 @@ void LLLineEditor::copyPrimary() { S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); S32 length = llabs( mSelectionStart - mSelectionEnd ); - gClipboard.copyFromPrimarySubstring( mText.getWString(), left_pos, length ); + LLClipboard::getInstance()->copyFromPrimarySubstring( mText.getWString(), left_pos, length ); } } BOOL LLLineEditor::canPastePrimary() const { - return !mReadOnly && gClipboard.canPastePrimaryString(); + return !mReadOnly && LLClipboard::getInstance()->canPastePrimaryString(); } void LLLineEditor::updatePrimary() diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 466fac33ea..8cbc2a8f99 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -2504,7 +2504,7 @@ void LLScrollListCtrl::copy() { buffer += (*itor)->getContentsCSV() + "\n"; } - gClipboard.copyFromSubstring(utf8str_to_wstring(buffer), 0, buffer.length()); + LLClipboard::getInstance()->copyFromSubstring(utf8str_to_wstring(buffer), 0, buffer.length()); } // virtual diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 3a23ce1cac..22a577cda8 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -1332,7 +1332,7 @@ void LLTextEditor::cut() } S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); S32 length = llabs( mSelectionStart - mSelectionEnd ); - gClipboard.copyFromSubstring( getWText(), left_pos, length, mSourceID ); + LLClipboard::getInstance()->copyFromSubstring( getWText(), left_pos, length, mSourceID ); deleteSelection( FALSE ); onKeyStroke(); @@ -1352,12 +1352,12 @@ void LLTextEditor::copy() } S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); S32 length = llabs( mSelectionStart - mSelectionEnd ); - gClipboard.copyFromSubstring(getWText(), left_pos, length, mSourceID); + LLClipboard::getInstance()->copyFromSubstring(getWText(), left_pos, length, mSourceID); } BOOL LLTextEditor::canPaste() const { - return !mReadOnly && gClipboard.canPasteString(); + return !mReadOnly && LLClipboard::getInstance()->canPasteString(); } // paste from clipboard @@ -1397,11 +1397,11 @@ void LLTextEditor::pasteHelper(bool is_primary) LLWString paste; if (is_primary) { - paste = gClipboard.getPastePrimaryWString(&source_id); + paste = LLClipboard::getInstance()->getPastePrimaryWString(&source_id); } else { - paste = gClipboard.getPasteWString(&source_id); + paste = LLClipboard::getInstance()->getPasteWString(&source_id); } if (paste.empty()) @@ -1475,12 +1475,12 @@ void LLTextEditor::copyPrimary() } S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); S32 length = llabs( mSelectionStart - mSelectionEnd ); - gClipboard.copyFromPrimarySubstring(getWText(), left_pos, length, mSourceID); + LLClipboard::getInstance()->copyFromPrimarySubstring(getWText(), left_pos, length, mSourceID); } BOOL LLTextEditor::canPastePrimary() const { - return !mReadOnly && gClipboard.canPastePrimaryString(); + return !mReadOnly && LLClipboard::getInstance()->canPastePrimaryString(); } void LLTextEditor::updatePrimary() diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index f4b6dc2c81..24bd2cf313 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -1118,7 +1118,7 @@ BOOL LLFavoritesBarCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) } void copy_slurl_to_clipboard_cb(std::string& slurl) { - gClipboard.copyFromString(utf8str_to_wstring(slurl)); + LLClipboard::getInstance()->copyFromString(utf8str_to_wstring(slurl)); LLSD args; args["SLURL"] = slurl; diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp index d495f20a9a..e025d6edb5 100644 --- a/indra/newview/llfloatergesture.cpp +++ b/indra/newview/llfloatergesture.cpp @@ -534,7 +534,7 @@ void LLFloaterGesture::onCopyPasteAction(const LLSD& command) } else if ("copy_uuid" == command_name) { - gClipboard.copyFromString(utf8str_to_wstring(mGestureList->getCurrentID().asString()), mGestureList->getCurrentID()); + LLClipboard::getInstance()->copyFromString(utf8str_to_wstring(mGestureList->getCurrentID().asString()), mGestureList->getCurrentID()); } } diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp index 1f1cccad85..a4c9af3fad 100644 --- a/indra/newview/llpanelteleporthistory.cpp +++ b/indra/newview/llpanelteleporthistory.cpp @@ -358,7 +358,7 @@ void LLTeleportHistoryPanel::ContextMenu::onInfo() //static void LLTeleportHistoryPanel::ContextMenu::gotSLURLCallback(const std::string& slurl) { - gClipboard.copyFromString(utf8str_to_wstring(slurl)); + LLClipboard::getInstance()->copyFromString(utf8str_to_wstring(slurl)); } void LLTeleportHistoryPanel::ContextMenu::onCopyToClipboard() diff --git a/indra/newview/llpaneltopinfobar.cpp b/indra/newview/llpaneltopinfobar.cpp index eb4c7572d4..0e3ff99066 100644 --- a/indra/newview/llpaneltopinfobar.cpp +++ b/indra/newview/llpaneltopinfobar.cpp @@ -467,7 +467,7 @@ void LLPanelTopInfoBar::onContextMenuItemClicked(const LLSD::String& item) LLAgentUI::buildSLURL(slurl, false); LLUIString location_str(slurl.getSLURLString()); - gClipboard.copyFromString(location_str); + LLClipboard::getInstance()->copyFromString(location_str); } } diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp index e2801c09bd..1286756693 100644 --- a/indra/newview/llpanelwearing.cpp +++ b/indra/newview/llpanelwearing.cpp @@ -302,6 +302,6 @@ void LLPanelWearing::copyToClipboard() } } - gClipboard.copyFromString(utf8str_to_wstring(text)); + LLClipboard::getInstance()->copyFromString(utf8str_to_wstring(text)); } // EOF diff --git a/indra/newview/lltoolbarview.cpp b/indra/newview/lltoolbarview.cpp index eccb2cf2f1..8a0b035234 100644 --- a/indra/newview/lltoolbarview.cpp +++ b/indra/newview/lltoolbarview.cpp @@ -75,6 +75,7 @@ LLToolBarView::LLToolBarView(const LLToolBarView::Params& p) mDragStarted(false), mShowToolbars(true), mDragToolbarButton(NULL), + mDragItem(NULL), mToolbarsLoaded(false) { for (S32 i = 0; i < TOOLBAR_COUNT; i++) @@ -579,7 +580,7 @@ BOOL LLToolBarView::handleDragTool( S32 x, S32 y, const LLUUID& uuid, LLAssetTyp uuid_vec_t cargo_ids; types.push_back(DAD_WIDGET); cargo_ids.push_back(uuid); - gClipboard.setSourceObject(uuid,LLAssetType::AT_WIDGET); + LLClipboard::getInstance()->setSourceObject(uuid); LLToolDragAndDrop::ESource src = LLToolDragAndDrop::SOURCE_VIEWER; LLUUID srcID; LLToolDragAndDrop::getInstance()->beginMultiDrag(types, cargo_ids, src, srcID); @@ -662,6 +663,18 @@ void LLToolBarView::resetDragTool(LLToolBarButton* toolbarButton) gToolBarView->mDragToolbarButton = toolbarButton; } +// Provide a handle on a free standing inventory item containing references to the tool. +// This might be used by Drag and Drop to move around references to tool items. +LLInventoryObject* LLToolBarView::getDragItem() +{ + if (mDragToolbarButton) + { + LLUUID item_uuid = mDragToolbarButton->getCommandId().uuid(); + mDragItem = new LLInventoryObject (item_uuid, LLUUID::null, LLAssetType::AT_WIDGET, ""); + } + return mDragItem; +} + void LLToolBarView::setToolBarsVisible(bool visible) { mShowToolbars = visible; diff --git a/indra/newview/lltoolbarview.h b/indra/newview/lltoolbarview.h index be66bcae36..9c4194ebed 100644 --- a/indra/newview/lltoolbarview.h +++ b/indra/newview/lltoolbarview.h @@ -31,6 +31,7 @@ #include "lluictrl.h" #include "lltoolbar.h" #include "llcommandmanager.h" +#include "llinventory.h" class LLUICtrlFactory; @@ -106,6 +107,7 @@ public: static BOOL handleDragTool(S32 x, S32 y, const LLUUID& uuid, LLAssetType::EType type); static BOOL handleDropTool(void* cargo_data, S32 x, S32 y, LLToolBar* toolbar); static void resetDragTool(LLToolBarButton* toolbarButton); + LLInventoryObject* getDragItem(); bool isModified() const; @@ -129,6 +131,7 @@ private: bool mDragStarted; LLToolBarButton* mDragToolbarButton; + LLInventoryObject* mDragItem; bool mShowToolbars; }; diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 8c32dfcb4d..f3637756fe 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -48,6 +48,7 @@ #include "llpreviewnotecard.h" #include "llrootview.h" #include "llselectmgr.h" +#include "lltoolbarview.h" #include "lltoolmgr.h" #include "lltooltip.h" #include "lltrans.h" @@ -2527,7 +2528,7 @@ LLInventoryObject* LLToolDragAndDrop::locateInventory( } else if(mSource == SOURCE_VIEWER) { - item = (LLViewerInventoryItem*)gClipboard.getSourceObject(); + item = (LLViewerInventoryItem*)gToolBarView->getDragItem(); } if(item) return item; if(cat) return cat; diff --git a/indra/newview/llurllineeditorctrl.cpp b/indra/newview/llurllineeditorctrl.cpp index 56b5bbf942..9d7e26d41c 100644 --- a/indra/newview/llurllineeditorctrl.cpp +++ b/indra/newview/llurllineeditorctrl.cpp @@ -89,5 +89,5 @@ void LLURLLineEditor::copyEscapedURLToClipboard() else // human-readable location text_to_copy = utf8str_to_wstring(unescaped_text); - gClipboard.copyFromString( text_to_copy ); + LLClipboard::getInstance()->copyFromString( text_to_copy ); } -- cgit v1.3 From db824cff75696c42fff80ba29dbb60f12d10a1da Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Fri, 3 Feb 2012 18:38:03 -0800 Subject: EXP-1862 : Suppress LLInventoryClipboard, move its functions to the unified LLClipboard and use this only --- indra/llui/llclipboard.cpp | 102 ++++++++++++++++++++++++------ indra/llui/llclipboard.h | 27 +++++++- indra/newview/CMakeLists.txt | 2 - indra/newview/llfavoritesbar.cpp | 10 +-- indra/newview/llfloatergesture.cpp | 15 +++-- indra/newview/llfolderview.cpp | 8 +-- indra/newview/llinventorybridge.cpp | 26 ++++---- indra/newview/llinventoryclipboard.cpp | 110 --------------------------------- indra/newview/llinventoryclipboard.h | 86 -------------------------- indra/newview/llinventoryfunctions.cpp | 1 - indra/newview/lltoolbarview.cpp | 1 - 11 files changed, 138 insertions(+), 250 deletions(-) delete mode 100644 indra/newview/llinventoryclipboard.cpp delete mode 100644 indra/newview/llinventoryclipboard.h (limited to 'indra/llui') diff --git a/indra/llui/llclipboard.cpp b/indra/llui/llclipboard.cpp index 984c4ec5fb..8917dc2d88 100644 --- a/indra/llui/llclipboard.cpp +++ b/indra/llui/llclipboard.cpp @@ -34,44 +34,104 @@ #include "llview.h" #include "llwindow.h" -// Global singleton -LLClipboard gClipboard; +LLClipboard::LLClipboard() +: mCutMode(false) +{ +} +LLClipboard::~LLClipboard() +{ + reset(); +} -LLClipboard::LLClipboard() +void LLClipboard::add(const LLUUID& object) { + mObjects.put(object); } +void LLClipboard::store(const LLUUID& object) +{ + reset(); + mObjects.put(object); +} -LLClipboard::~LLClipboard() +void LLClipboard::store(const LLDynamicArray& inv_objects) { + reset(); + S32 count = inv_objects.count(); + for(S32 i = 0; i < count; i++) + { + mObjects.put(inv_objects[i]); + } +} + +void LLClipboard::cut(const LLUUID& object) +{ + if(!mCutMode && !mObjects.empty()) + { + //looks like there are some stored items, reset clipboard state + reset(); + } + mCutMode = true; + add(object); +} +void LLClipboard::retrieve(LLDynamicArray& inv_objects) const +{ + inv_objects.reset(); + S32 count = mObjects.count(); + for(S32 i = 0; i < count; i++) + { + inv_objects.put(mObjects[i]); + } +} + +void LLClipboard::reset() +{ + mObjects.reset(); + mCutMode = false; +} + +// returns true if the clipboard has something pasteable in it. +BOOL LLClipboard::hasContents() const +{ + return (mObjects.count() > 0); } void LLClipboard::copyFromSubstring(const LLWString &src, S32 pos, S32 len, const LLUUID& source_id ) { - mSourceID = source_id; + reset(); + if (source_id.notNull()) + { + store(source_id); + } mString = src.substr(pos, len); + llinfos << "Merov debug : copyFromSubstring, string = " << wstring_to_utf8str(mString) << ", uuid = " << (hasContents() ? mObjects[0] : LLUUID::null) << llendl; LLView::getWindow()->copyTextToClipboard( mString ); } void LLClipboard::copyFromString(const LLWString &src, const LLUUID& source_id ) { - mSourceID = source_id; + reset(); + if (source_id.notNull()) + { + store(source_id); + } mString = src; + llinfos << "Merov debug : copyFromString, string = " << wstring_to_utf8str(mString) << ", uuid = " << (hasContents() ? mObjects[0] : LLUUID::null) << llendl; LLView::getWindow()->copyTextToClipboard( mString ); } const LLWString& LLClipboard::getPasteWString( LLUUID* source_id ) { - if( mSourceID.notNull() ) + if (hasContents()) { LLWString temp_string; LLView::getWindow()->pasteTextFromClipboard(temp_string); - if( temp_string != mString ) + if (temp_string != mString) { - mSourceID.setNull(); + reset(); mString = temp_string; } } @@ -80,11 +140,13 @@ const LLWString& LLClipboard::getPasteWString( LLUUID* source_id ) LLView::getWindow()->pasteTextFromClipboard(mString); } - if( source_id ) + if (source_id) { - *source_id = mSourceID; + *source_id = (hasContents() ? mObjects[0] : LLUUID::null); } + llinfos << "Merov debug : getPasteWString, string = " << wstring_to_utf8str(mString) << ", uuid = " << (hasContents() ? mObjects[0] : LLUUID::null) << llendl; + return mString; } @@ -97,7 +159,11 @@ BOOL LLClipboard::canPasteString() const void LLClipboard::copyFromPrimarySubstring(const LLWString &src, S32 pos, S32 len, const LLUUID& source_id ) { - mSourceID = source_id; + reset(); + if (source_id.notNull()) + { + store(source_id); + } mString = src.substr(pos, len); LLView::getWindow()->copyTextToPrimary( mString ); } @@ -105,14 +171,14 @@ void LLClipboard::copyFromPrimarySubstring(const LLWString &src, S32 pos, S32 le const LLWString& LLClipboard::getPastePrimaryWString( LLUUID* source_id ) { - if( mSourceID.notNull() ) + if (hasContents()) { LLWString temp_string; LLView::getWindow()->pasteTextFromPrimary(temp_string); - if( temp_string != mString ) + if (temp_string != mString) { - mSourceID.setNull(); + reset(); mString = temp_string; } } @@ -121,11 +187,11 @@ const LLWString& LLClipboard::getPastePrimaryWString( LLUUID* source_id ) LLView::getWindow()->pasteTextFromPrimary(mString); } - if( source_id ) + if (source_id) { - *source_id = mSourceID; + *source_id = (hasContents() ? mObjects[0] : LLUUID::null); } - + return mString; } diff --git a/indra/llui/llclipboard.h b/indra/llui/llclipboard.h index 2567eaab48..2cb857145e 100644 --- a/indra/llui/llclipboard.h +++ b/indra/llui/llclipboard.h @@ -34,6 +34,13 @@ #include "llsingleton.h" #include "llinventory.h" +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLClipboard +// +// This class is used to cut/copy/paste text strings and inventory items around +// the world. Use LLClipboard::getInstance()->method() to use its methods. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + class LLClipboard : public LLSingleton { public: @@ -45,20 +52,36 @@ public: which is implicitly copied upon selection on platforms which expect this (i.e. X11/Linux). */ + // Text strings management void copyFromSubstring(const LLWString ©_from, S32 pos, S32 len, const LLUUID& source_id = LLUUID::null ); void copyFromString(const LLWString ©_from, const LLUUID& source_id = LLUUID::null ); BOOL canPasteString() const; const LLWString& getPasteWString(LLUUID* source_id = NULL); + // Primary text string management (Linux gtk implementation) void copyFromPrimarySubstring(const LLWString ©_from, S32 pos, S32 len, const LLUUID& source_id = LLUUID::null ); BOOL canPastePrimaryString() const; const LLWString& getPastePrimaryWString(LLUUID* source_id = NULL); // Support clipboard for object known only by their uuid - void setSourceObject(const LLUUID& source_id) { mSourceID = source_id; } + //void setSourceObject(const LLUUID& source_id) { mSourceID = source_id; } + + // Object list management + void add(const LLUUID& object); // Adds to the current list of objects on the clipboard + void store(const LLUUID& object); // Stores a single inventory object + void store(const LLDynamicArray& inventory_objects); // Stores an array of objects + void cut(const LLUUID& object); // Adds to the current list of cut objects on the clipboard + void retrieve(LLDynamicArray& inventory_objects) const; // Gets a copy of the objects on the clipboard + void reset(); // Clears the clipboard + BOOL hasContents() const; // true if the clipboard has something pasteable in it + bool isCutMode() const { return mCutMode; } + private: - LLUUID mSourceID; + // *TODO: To know if an asset ID can be serialized, check out LLAssetType::lookupIsAssetIDKnowable(EType asset_type) + LLDynamicArray mObjects; + bool mCutMode; + LLWString mString; }; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 69bf1f15a1..325c2a12a6 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -287,7 +287,6 @@ set(viewer_SOURCE_FILES llinspectremoteobject.cpp llinspecttoast.cpp llinventorybridge.cpp - llinventoryclipboard.cpp llinventoryfilter.cpp llinventoryfunctions.cpp llinventoryicon.cpp @@ -842,7 +841,6 @@ set(viewer_HEADER_FILES llinspectremoteobject.h llinspecttoast.h llinventorybridge.h - llinventoryclipboard.h llinventoryfilter.h llinventoryfunctions.h llinventoryicon.h diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 24bd2cf313..c81bff4b5d 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -39,7 +39,7 @@ #include "llagent.h" #include "llclipboard.h" -#include "llinventoryclipboard.h" +#include "llclipboard.h" #include "llinventorybridge.h" #include "llinventoryfunctions.h" #include "llfloatersidepanelcontainer.h" @@ -1187,7 +1187,7 @@ void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata) } else if (action == "copy") { - LLInventoryClipboard::instance().store(mSelectedItemID); + LLClipboard::getInstance()->store(mSelectedItemID); } else if (action == "paste") { @@ -1211,13 +1211,13 @@ void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata) BOOL LLFavoritesBarCtrl::isClipboardPasteable() const { - if (!LLInventoryClipboard::instance().hasContents()) + if (!LLClipboard::getInstance()->hasContents()) { return FALSE; } LLDynamicArray objects; - LLInventoryClipboard::instance().retrieve(objects); + LLClipboard::getInstance()->retrieve(objects); S32 count = objects.count(); for(S32 i = 0; i < count; i++) { @@ -1246,7 +1246,7 @@ void LLFavoritesBarCtrl::pastFromClipboard() const { LLInventoryItem* item = NULL; LLDynamicArray objects; - LLInventoryClipboard::instance().retrieve(objects); + LLClipboard::getInstance()->retrieve(objects); S32 count = objects.count(); LLUUID parent_id(mFavoriteFolderId); for(S32 i = 0; i < count; i++) diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp index e025d6edb5..281cafa90d 100644 --- a/indra/newview/llfloatergesture.cpp +++ b/indra/newview/llfloatergesture.cpp @@ -32,7 +32,7 @@ #include "llinventorybridge.h" #include "llinventoryfunctions.h" #include "llinventorymodel.h" -#include "llinventoryclipboard.h" +#include "llclipboard.h" #include "llagent.h" #include "llappearancemgr.h" @@ -391,11 +391,11 @@ bool LLFloaterGesture::isActionEnabled(const LLSD& command) std::string command_name = command.asString(); if("paste" == command_name) { - if(!LLInventoryClipboard::instance().hasContents()) + if(!LLClipboard::getInstance()->hasContents()) return false; LLDynamicArray ids; - LLInventoryClipboard::instance().retrieve(ids); + LLClipboard::getInstance()->retrieve(ids); for(LLDynamicArray::iterator it = ids.begin(); it != ids.end(); it++) { LLInventoryItem* item = gInventory.getItem(*it); @@ -496,21 +496,20 @@ void LLFloaterGesture::onCopyPasteAction(const LLSD& command) uuid_vec_t ids; getSelectedIds(ids); // make sure that clopboard is empty - LLInventoryClipboard::instance().reset(); + LLClipboard::getInstance()->reset(); for(uuid_vec_t::iterator it = ids.begin(); it != ids.end(); it++) { LLInventoryItem* item = gInventory.getItem(*it); if(item && item->getInventoryType() == LLInventoryType::IT_GESTURE) { - LLInventoryClipboard::instance().add(item->getUUID()); + LLClipboard::getInstance()->add(item->getUUID()); } } } else if ("paste" == command_name) { - LLInventoryClipboard& clipbord = LLInventoryClipboard::instance(); LLDynamicArray ids; - clipbord.retrieve(ids); + LLClipboard::getInstance()->retrieve(ids); if(ids.empty() || !gInventory.isCategoryComplete(mGestureFolderID)) return; LLInventoryCategory* gesture_dir = gInventory.getCategory(mGestureFolderID); @@ -530,7 +529,7 @@ void LLFloaterGesture::onCopyPasteAction(const LLSD& command) gesture_dir->getUUID(), getString("copy_name", string_args), cb); } } - clipbord.reset(); + LLClipboard::getInstance()->reset(); } else if ("copy_uuid" == command_name) { diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 79c987fa37..438d7e7ae3 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -30,7 +30,7 @@ #include "llcallbacklist.h" #include "llinventorybridge.h" -#include "llinventoryclipboard.h" // *TODO: remove this once hack below gone. +#include "llclipboard.h" // *TODO: remove this once hack below gone. #include "llinventoryfilter.h" #include "llinventoryfunctions.h" #include "llinventorymodelbackgroundfetch.h" @@ -1293,7 +1293,7 @@ BOOL LLFolderView::canCopy() const void LLFolderView::copy() { // *NOTE: total hack to clear the inventory clipboard - LLInventoryClipboard::instance().reset(); + LLClipboard::getInstance()->reset(); S32 count = mSelectedItems.size(); if(getVisible() && getEnabled() && (count > 0)) { @@ -1334,7 +1334,7 @@ BOOL LLFolderView::canCut() const void LLFolderView::cut() { // clear the inventory clipboard - LLInventoryClipboard::instance().reset(); + LLClipboard::getInstance()->reset(); S32 count = mSelectedItems.size(); if(getVisible() && getEnabled() && (count > 0)) { @@ -2111,7 +2111,7 @@ bool LLFolderView::doToSelected(LLInventoryModel* model, const LLSD& userdata) if ("copy" == action) { - LLInventoryClipboard::instance().reset(); + LLClipboard::getInstance()->reset(); } static const std::string change_folder_string = "change_folder_type_"; diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 869cb735d5..420b834933 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -47,7 +47,7 @@ #include "llgiveinventory.h" #include "llimfloater.h" #include "llimview.h" -#include "llinventoryclipboard.h" +#include "llclipboard.h" #include "llinventorydefines.h" #include "llinventoryfunctions.h" #include "llinventorymodel.h" @@ -212,7 +212,7 @@ void LLInvFVBridge::cutToClipboard() { if(isItemMovable()) { - LLInventoryClipboard::instance().cut(mUUID); + LLClipboard::getInstance()->cut(mUUID); } } // *TODO: make sure this does the right thing @@ -397,7 +397,7 @@ void LLInvFVBridge::removeBatchNoCheck(LLDynamicArrayhasContents() || !isAgentInventory()) { return FALSE; } @@ -410,7 +410,7 @@ BOOL LLInvFVBridge::isClipboardPasteable() const const LLUUID &agent_id = gAgent.getID(); LLDynamicArray objects; - LLInventoryClipboard::instance().retrieve(objects); + LLClipboard::getInstance()->retrieve(objects); S32 count = objects.count(); for(S32 i = 0; i < count; i++) { @@ -437,7 +437,7 @@ BOOL LLInvFVBridge::isClipboardPasteable() const BOOL LLInvFVBridge::isClipboardPasteableAsLink() const { - if (!LLInventoryClipboard::instance().hasContents() || !isAgentInventory()) + if (!LLClipboard::getInstance()->hasContents() || !isAgentInventory()) { return FALSE; } @@ -448,7 +448,7 @@ BOOL LLInvFVBridge::isClipboardPasteableAsLink() const } LLDynamicArray objects; - LLInventoryClipboard::instance().retrieve(objects); + LLClipboard::getInstance()->retrieve(objects); S32 count = objects.count(); for(S32 i = 0; i < count; i++) { @@ -1663,7 +1663,7 @@ BOOL LLItemBridge::copyToClipboard() const { if(isItemCopyable()) { - LLInventoryClipboard::instance().add(mUUID); + LLClipboard::getInstance()->add(mUUID); return TRUE; } return FALSE; @@ -1775,7 +1775,7 @@ BOOL LLFolderBridge::copyToClipboard() const { if(isItemCopyable()) { - LLInventoryClipboard::instance().add(mUUID); + LLClipboard::getInstance()->add(mUUID); return TRUE; } return FALSE; @@ -1796,7 +1796,7 @@ BOOL LLFolderBridge::isClipboardPasteable() const } LLDynamicArray objects; - LLInventoryClipboard::instance().retrieve(objects); + LLClipboard::getInstance()->retrieve(objects); const LLViewerInventoryCategory *current_cat = getCategory(); // Search for the direct descendent of current Friends subfolder among all pasted items, @@ -1834,7 +1834,7 @@ BOOL LLFolderBridge::isClipboardPasteableAsLink() const const BOOL is_in_friend_folder = LLFriendCardsManager::instance().isCategoryInFriendFolder( current_cat ); const LLUUID ¤t_cat_id = current_cat->getUUID(); LLDynamicArray objects; - LLInventoryClipboard::instance().retrieve(objects); + LLClipboard::getInstance()->retrieve(objects); S32 count = objects.count(); for(S32 i = 0; i < count; i++) { @@ -2825,7 +2825,7 @@ void LLFolderBridge::pasteFromClipboard() const LLUUID parent_id(mUUID); LLDynamicArray objects; - LLInventoryClipboard::instance().retrieve(objects); + LLClipboard::getInstance()->retrieve(objects); for (LLDynamicArray::const_iterator iter = objects.begin(); iter != objects.end(); ++iter) @@ -2841,7 +2841,7 @@ void LLFolderBridge::pasteFromClipboard() dropToOutfit(item, move_is_into_current_outfit); } } - else if(LLInventoryClipboard::instance().isCutMode()) + else if (LLClipboard::getInstance()->isCutMode()) { // move_inventory_item() is not enough, //we have to update inventory locally too @@ -2879,7 +2879,7 @@ void LLFolderBridge::pasteLinkFromClipboard() const LLUUID parent_id(mUUID); LLDynamicArray objects; - LLInventoryClipboard::instance().retrieve(objects); + LLClipboard::getInstance()->retrieve(objects); for (LLDynamicArray::const_iterator iter = objects.begin(); iter != objects.end(); ++iter) diff --git a/indra/newview/llinventoryclipboard.cpp b/indra/newview/llinventoryclipboard.cpp deleted file mode 100644 index 53da34f448..0000000000 --- a/indra/newview/llinventoryclipboard.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/** - * @file llinventoryclipboard.cpp - * @brief LLInventoryClipboard class implementation - * - * $LicenseInfo:firstyear=2002&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 "llinventoryclipboard.h" - - -LLInventoryClipboard LLInventoryClipboard::sInstance; - -///---------------------------------------------------------------------------- -/// Local function declarations, constants, enums, and typedefs -///---------------------------------------------------------------------------- - - -///---------------------------------------------------------------------------- -/// Class LLInventoryClipboard -///---------------------------------------------------------------------------- - -LLInventoryClipboard::LLInventoryClipboard() -: mCutMode(false) -{ -} - -LLInventoryClipboard::~LLInventoryClipboard() -{ - reset(); -} - -void LLInventoryClipboard::add(const LLUUID& object) -{ - mObjects.put(object); -} - -// this stores a single inventory object -void LLInventoryClipboard::store(const LLUUID& object) -{ - reset(); - mObjects.put(object); -} - -void LLInventoryClipboard::store(const LLDynamicArray& inv_objects) -{ - reset(); - S32 count = inv_objects.count(); - for(S32 i = 0; i < count; i++) - { - mObjects.put(inv_objects[i]); - } -} - -void LLInventoryClipboard::cut(const LLUUID& object) -{ - if(!mCutMode && !mObjects.empty()) - { - //looks like there are some stored items, reset clipboard state - reset(); - } - mCutMode = true; - add(object); -} -void LLInventoryClipboard::retrieve(LLDynamicArray& inv_objects) const -{ - inv_objects.reset(); - S32 count = mObjects.count(); - for(S32 i = 0; i < count; i++) - { - inv_objects.put(mObjects[i]); - } -} - -void LLInventoryClipboard::reset() -{ - mObjects.reset(); - mCutMode = false; -} - -// returns true if the clipboard has something pasteable in it. -BOOL LLInventoryClipboard::hasContents() const -{ - return (mObjects.count() > 0); -} - - -///---------------------------------------------------------------------------- -/// Local function definitions -///---------------------------------------------------------------------------- diff --git a/indra/newview/llinventoryclipboard.h b/indra/newview/llinventoryclipboard.h deleted file mode 100644 index b9f1451e5c..0000000000 --- a/indra/newview/llinventoryclipboard.h +++ /dev/null @@ -1,86 +0,0 @@ -/** - * @file llinventoryclipboard.h - * @brief LLInventoryClipboard class header file - * - * $LicenseInfo:firstyear=2002&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_LLINVENTORYCLIPBOARD_H -#define LL_LLINVENTORYCLIPBOARD_H - -#include "lldarray.h" -#include "lluuid.h" - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryClipboard -// -// This class is used to cut/copy/paste inventory items around the -// world. This class is accessed through a singleton (only one -// inventory clipboard for now) which can be referenced using the -// instance() method. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLInventoryClipboard -{ -public: - // calling this before main() is undefined - static LLInventoryClipboard& instance() { return sInstance; } - - // this method adds to the current list. - void add(const LLUUID& object); - - // this stores a single inventory object - void store(const LLUUID& object); - - // this method stores an array of objects - void store(const LLDynamicArray& inventory_objects); - - void cut(const LLUUID& object); - // this method gets the objects in the clipboard by copying them - // into the array provided. - void retrieve(LLDynamicArray& inventory_objects) const; - - // this method empties out the clipboard - void reset(); - - // returns true if the clipboard has something pasteable in it. - BOOL hasContents() const; - bool isCutMode() const { return mCutMode; } - -protected: - static LLInventoryClipboard sInstance; - - LLDynamicArray mObjects; - bool mCutMode; - -public: - // please don't actually call these - LLInventoryClipboard(); - ~LLInventoryClipboard(); -private: - // please don't implement these - LLInventoryClipboard(const LLInventoryClipboard&); - LLInventoryClipboard& operator=(const LLInventoryClipboard&); -}; - - -#endif // LL_LLINVENTORYCLIPBOARD_H diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index dd92188e9d..ea00474b2a 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -54,7 +54,6 @@ #include "lliconctrl.h" #include "llimview.h" #include "llinventorybridge.h" -#include "llinventoryclipboard.h" #include "llinventorymodel.h" #include "llinventorypanel.h" #include "lllineeditor.h" diff --git a/indra/newview/lltoolbarview.cpp b/indra/newview/lltoolbarview.cpp index 8a0b035234..81ad96f39e 100644 --- a/indra/newview/lltoolbarview.cpp +++ b/indra/newview/lltoolbarview.cpp @@ -580,7 +580,6 @@ BOOL LLToolBarView::handleDragTool( S32 x, S32 y, const LLUUID& uuid, LLAssetTyp uuid_vec_t cargo_ids; types.push_back(DAD_WIDGET); cargo_ids.push_back(uuid); - LLClipboard::getInstance()->setSourceObject(uuid); LLToolDragAndDrop::ESource src = LLToolDragAndDrop::SOURCE_VIEWER; LLUUID srcID; LLToolDragAndDrop::getInstance()->beginMultiDrag(types, cargo_ids, src, srcID); -- cgit v1.3 From 9761375ac244af36635899c73e99efc46b68b589 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Mon, 6 Feb 2012 15:43:53 -0800 Subject: EXP-1841 : Refactoring of LLClipboard, simplify the API and make it behave like a normal clipboard. --- indra/llui/llclipboard.cpp | 112 +++++++++---------------------- indra/llui/llclipboard.h | 23 ++----- indra/llui/lllineeditor.cpp | 19 ++---- indra/llui/llscrolllistctrl.cpp | 2 +- indra/llui/lltexteditor.cpp | 20 ++---- indra/newview/llfavoritesbar.cpp | 2 +- indra/newview/llfloatergesture.cpp | 2 +- indra/newview/llinventorybridge.cpp | 3 + indra/newview/llpanelteleporthistory.cpp | 2 +- indra/newview/llpaneltopinfobar.cpp | 2 +- indra/newview/llpanelwearing.cpp | 2 +- indra/newview/llurllineeditorctrl.cpp | 2 +- 12 files changed, 60 insertions(+), 131 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llclipboard.cpp b/indra/llui/llclipboard.cpp index 8917dc2d88..5c8db29ae4 100644 --- a/indra/llui/llclipboard.cpp +++ b/indra/llui/llclipboard.cpp @@ -91,112 +91,62 @@ void LLClipboard::reset() mCutMode = false; } -// returns true if the clipboard has something pasteable in it. +// Returns true if the LL Clipboard has pasteable items in it BOOL LLClipboard::hasContents() const { return (mObjects.count() > 0); } - -void LLClipboard::copyFromSubstring(const LLWString &src, S32 pos, S32 len, const LLUUID& source_id ) +// Copy the input string to the LL and the system clipboard +bool LLClipboard::copyToClipboard(const LLWString &src, S32 pos, S32 len, bool use_primary) { reset(); - if (source_id.notNull()) - { - store(source_id); - } mString = src.substr(pos, len); - llinfos << "Merov debug : copyFromSubstring, string = " << wstring_to_utf8str(mString) << ", uuid = " << (hasContents() ? mObjects[0] : LLUUID::null) << llendl; - LLView::getWindow()->copyTextToClipboard( mString ); + return (use_primary ? LLView::getWindow()->copyTextToPrimary(mString) : LLView::getWindow()->copyTextToClipboard(mString)); } -void LLClipboard::copyFromString(const LLWString &src, const LLUUID& source_id ) +// Copy the input uuid to the LL clipboard +// Convert the uuid to string and copy that string to the system clipboard if legit +bool LLClipboard::copyToClipboard(const LLUUID& src, const LLAssetType::EType type) { + bool res = false; reset(); - if (source_id.notNull()) - { - store(source_id); - } - mString = src; - llinfos << "Merov debug : copyFromString, string = " << wstring_to_utf8str(mString) << ", uuid = " << (hasContents() ? mObjects[0] : LLUUID::null) << llendl; - LLView::getWindow()->copyTextToClipboard( mString ); -} - -const LLWString& LLClipboard::getPasteWString( LLUUID* source_id ) -{ - if (hasContents()) + if (src.notNull()) { - LLWString temp_string; - LLView::getWindow()->pasteTextFromClipboard(temp_string); - - if (temp_string != mString) + res = true; + if (LLAssetType::lookupIsAssetIDKnowable(type)) { - reset(); - mString = temp_string; + LLWString source = utf8str_to_wstring(src.asString()); + res = copyToClipboard(source, 0, source.size()); + } + if (res) + { + store(src); } } - else - { - LLView::getWindow()->pasteTextFromClipboard(mString); - } - - if (source_id) - { - *source_id = (hasContents() ? mObjects[0] : LLUUID::null); - } - - llinfos << "Merov debug : getPasteWString, string = " << wstring_to_utf8str(mString) << ", uuid = " << (hasContents() ? mObjects[0] : LLUUID::null) << llendl; - - return mString; -} - - -BOOL LLClipboard::canPasteString() const -{ - return LLView::getWindow()->isClipboardTextAvailable(); -} - - -void LLClipboard::copyFromPrimarySubstring(const LLWString &src, S32 pos, S32 len, const LLUUID& source_id ) -{ - reset(); - if (source_id.notNull()) - { - store(source_id); - } - mString = src.substr(pos, len); - LLView::getWindow()->copyTextToPrimary( mString ); + return res; } - -const LLWString& LLClipboard::getPastePrimaryWString( LLUUID* source_id ) +// Copy the System clipboard to the output string. +// Manage the LL Clipboard / System clipboard consistency +bool LLClipboard::pasteFromClipboard(LLWString &dst, bool use_primary) { - if (hasContents()) + bool res = (use_primary ? LLView::getWindow()->pasteTextFromPrimary(dst) : LLView::getWindow()->pasteTextFromClipboard(dst)); + if (res) { - LLWString temp_string; - LLView::getWindow()->pasteTextFromPrimary(temp_string); - - if (temp_string != mString) + if (dst != mString) { + // Invalidate the LL clipboard if the System had a different string in it (i.e. some copy/cut was done in some other app) reset(); - mString = temp_string; } + mString = dst; } - else - { - LLView::getWindow()->pasteTextFromPrimary(mString); - } - - if (source_id) - { - *source_id = (hasContents() ? mObjects[0] : LLUUID::null); - } - - return mString; + return res; } - -BOOL LLClipboard::canPastePrimaryString() const +// Return true if there's something on the System clipboard +bool LLClipboard::isTextAvailable(bool use_primary) const { - return LLView::getWindow()->isPrimaryTextAvailable(); + return (use_primary ? LLView::getWindow()->isPrimaryTextAvailable() : LLView::getWindow()->isClipboardTextAvailable()); } + diff --git a/indra/llui/llclipboard.h b/indra/llui/llclipboard.h index 2cb857145e..bb2d003703 100644 --- a/indra/llui/llclipboard.h +++ b/indra/llui/llclipboard.h @@ -32,6 +32,7 @@ #include "lluuid.h" #include "stdenums.h" #include "llsingleton.h" +#include "llassettype.h" #include "llinventory.h" //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -52,19 +53,11 @@ public: which is implicitly copied upon selection on platforms which expect this (i.e. X11/Linux). */ - // Text strings management - void copyFromSubstring(const LLWString ©_from, S32 pos, S32 len, const LLUUID& source_id = LLUUID::null ); - void copyFromString(const LLWString ©_from, const LLUUID& source_id = LLUUID::null ); - BOOL canPasteString() const; - const LLWString& getPasteWString(LLUUID* source_id = NULL); - - // Primary text string management (Linux gtk implementation) - void copyFromPrimarySubstring(const LLWString ©_from, S32 pos, S32 len, const LLUUID& source_id = LLUUID::null ); - BOOL canPastePrimaryString() const; - const LLWString& getPastePrimaryWString(LLUUID* source_id = NULL); - - // Support clipboard for object known only by their uuid - //void setSourceObject(const LLUUID& source_id) { mSourceID = source_id; } + // Text strings and single item management + bool copyToClipboard(const LLWString& src, S32 pos, S32 len, bool use_primary = false); + bool copyToClipboard(const LLUUID& src, const LLAssetType::EType type = LLAssetType::AT_NONE); + bool pasteFromClipboard(LLWString& dst, bool use_primary = false); + bool isTextAvailable(bool use_primary = false) const; // Object list management void add(const LLUUID& object); // Adds to the current list of objects on the clipboard @@ -78,11 +71,9 @@ public: bool isCutMode() const { return mCutMode; } private: - // *TODO: To know if an asset ID can be serialized, check out LLAssetType::lookupIsAssetIDKnowable(EType asset_type) LLDynamicArray mObjects; bool mCutMode; - - LLWString mString; + LLWString mString; }; #endif // LL_LLCLIPBOARD_H diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 9292158b7c..e961cfb14f 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -1047,7 +1047,7 @@ void LLLineEditor::cut() // Prepare for possible rollback LLLineEditorRollback rollback( this ); - LLClipboard::getInstance()->copyFromSubstring( mText.getWString(), left_pos, length ); + LLClipboard::getInstance()->copyToClipboard( mText.getWString(), left_pos, length ); deleteSelection(); // Validate new string and rollback the if needed. @@ -1078,13 +1078,13 @@ void LLLineEditor::copy() { S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); S32 length = llabs( mSelectionStart - mSelectionEnd ); - LLClipboard::getInstance()->copyFromSubstring( mText.getWString(), left_pos, length ); + LLClipboard::getInstance()->copyToClipboard( mText.getWString(), left_pos, length ); } } BOOL LLLineEditor::canPaste() const { - return !mReadOnly && LLClipboard::getInstance()->canPasteString(); + return !mReadOnly && LLClipboard::getInstance()->isTextAvailable(); } void LLLineEditor::paste() @@ -1115,14 +1115,7 @@ void LLLineEditor::pasteHelper(bool is_primary) if (can_paste_it) { LLWString paste; - if (is_primary) - { - paste = LLClipboard::getInstance()->getPastePrimaryWString(); - } - else - { - paste = LLClipboard::getInstance()->getPasteWString(); - } + LLClipboard::getInstance()->pasteFromClipboard(paste, is_primary); if (!paste.empty()) { @@ -1209,13 +1202,13 @@ void LLLineEditor::copyPrimary() { S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); S32 length = llabs( mSelectionStart - mSelectionEnd ); - LLClipboard::getInstance()->copyFromPrimarySubstring( mText.getWString(), left_pos, length ); + LLClipboard::getInstance()->copyToClipboard( mText.getWString(), left_pos, length, true); } } BOOL LLLineEditor::canPastePrimary() const { - return !mReadOnly && LLClipboard::getInstance()->canPastePrimaryString(); + return !mReadOnly && LLClipboard::getInstance()->isTextAvailable(true); } void LLLineEditor::updatePrimary() diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 8cbc2a8f99..0a9d862b66 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -2504,7 +2504,7 @@ void LLScrollListCtrl::copy() { buffer += (*itor)->getContentsCSV() + "\n"; } - LLClipboard::getInstance()->copyFromSubstring(utf8str_to_wstring(buffer), 0, buffer.length()); + LLClipboard::getInstance()->copyToClipboard(utf8str_to_wstring(buffer), 0, buffer.length()); } // virtual diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 22a577cda8..ffe012c110 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -1332,7 +1332,7 @@ void LLTextEditor::cut() } S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); S32 length = llabs( mSelectionStart - mSelectionEnd ); - LLClipboard::getInstance()->copyFromSubstring( getWText(), left_pos, length, mSourceID ); + LLClipboard::getInstance()->copyToClipboard( getWText(), left_pos, length); deleteSelection( FALSE ); onKeyStroke(); @@ -1352,12 +1352,12 @@ void LLTextEditor::copy() } S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); S32 length = llabs( mSelectionStart - mSelectionEnd ); - LLClipboard::getInstance()->copyFromSubstring(getWText(), left_pos, length, mSourceID); + LLClipboard::getInstance()->copyToClipboard(getWText(), left_pos, length); } BOOL LLTextEditor::canPaste() const { - return !mReadOnly && LLClipboard::getInstance()->canPasteString(); + return !mReadOnly && LLClipboard::getInstance()->isTextAvailable(); } // paste from clipboard @@ -1393,16 +1393,8 @@ void LLTextEditor::pasteHelper(bool is_primary) return; } - LLUUID source_id; LLWString paste; - if (is_primary) - { - paste = LLClipboard::getInstance()->getPastePrimaryWString(&source_id); - } - else - { - paste = LLClipboard::getInstance()->getPasteWString(&source_id); - } + LLClipboard::getInstance()->pasteFromClipboard(paste, is_primary); if (paste.empty()) { @@ -1475,12 +1467,12 @@ void LLTextEditor::copyPrimary() } S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); S32 length = llabs( mSelectionStart - mSelectionEnd ); - LLClipboard::getInstance()->copyFromPrimarySubstring(getWText(), left_pos, length, mSourceID); + LLClipboard::getInstance()->copyToClipboard(getWText(), left_pos, length, true); } BOOL LLTextEditor::canPastePrimary() const { - return !mReadOnly && LLClipboard::getInstance()->canPastePrimaryString(); + return !mReadOnly && LLClipboard::getInstance()->isTextAvailable(true); } void LLTextEditor::updatePrimary() diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index c81bff4b5d..4308bf2d3c 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -1118,7 +1118,7 @@ BOOL LLFavoritesBarCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) } void copy_slurl_to_clipboard_cb(std::string& slurl) { - LLClipboard::getInstance()->copyFromString(utf8str_to_wstring(slurl)); + LLClipboard::getInstance()->copyToClipboard(utf8str_to_wstring(slurl),0,slurl.size()); LLSD args; args["SLURL"] = slurl; diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp index 281cafa90d..3c647284f6 100644 --- a/indra/newview/llfloatergesture.cpp +++ b/indra/newview/llfloatergesture.cpp @@ -533,7 +533,7 @@ void LLFloaterGesture::onCopyPasteAction(const LLSD& command) } else if ("copy_uuid" == command_name) { - LLClipboard::getInstance()->copyFromString(utf8str_to_wstring(mGestureList->getCurrentID().asString()), mGestureList->getCurrentID()); + LLClipboard::getInstance()->copyToClipboard(mGestureList->getCurrentID(),LLAssetType::AT_GESTURE); } } diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 420b834933..14f1bb9d41 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -409,6 +409,9 @@ BOOL LLInvFVBridge::isClipboardPasteable() const const LLUUID &agent_id = gAgent.getID(); + // Merov : This should be suppressed for 2 reasons: + // 1. folders should be pastable + // 2. when pasting, we should paste what is authorized and let the rest not pasted LLDynamicArray objects; LLClipboard::getInstance()->retrieve(objects); S32 count = objects.count(); diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp index a4c9af3fad..f92fbf3220 100644 --- a/indra/newview/llpanelteleporthistory.cpp +++ b/indra/newview/llpanelteleporthistory.cpp @@ -358,7 +358,7 @@ void LLTeleportHistoryPanel::ContextMenu::onInfo() //static void LLTeleportHistoryPanel::ContextMenu::gotSLURLCallback(const std::string& slurl) { - LLClipboard::getInstance()->copyFromString(utf8str_to_wstring(slurl)); + LLClipboard::getInstance()->copyToClipboard(utf8str_to_wstring(slurl),0,slurl.size()); } void LLTeleportHistoryPanel::ContextMenu::onCopyToClipboard() diff --git a/indra/newview/llpaneltopinfobar.cpp b/indra/newview/llpaneltopinfobar.cpp index 0e3ff99066..0ad207ef00 100644 --- a/indra/newview/llpaneltopinfobar.cpp +++ b/indra/newview/llpaneltopinfobar.cpp @@ -467,7 +467,7 @@ void LLPanelTopInfoBar::onContextMenuItemClicked(const LLSD::String& item) LLAgentUI::buildSLURL(slurl, false); LLUIString location_str(slurl.getSLURLString()); - LLClipboard::getInstance()->copyFromString(location_str); + LLClipboard::getInstance()->copyToClipboard(location_str,0,location_str.length()); } } diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp index 1286756693..5199bcb6b1 100644 --- a/indra/newview/llpanelwearing.cpp +++ b/indra/newview/llpanelwearing.cpp @@ -302,6 +302,6 @@ void LLPanelWearing::copyToClipboard() } } - LLClipboard::getInstance()->copyFromString(utf8str_to_wstring(text)); + LLClipboard::getInstance()->copyToClipboard(utf8str_to_wstring(text),0,text.size()); } // EOF diff --git a/indra/newview/llurllineeditorctrl.cpp b/indra/newview/llurllineeditorctrl.cpp index 9d7e26d41c..3efebcade9 100644 --- a/indra/newview/llurllineeditorctrl.cpp +++ b/indra/newview/llurllineeditorctrl.cpp @@ -89,5 +89,5 @@ void LLURLLineEditor::copyEscapedURLToClipboard() else // human-readable location text_to_copy = utf8str_to_wstring(unescaped_text); - LLClipboard::getInstance()->copyFromString( text_to_copy ); + LLClipboard::getInstance()->copyToClipboard(text_to_copy, 0, text_to_copy.size()); } -- cgit v1.3 From c744603af9b53c6bc73fefbd56de68cf2778ed70 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Tue, 7 Feb 2012 17:13:24 -0800 Subject: EXP-1873 : Implement cut in the inventory contextual menu. Works without deleting the items but simply dimming them and moving them. Doesn't work for folders yet. --- indra/llui/llclipboard.cpp | 6 ++++++ indra/llui/llclipboard.h | 2 ++ indra/newview/llfolderview.cpp | 3 +-- indra/newview/llfolderviewitem.cpp | 9 ++++++++- indra/newview/llinventorybridge.cpp | 22 +++++++++++++++++++++- .../skins/default/xui/en/menu_inventory.xml | 8 ++++++++ 6 files changed, 46 insertions(+), 4 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llclipboard.cpp b/indra/llui/llclipboard.cpp index 5c8db29ae4..a2a3f7f285 100644 --- a/indra/llui/llclipboard.cpp +++ b/indra/llui/llclipboard.cpp @@ -97,6 +97,12 @@ BOOL LLClipboard::hasContents() const return (mObjects.count() > 0); } +// Returns true if the input uuid is in the list of clipboard objects +bool LLClipboard::isOnClipboard(const LLUUID& object) const +{ + return (mObjects.find(object) != LLDynamicArray::FAIL); +} + // Copy the input string to the LL and the system clipboard bool LLClipboard::copyToClipboard(const LLWString &src, S32 pos, S32 len, bool use_primary) { diff --git a/indra/llui/llclipboard.h b/indra/llui/llclipboard.h index bb2d003703..8e417a490d 100644 --- a/indra/llui/llclipboard.h +++ b/indra/llui/llclipboard.h @@ -69,6 +69,8 @@ public: BOOL hasContents() const; // true if the clipboard has something pasteable in it bool isCutMode() const { return mCutMode; } + void setCutMode(bool mode) { mCutMode = mode; } + bool isOnClipboard(const LLUUID& object) const; private: LLDynamicArray mObjects; diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 438d7e7ae3..1d318ca221 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -2108,8 +2108,7 @@ bool LLFolderView::doToSelected(LLInventoryModel* model, const LLSD& userdata) removeSelectedItems(); return true; } - - if ("copy" == action) + if (("copy" == action) || ("cut" == action)) { LLClipboard::getInstance()->reset(); } diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp index 734adbc648..37ef27a5d7 100644 --- a/indra/newview/llfolderviewitem.cpp +++ b/indra/newview/llfolderviewitem.cpp @@ -40,6 +40,7 @@ #include "llviewerwindow.h" // Argh, only for setCursor() // linden library includes +#include "llclipboard.h" #include "llfocusmgr.h" // gFocusMgr #include "lltrans.h" @@ -1002,7 +1003,13 @@ void LLFolderViewItem::draw() LLColor4 color = (mIsSelected && filled) ? sHighlightFgColor : sFgColor; if (highlight_link) color = sLinkColor; if (in_library) color = sLibraryColor; - + + // Cut state rendering tweak (experimental) + if (LLClipboard::getInstance()->isCutMode() && LLClipboard::getInstance()->isOnClipboard(getListener()->getUUID())) + { + color.setAlpha(0.5); + } + F32 right_x = 0; F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)TEXT_PAD - (F32)TOP_PAD; F32 text_left = (F32)(ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + mIndentation); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 14f1bb9d41..7ba914eaf6 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -210,7 +210,7 @@ BOOL LLInvFVBridge::isLink() const */ void LLInvFVBridge::cutToClipboard() { - if(isItemMovable()) + if (isItemMovable() && isItemRemovable()) { LLClipboard::getInstance()->cut(mUUID); } @@ -602,6 +602,12 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, disabled_items.push_back(std::string("Copy")); } + items.push_back(std::string("Cut")); + if (!isItemMovable() || !isItemRemovable()) + { + disabled_items.push_back(std::string("Cut")); + } + if (canListOnMarketplace()) { items.push_back(std::string("Marketplace Separator")); @@ -1281,6 +1287,11 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action) gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(buffer)); return; } + else if ("cut" == action) + { + cutToClipboard(); + return; + } else if ("copy" == action) { copyToClipboard(); @@ -2608,6 +2619,11 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action) modifyOutfit(TRUE); return; } + else if ("cut" == action) + { + cutToClipboard(); + return; + } else if ("copy" == action) { copyToClipboard(); @@ -2867,6 +2883,8 @@ void LLFolderBridge::pasteFromClipboard() } } } + // Change mode to paste for next paste + LLClipboard::getInstance()->setCutMode(false); } } @@ -2920,6 +2938,8 @@ void LLFolderBridge::pasteLinkFromClipboard() LLPointer(NULL)); } } + // Change mode to paste for next paste + LLClipboard::getInstance()->setCutMode(false); } } diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml index ef4a1bc061..b13bf5b508 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory.xml @@ -452,6 +452,14 @@ + + + Date: Tue, 7 Feb 2012 22:46:04 -0800 Subject: EXP-1841 : Final deep scrub on LLClipboard API, clean up the use of copy and cut everywhere. --- indra/llui/llclipboard.cpp | 96 +++++++++++++++---------------- indra/llui/llclipboard.h | 44 +++++++------- indra/newview/llfavoritesbar.cpp | 6 +- indra/newview/llfloatergesture.cpp | 10 ++-- indra/newview/llfoldervieweventlistener.h | 2 +- indra/newview/llinventorybridge.cpp | 52 ++++++++--------- indra/newview/llinventorybridge.h | 6 +- indra/newview/llpanelobjectinventory.cpp | 5 +- 8 files changed, 107 insertions(+), 114 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llclipboard.cpp b/indra/llui/llclipboard.cpp index a2a3f7f285..7794a0537f 100644 --- a/indra/llui/llclipboard.cpp +++ b/indra/llui/llclipboard.cpp @@ -35,8 +35,8 @@ #include "llwindow.h" LLClipboard::LLClipboard() -: mCutMode(false) { + reset(); } LLClipboard::~LLClipboard() @@ -44,55 +44,59 @@ LLClipboard::~LLClipboard() reset(); } -void LLClipboard::add(const LLUUID& object) +void LLClipboard::reset() { - mObjects.put(object); + mObjects.reset(); + mCutMode = false; + mString = LLWString(); } -void LLClipboard::store(const LLUUID& object) +// Copy the input uuid to the LL clipboard +bool LLClipboard::copyToClipboard(const LLUUID& src, const LLAssetType::EType type) { reset(); - mObjects.put(object); + return addToClipboard(src, type); } -void LLClipboard::store(const LLDynamicArray& inv_objects) +// Add the input uuid to the LL clipboard +// Convert the uuid to string and concatenate that string to the system clipboard if legit +bool LLClipboard::addToClipboard(const LLUUID& src, const LLAssetType::EType type) { - reset(); - S32 count = inv_objects.count(); - for(S32 i = 0; i < count; i++) + bool res = false; + if (src.notNull()) { - mObjects.put(inv_objects[i]); + res = true; + if (LLAssetType::lookupIsAssetIDKnowable(type)) + { + LLWString source = utf8str_to_wstring(src.asString()); + res = addToClipboard(source, 0, source.size()); + } + if (res) + { + mObjects.put(src); + } } + return res; } -void LLClipboard::cut(const LLUUID& object) +bool LLClipboard::pasteFromClipboard(LLDynamicArray& inv_objects) const { - if(!mCutMode && !mObjects.empty()) - { - //looks like there are some stored items, reset clipboard state - reset(); - } - mCutMode = true; - add(object); -} -void LLClipboard::retrieve(LLDynamicArray& inv_objects) const -{ - inv_objects.reset(); + bool res = false; S32 count = mObjects.count(); - for(S32 i = 0; i < count; i++) + if (count > 0) { - inv_objects.put(mObjects[i]); + res = true; + inv_objects.reset(); + for (S32 i = 0; i < count; i++) + { + inv_objects.put(mObjects[i]); + } } -} - -void LLClipboard::reset() -{ - mObjects.reset(); - mCutMode = false; + return res; } // Returns true if the LL Clipboard has pasteable items in it -BOOL LLClipboard::hasContents() const +bool LLClipboard::hasContents() const { return (mObjects.count() > 0); } @@ -107,30 +111,22 @@ bool LLClipboard::isOnClipboard(const LLUUID& object) const bool LLClipboard::copyToClipboard(const LLWString &src, S32 pos, S32 len, bool use_primary) { reset(); - mString = src.substr(pos, len); - return (use_primary ? LLView::getWindow()->copyTextToPrimary(mString) : LLView::getWindow()->copyTextToClipboard(mString)); + return addToClipboard(src, pos, len, use_primary); } -// Copy the input uuid to the LL clipboard -// Convert the uuid to string and copy that string to the system clipboard if legit -bool LLClipboard::copyToClipboard(const LLUUID& src, const LLAssetType::EType type) +// Concatenate the input string to the LL and the system clipboard +bool LLClipboard::addToClipboard(const LLWString &src, S32 pos, S32 len, bool use_primary) { - bool res = false; - reset(); - if (src.notNull()) + const LLWString sep(utf8str_to_wstring(std::string(", "))); + if (mString.length() == 0) { - res = true; - if (LLAssetType::lookupIsAssetIDKnowable(type)) - { - LLWString source = utf8str_to_wstring(src.asString()); - res = copyToClipboard(source, 0, source.size()); - } - if (res) - { - store(src); - } + mString = src.substr(pos, len); } - return res; + else + { + mString = mString + sep + src.substr(pos, len); + } + return (use_primary ? LLView::getWindow()->copyTextToPrimary(mString) : LLView::getWindow()->copyTextToClipboard(mString)); } // Copy the System clipboard to the output string. diff --git a/indra/llui/llclipboard.h b/indra/llui/llclipboard.h index 8e417a490d..608ea246a7 100644 --- a/indra/llui/llclipboard.h +++ b/indra/llui/llclipboard.h @@ -48,34 +48,38 @@ public: LLClipboard(); ~LLClipboard(); - /* We support two flavors of clipboard. The default is the explicitly - copy-and-pasted clipboard. The second is the so-called 'primary' clipboard - which is implicitly copied upon selection on platforms which expect this - (i.e. X11/Linux). */ - - // Text strings and single item management - bool copyToClipboard(const LLWString& src, S32 pos, S32 len, bool use_primary = false); - bool copyToClipboard(const LLUUID& src, const LLAssetType::EType type = LLAssetType::AT_NONE); - bool pasteFromClipboard(LLWString& dst, bool use_primary = false); - bool isTextAvailable(bool use_primary = false) const; + // Text strings management: + // ------------------------ + // We support two flavors of text clipboards. The default is the explicitly + // copy-and-pasted clipboard. The second is the so-called 'primary' clipboard + // which is implicitly copied upon selection on platforms which expect this + // (i.e. X11/Linux, Mac). + bool copyToClipboard(const LLWString& src, S32 pos, S32 len, bool use_primary = false); + bool addToClipboard(const LLWString& src, S32 pos, S32 len, bool use_primary = false); + bool pasteFromClipboard(LLWString& dst, bool use_primary = false); + bool isTextAvailable(bool use_primary = false) const; - // Object list management - void add(const LLUUID& object); // Adds to the current list of objects on the clipboard - void store(const LLUUID& object); // Stores a single inventory object - void store(const LLDynamicArray& inventory_objects); // Stores an array of objects - void cut(const LLUUID& object); // Adds to the current list of cut objects on the clipboard - void retrieve(LLDynamicArray& inventory_objects) const; // Gets a copy of the objects on the clipboard - void reset(); // Clears the clipboard + // Object list management: + // ----------------------- + // Clears the clipboard + void reset(); + // Clears and adds one single object to the clipboard + bool copyToClipboard(const LLUUID& src, const LLAssetType::EType type = LLAssetType::AT_NONE); + // Adds one object to the current list of objects on the clipboard + bool addToClipboard(const LLUUID& src, const LLAssetType::EType type = LLAssetType::AT_NONE); + // Gets a copy of the objects on the clipboard + bool pasteFromClipboard(LLDynamicArray& inventory_objects) const; - BOOL hasContents() const; // true if the clipboard has something pasteable in it + bool hasContents() const; // True if the clipboard has pasteable objects + bool isOnClipboard(const LLUUID& object) const; // True if the input object uuid is on the clipboard + bool isCutMode() const { return mCutMode; } void setCutMode(bool mode) { mCutMode = mode; } - bool isOnClipboard(const LLUUID& object) const; private: LLDynamicArray mObjects; - bool mCutMode; LLWString mString; + bool mCutMode; // This is a convenience flag for the viewer. It has no influence on the cliboard management. }; #endif // LL_LLCLIPBOARD_H diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 4308bf2d3c..d4bce1e3a1 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -1187,7 +1187,7 @@ void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata) } else if (action == "copy") { - LLClipboard::getInstance()->store(mSelectedItemID); + LLClipboard::getInstance()->copyToClipboard(mSelectedItemID, LLAssetType::AT_LANDMARK); } else if (action == "paste") { @@ -1217,7 +1217,7 @@ BOOL LLFavoritesBarCtrl::isClipboardPasteable() const } LLDynamicArray objects; - LLClipboard::getInstance()->retrieve(objects); + LLClipboard::getInstance()->pasteFromClipboard(objects); S32 count = objects.count(); for(S32 i = 0; i < count; i++) { @@ -1246,7 +1246,7 @@ void LLFavoritesBarCtrl::pastFromClipboard() const { LLInventoryItem* item = NULL; LLDynamicArray objects; - LLClipboard::getInstance()->retrieve(objects); + LLClipboard::getInstance()->pasteFromClipboard(objects); S32 count = objects.count(); LLUUID parent_id(mFavoriteFolderId); for(S32 i = 0; i < count; i++) diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp index 3c647284f6..d449c4ff1b 100644 --- a/indra/newview/llfloatergesture.cpp +++ b/indra/newview/llfloatergesture.cpp @@ -395,7 +395,7 @@ bool LLFloaterGesture::isActionEnabled(const LLSD& command) return false; LLDynamicArray ids; - LLClipboard::getInstance()->retrieve(ids); + LLClipboard::getInstance()->pasteFromClipboard(ids); for(LLDynamicArray::iterator it = ids.begin(); it != ids.end(); it++) { LLInventoryItem* item = gInventory.getItem(*it); @@ -490,26 +490,26 @@ void LLFloaterGesture::onActivateBtnClick() void LLFloaterGesture::onCopyPasteAction(const LLSD& command) { std::string command_name = command.asString(); - // since we select this comman inventory item had already arrived . + // Since we select this command, the inventory items must have already arrived if("copy_gesture" == command_name) { uuid_vec_t ids; getSelectedIds(ids); - // make sure that clopboard is empty + // Make sure the clipboard is empty LLClipboard::getInstance()->reset(); for(uuid_vec_t::iterator it = ids.begin(); it != ids.end(); it++) { LLInventoryItem* item = gInventory.getItem(*it); if(item && item->getInventoryType() == LLInventoryType::IT_GESTURE) { - LLClipboard::getInstance()->add(item->getUUID()); + LLClipboard::getInstance()->addToClipboard(item->getUUID(),LLAssetType::AT_GESTURE); } } } else if ("paste" == command_name) { LLDynamicArray ids; - LLClipboard::getInstance()->retrieve(ids); + LLClipboard::getInstance()->pasteFromClipboard(ids); if(ids.empty() || !gInventory.isCategoryComplete(mGestureFolderID)) return; LLInventoryCategory* gesture_dir = gInventory.getCategory(mGestureFolderID); diff --git a/indra/newview/llfoldervieweventlistener.h b/indra/newview/llfoldervieweventlistener.h index aee31ca033..06682dcbf1 100644 --- a/indra/newview/llfoldervieweventlistener.h +++ b/indra/newview/llfoldervieweventlistener.h @@ -75,7 +75,7 @@ public: virtual void move( LLFolderViewEventListener* parent_listener ) = 0; virtual BOOL isItemCopyable() const = 0; virtual BOOL copyToClipboard() const = 0; - virtual void cutToClipboard() = 0; + virtual BOOL cutToClipboard() const = 0; virtual BOOL isClipboardPasteable() const = 0; virtual void pasteFromClipboard() = 0; virtual void pasteLinkFromClipboard() = 0; diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 7ba914eaf6..9775e54d6a 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -208,13 +208,27 @@ BOOL LLInvFVBridge::isLink() const /** * @brief Adds this item into clipboard storage */ -void LLInvFVBridge::cutToClipboard() +BOOL LLInvFVBridge::cutToClipboard() const { - if (isItemMovable() && isItemRemovable()) + LLViewerInventoryItem* inv_item = gInventory.getItem(mUUID); + if (inv_item && isItemMovable() && isItemRemovable()) { - LLClipboard::getInstance()->cut(mUUID); + LLClipboard::getInstance()->setCutMode(true); + return LLClipboard::getInstance()->addToClipboard(mUUID,inv_item->getType()); } + return FALSE; } + +BOOL LLInvFVBridge::copyToClipboard() const +{ + LLViewerInventoryItem* inv_item = gInventory.getItem(mUUID); + if (inv_item && isItemCopyable()) + { + return LLClipboard::getInstance()->addToClipboard(mUUID,inv_item->getType()); + } + return FALSE; +} + // *TODO: make sure this does the right thing void LLInvFVBridge::showProperties() { @@ -413,7 +427,7 @@ BOOL LLInvFVBridge::isClipboardPasteable() const // 1. folders should be pastable // 2. when pasting, we should paste what is authorized and let the rest not pasted LLDynamicArray objects; - LLClipboard::getInstance()->retrieve(objects); + LLClipboard::getInstance()->pasteFromClipboard(objects); S32 count = objects.count(); for(S32 i = 0; i < count; i++) { @@ -451,7 +465,7 @@ BOOL LLInvFVBridge::isClipboardPasteableAsLink() const } LLDynamicArray objects; - LLClipboard::getInstance()->retrieve(objects); + LLClipboard::getInstance()->pasteFromClipboard(objects); S32 count = objects.count(); for(S32 i = 0; i < count; i++) { @@ -1673,16 +1687,6 @@ BOOL LLItemBridge::isItemCopyable() const return FALSE; } -BOOL LLItemBridge::copyToClipboard() const -{ - if(isItemCopyable()) - { - LLClipboard::getInstance()->add(mUUID); - return TRUE; - } - return FALSE; -} - LLViewerInventoryItem* LLItemBridge::getItem() const { LLViewerInventoryItem* item = NULL; @@ -1785,16 +1789,6 @@ BOOL LLFolderBridge::isItemCopyable() const return gSavedSettings.getBOOL("InventoryLinking"); } -BOOL LLFolderBridge::copyToClipboard() const -{ - if(isItemCopyable()) - { - LLClipboard::getInstance()->add(mUUID); - return TRUE; - } - return FALSE; -} - BOOL LLFolderBridge::isClipboardPasteable() const { if ( ! LLInvFVBridge::isClipboardPasteable() ) @@ -1810,7 +1804,7 @@ BOOL LLFolderBridge::isClipboardPasteable() const } LLDynamicArray objects; - LLClipboard::getInstance()->retrieve(objects); + LLClipboard::getInstance()->pasteFromClipboard(objects); const LLViewerInventoryCategory *current_cat = getCategory(); // Search for the direct descendent of current Friends subfolder among all pasted items, @@ -1848,7 +1842,7 @@ BOOL LLFolderBridge::isClipboardPasteableAsLink() const const BOOL is_in_friend_folder = LLFriendCardsManager::instance().isCategoryInFriendFolder( current_cat ); const LLUUID ¤t_cat_id = current_cat->getUUID(); LLDynamicArray objects; - LLClipboard::getInstance()->retrieve(objects); + LLClipboard::getInstance()->pasteFromClipboard(objects); S32 count = objects.count(); for(S32 i = 0; i < count; i++) { @@ -2844,7 +2838,7 @@ void LLFolderBridge::pasteFromClipboard() const LLUUID parent_id(mUUID); LLDynamicArray objects; - LLClipboard::getInstance()->retrieve(objects); + LLClipboard::getInstance()->pasteFromClipboard(objects); for (LLDynamicArray::const_iterator iter = objects.begin(); iter != objects.end(); ++iter) @@ -2900,7 +2894,7 @@ void LLFolderBridge::pasteLinkFromClipboard() const LLUUID parent_id(mUUID); LLDynamicArray objects; - LLClipboard::getInstance()->retrieve(objects); + LLClipboard::getInstance()->pasteFromClipboard(objects); for (LLDynamicArray::const_iterator iter = objects.begin(); iter != objects.end(); ++iter) diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 3bcd71557c..f13ff15bc5 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -105,8 +105,8 @@ public: virtual void removeBatch(LLDynamicArray& batch); virtual void move(LLFolderViewEventListener* new_parent_bridge) {} virtual BOOL isItemCopyable() const { return FALSE; } - virtual BOOL copyToClipboard() const { return FALSE; } - virtual void cutToClipboard(); + virtual BOOL copyToClipboard() const; + virtual BOOL cutToClipboard() const; virtual BOOL isClipboardPasteable() const; virtual BOOL isClipboardPasteableAsLink() const; virtual void pasteFromClipboard() {} @@ -211,7 +211,6 @@ public: virtual BOOL renameItem(const std::string& new_name); virtual BOOL removeItem(); virtual BOOL isItemCopyable() const; - virtual BOOL copyToClipboard() const; virtual BOOL hasChildren() const { return FALSE; } virtual BOOL isUpToDate() const { return TRUE; } @@ -274,7 +273,6 @@ public: virtual BOOL isItemCopyable() const; virtual BOOL isClipboardPasteable() const; virtual BOOL isClipboardPasteableAsLink() const; - virtual BOOL copyToClipboard() const; static void createWearable(LLFolderBridge* bridge, LLWearableType::EType type); diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 98ea680504..eb0a257def 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -124,7 +124,7 @@ public: virtual void move(LLFolderViewEventListener* parent_listener); virtual BOOL isItemCopyable() const; virtual BOOL copyToClipboard() const; - virtual void cutToClipboard(); + virtual BOOL cutToClipboard() const; virtual BOOL isClipboardPasteable() const; virtual void pasteFromClipboard(); virtual void pasteLinkFromClipboard(); @@ -524,8 +524,9 @@ BOOL LLTaskInvFVBridge::copyToClipboard() const return FALSE; } -void LLTaskInvFVBridge::cutToClipboard() +BOOL LLTaskInvFVBridge::cutToClipboard() const { + return FALSE; } BOOL LLTaskInvFVBridge::isClipboardPasteable() const -- cgit v1.3 From 91f77318db63d4b2560390551306056c4a6cc2d5 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Wed, 8 Feb 2012 15:44:02 -0800 Subject: EXP-1873 : Implement the hiding of cut items on the clipboard --- indra/llui/llclipboard.cpp | 6 +++++- indra/llui/llclipboard.h | 14 +++++++++----- indra/newview/llfolderviewitem.cpp | 6 ------ indra/newview/llinventoryfilter.cpp | 19 ++++++++++++++++++- indra/newview/llinventoryfilter.h | 4 +++- indra/newview/llinventorypanel.cpp | 13 +++++++++++++ indra/newview/llinventorypanel.h | 1 + 7 files changed, 49 insertions(+), 14 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llclipboard.cpp b/indra/llui/llclipboard.cpp index 7794a0537f..ee1f1aa816 100644 --- a/indra/llui/llclipboard.cpp +++ b/indra/llui/llclipboard.cpp @@ -34,7 +34,8 @@ #include "llview.h" #include "llwindow.h" -LLClipboard::LLClipboard() +LLClipboard::LLClipboard() : + mState(0) { reset(); } @@ -46,6 +47,7 @@ LLClipboard::~LLClipboard() void LLClipboard::reset() { + mState++; mObjects.reset(); mCutMode = false; mString = LLWString(); @@ -74,6 +76,7 @@ bool LLClipboard::addToClipboard(const LLUUID& src, const LLAssetType::EType typ if (res) { mObjects.put(src); + mState++; } } return res; @@ -126,6 +129,7 @@ bool LLClipboard::addToClipboard(const LLWString &src, S32 pos, S32 len, bool us { mString = mString + sep + src.substr(pos, len); } + mState++; return (use_primary ? LLView::getWindow()->copyTextToPrimary(mString) : LLView::getWindow()->copyTextToClipboard(mString)); } diff --git a/indra/llui/llclipboard.h b/indra/llui/llclipboard.h index 608ea246a7..0231169748 100644 --- a/indra/llui/llclipboard.h +++ b/indra/llui/llclipboard.h @@ -47,6 +47,11 @@ class LLClipboard : public LLSingleton public: LLClipboard(); ~LLClipboard(); + + // Clears the clipboard + void reset(); + // Returns the state of the clipboard so client can know if it has been modified (comparing with tracked state) + int getState() const { return mState; } // Text strings management: // ------------------------ @@ -61,8 +66,6 @@ public: // Object list management: // ----------------------- - // Clears the clipboard - void reset(); // Clears and adds one single object to the clipboard bool copyToClipboard(const LLUUID& src, const LLAssetType::EType type = LLAssetType::AT_NONE); // Adds one object to the current list of objects on the clipboard @@ -74,12 +77,13 @@ public: bool isOnClipboard(const LLUUID& object) const; // True if the input object uuid is on the clipboard bool isCutMode() const { return mCutMode; } - void setCutMode(bool mode) { mCutMode = mode; } + void setCutMode(bool mode) { mCutMode = mode; mState++; } private: - LLDynamicArray mObjects; - LLWString mString; + LLDynamicArray mObjects; // Objects on the clipboard. Can be empty while mString contains something licit (e.g. text from chat) + LLWString mString; // The text string. If mObjects is not empty, this string is reflecting them (UUIDs for the moment). bool mCutMode; // This is a convenience flag for the viewer. It has no influence on the cliboard management. + int mState; // Incremented when the clipboard change so that interested parties can check its state. }; #endif // LL_LLCLIPBOARD_H diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp index 37ef27a5d7..884cddfe7f 100644 --- a/indra/newview/llfolderviewitem.cpp +++ b/indra/newview/llfolderviewitem.cpp @@ -1004,12 +1004,6 @@ void LLFolderViewItem::draw() if (highlight_link) color = sLinkColor; if (in_library) color = sLibraryColor; - // Cut state rendering tweak (experimental) - if (LLClipboard::getInstance()->isCutMode() && LLClipboard::getInstance()->isOnClipboard(getListener()->getUUID())) - { - color.setAlpha(0.5); - } - F32 right_x = 0; F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)TEXT_PAD - (F32)TOP_PAD; F32 text_left = (F32)(ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + mIndentation); diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 796251cae5..9d12478019 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -39,6 +39,7 @@ #include "llviewerfoldertype.h" // linden library includes +#include "llclipboard.h" #include "lltrans.h" LLInventoryFilter::FilterOps::FilterOps() : @@ -236,7 +237,18 @@ BOOL LLInventoryFilter::checkAgainstFilterType(const LLFolderViewItem* item) con } } } - + + //////////////////////////////////////////////////////////////////////////////// + // FILTERTYPE_CLIPBOARD + // Pass if this item is not on the clipboard + if (filterTypes & FILTERTYPE_CLIPBOARD) + { + if (LLClipboard::getInstance()->isCutMode() && LLClipboard::getInstance()->isOnClipboard(object_id)) + { + return FALSE; + } + } + return TRUE; } @@ -450,6 +462,11 @@ void LLInventoryFilter::setFilterEmptySystemFolders() mFilterOps.mFilterTypes |= FILTERTYPE_EMPTYFOLDERS; } +void LLInventoryFilter::setFilterClipboard() +{ + mFilterOps.mFilterTypes |= FILTERTYPE_CLIPBOARD; +} + void LLInventoryFilter::setFilterUUID(const LLUUID& object_id) { if (mFilterOps.mFilterUUID == LLUUID::null) diff --git a/indra/newview/llinventoryfilter.h b/indra/newview/llinventoryfilter.h index 343306ae8e..fb4f84b139 100644 --- a/indra/newview/llinventoryfilter.h +++ b/indra/newview/llinventoryfilter.h @@ -59,7 +59,8 @@ public: FILTERTYPE_UUID = 0x1 << 2, // find the object with UUID and any links to it FILTERTYPE_DATE = 0x1 << 3, // search by date range FILTERTYPE_WEARABLE = 0x1 << 4, // search by wearable type - FILTERTYPE_EMPTYFOLDERS = 0x1 << 5 // pass if folder is not a system folder to be hidden if empty + FILTERTYPE_EMPTYFOLDERS = 0x1 << 5, // pass if folder is not a system folder to be hidden if empty + FILTERTYPE_CLIPBOARD = 0x1 << 6 // pass if item is not on the clipboard }; enum EFilterLink @@ -91,6 +92,7 @@ public: void setFilterUUID(const LLUUID &object_id); void setFilterWearableTypes(U64 types); void setFilterEmptySystemFolders(); + void setFilterClipboard(); void updateFilterTypes(U64 types, U64& current_types); void setFilterSubString(const std::string& string); diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 382569fa3a..27f97ad26f 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -33,6 +33,7 @@ #include "llagentwearables.h" #include "llappearancemgr.h" #include "llavataractions.h" +#include "llclipboard.h" #include "llfloaterinventory.h" #include "llfloaterreg.h" #include "llfloatersidepanelcontainer.h" @@ -247,6 +248,10 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params) getFilter()->setFilterEmptySystemFolders(); } + // hide items that are on the clipboard + getFilter()->setFilterClipboard(); + mClipboardState = LLClipboard::getInstance()->getState(); + // Initialize base class params. LLPanel::initFromParams(params); } @@ -277,6 +282,14 @@ void LLInventoryPanel::draw() { // Select the desired item (in case it wasn't loaded when the selection was requested) mFolderRoot->updateSelection(); + + // Nudge the filter if the clipboard state changed + if (mClipboardState != LLClipboard::getInstance()->getState()) + { + mClipboardState = LLClipboard::getInstance()->getState(); + getFilter()->setModified(LLInventoryFilter::FILTER_RESTART); + } + LLPanel::draw(); } diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index 7d805f6862..6db59afb9b 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -222,6 +222,7 @@ public: private: std::string mSortOrderSetting; + int mClipboardState; //-------------------------------------------------------------------- // Hidden folders -- cgit v1.3 From bb6ace0672fa5e1c47c534ba74396ef04daa408b Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Fri, 17 Feb 2012 14:42:12 -0800 Subject: EXP-1902, EXP-1903 : Move items cut to the trash when clipboard reset. --- indra/llui/llclipboard.cpp | 8 ++++++++ indra/llui/llclipboard.h | 9 +++++++-- indra/newview/llfolderview.cpp | 5 +---- indra/newview/llfolderview.h | 2 +- indra/newview/llinventorybridge.cpp | 2 +- 5 files changed, 18 insertions(+), 8 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llclipboard.cpp b/indra/llui/llclipboard.cpp index ee1f1aa816..e0729366cc 100644 --- a/indra/llui/llclipboard.cpp +++ b/indra/llui/llclipboard.cpp @@ -47,9 +47,17 @@ LLClipboard::~LLClipboard() void LLClipboard::reset() { + // Increment the clipboard state mState++; + // Call the cleanup function (if any) before releasing the object list + if (mCutMode && mCleanupCallback) + { + mCleanupCallback(); + } + // Clear the clipboard mObjects.reset(); mCutMode = false; + mCleanupCallback = NULL; mString = LLWString(); } diff --git a/indra/llui/llclipboard.h b/indra/llui/llclipboard.h index 0231169748..3947fa0229 100644 --- a/indra/llui/llclipboard.h +++ b/indra/llui/llclipboard.h @@ -27,6 +27,7 @@ #ifndef LL_LLCLIPBOARD_H #define LL_LLCLIPBOARD_H +#include #include "llstring.h" #include "lluuid.h" @@ -35,6 +36,8 @@ #include "llassettype.h" #include "llinventory.h" +typedef boost::function cleanup_callback_t; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLClipboard // @@ -77,13 +80,15 @@ public: bool isOnClipboard(const LLUUID& object) const; // True if the input object uuid is on the clipboard bool isCutMode() const { return mCutMode; } - void setCutMode(bool mode) { mCutMode = mode; mState++; } + void setCutMode(bool mode, cleanup_callback_t cb = NULL) { mCutMode = mode; mCleanupCallback = cb; mState++; } private: LLDynamicArray mObjects; // Objects on the clipboard. Can be empty while mString contains something licit (e.g. text from chat) LLWString mString; // The text string. If mObjects is not empty, this string is reflecting them (UUIDs for the moment). - bool mCutMode; // This is a convenience flag for the viewer. It has no influence on the cliboard management. + bool mCutMode; // This is a convenience flag for the viewer. Will determine if mCleanupCallback() needs to be called. + cleanup_callback_t mCleanupCallback;// Function to call when the cut clipboard is being wiped out. Can be set to NULL (nothing done then). int mState; // Incremented when the clipboard change so that interested parties can check its state. + }; #endif // LL_LLCLIPBOARD_H diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 0abfa9db8e..52cc70aee7 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -1014,6 +1014,7 @@ bool isDescendantOfASelectedItem(LLFolderViewItem* item, const std::vector exit @@ -2139,10 +2140,6 @@ bool LLFolderView::doToSelected(LLInventoryModel* model, const LLSD& userdata) } if (("copy" == action) || ("cut" == action)) { - // If there are things on the clipboard that have not been pasted but - // already disappeared from view, we need to move them to the trash - removeCutItems(); - // Clear the clipboard before we start adding things on it LLClipboard::getInstance()->reset(); } diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index 2f148d4e25..9a1df5a142 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -159,7 +159,7 @@ public: // deletion functionality void removeSelectedItems(); - void removeCutItems(); + static void removeCutItems(); // open the selected item. void openSelectedItems( void ); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index eb0f9803b0..54d195a2e6 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -213,7 +213,7 @@ BOOL LLInvFVBridge::cutToClipboard() const const LLInventoryObject* obj = gInventory.getObject(mUUID); if (obj && isItemMovable() && isItemRemovable()) { - LLClipboard::getInstance()->setCutMode(true); + LLClipboard::getInstance()->setCutMode(true, boost::bind(LLFolderView::removeCutItems)); return LLClipboard::getInstance()->addToClipboard(mUUID,obj->getType()); } return FALSE; -- cgit v1.3 From a5e4b15b7d29a64781eb32ef71e557a5bb8dc870 Mon Sep 17 00:00:00 2001 From: Seth ProductEngine Date: Thu, 23 Feb 2012 21:02:46 +0200 Subject: Linux build fix. Moved type casts from protected base classes to derived LLCoord. --- indra/llmath/llcoord.h | 19 +++++++++++++------ indra/llui/llfloater.cpp | 4 ++-- indra/llwindow/llwindow.cpp | 8 ++++---- 3 files changed, 19 insertions(+), 12 deletions(-) (limited to 'indra/llui') diff --git a/indra/llmath/llcoord.h b/indra/llmath/llcoord.h index 756e23dbdf..9b76268afd 100644 --- a/indra/llmath/llcoord.h +++ b/indra/llmath/llcoord.h @@ -26,6 +26,15 @@ #ifndef LL_LLCOORD_H #define LL_LLCOORD_H +template class LLCoord; +struct LL_COORD_TYPE_GL; +struct LL_COORD_TYPE_WINDOW; +struct LL_COORD_TYPE_SCREEN; + +typedef LLCoord LLCoordGL; +typedef LLCoord LLCoordWindow; +typedef LLCoord LLCoordScreen; + struct LLCoordCommon { LLCoordCommon(S32 x, S32 y) : mX(x), mY(y) {} @@ -62,6 +71,8 @@ public: bool operator==(const self_t& other) const { return mX == other.mX && mY == other.mY; } bool operator!=(const self_t& other) const { return !(*this == other); } + static const self_t& getTypedCoords(const COORD_FRAME& self) { return static_cast(self); } + static self_t& getTypedCoords(COORD_FRAME& self) { return static_cast(self); } }; struct LL_COORD_TYPE_GL @@ -70,13 +81,13 @@ struct LL_COORD_TYPE_GL LLCoordCommon convertToCommon() const { - const LLCoord& self = static_cast&>(*this); + const LLCoordGL& self = LLCoordGL::getTypedCoords(*this); return LLCoordCommon(self.mX, self.mY); } void convertFromCommon(const LLCoordCommon& from) { - LLCoord& self = static_cast&>(*this); + LLCoordGL& self = LLCoordGL::getTypedCoords(*this); self.mX = from.mX; self.mY = from.mY; } @@ -98,8 +109,4 @@ struct LL_COORD_TYPE_SCREEN void convertFromCommon(const LLCoordCommon& from); }; -typedef LLCoord LLCoordGL; -typedef LLCoord LLCoordWindow; -typedef LLCoord LLCoordScreen; - #endif diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 3afa1b8e3a..2a40bbf33c 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -3306,7 +3306,7 @@ bool LLCoordFloater::operator==(const LLCoordFloater& other) const LLCoordCommon LL_COORD_FLOATER::convertToCommon() const { - const LLCoordFloater& self = static_cast(*this); + const LLCoordFloater& self = static_cast(LLCoordFloater::getTypedCoords(*this)); LLRect snap_rect = gFloaterView->getSnapRect(); LLFloater* floaterp = mFloater.get(); @@ -3348,7 +3348,7 @@ LLCoordCommon LL_COORD_FLOATER::convertToCommon() const void LL_COORD_FLOATER::convertFromCommon(const LLCoordCommon& from) { - LLCoordFloater& self = static_cast(*this); + LLCoordFloater& self = static_cast(LLCoordFloater::getTypedCoords(*this)); LLRect snap_rect = gFloaterView->getSnapRect(); LLFloater* floaterp = mFloater.get(); S32 floater_width = floaterp ? floaterp->getRect().getWidth() : 0; diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp index 6834b34387..4e91271d83 100644 --- a/indra/llwindow/llwindow.cpp +++ b/indra/llwindow/llwindow.cpp @@ -440,7 +440,7 @@ BOOL LLWindowManager::isWindowValid(LLWindow *window) //coordinate conversion utility funcs that forward to llwindow LLCoordCommon LL_COORD_TYPE_WINDOW::convertToCommon() const { - const LLCoordWindow& self = static_cast(*this); + const LLCoordWindow& self = LLCoordWindow::getTypedCoords(*this); LLWindow* windowp = &(*LLWindow::beginInstances()); LLCoordGL out; @@ -450,7 +450,7 @@ LLCoordCommon LL_COORD_TYPE_WINDOW::convertToCommon() const void LL_COORD_TYPE_WINDOW::convertFromCommon(const LLCoordCommon& from) { - LLCoordWindow& self = static_cast(*this); + LLCoordWindow& self = LLCoordWindow::getTypedCoords(*this); LLWindow* windowp = &(*LLWindow::beginInstances()); LLCoordGL from_gl(from); @@ -459,7 +459,7 @@ void LL_COORD_TYPE_WINDOW::convertFromCommon(const LLCoordCommon& from) LLCoordCommon LL_COORD_TYPE_SCREEN::convertToCommon() const { - const LLCoordScreen& self = static_cast(*this); + const LLCoordScreen& self = LLCoordScreen::getTypedCoords(*this); LLWindow* windowp = &(*LLWindow::beginInstances()); LLCoordGL out; @@ -469,7 +469,7 @@ LLCoordCommon LL_COORD_TYPE_SCREEN::convertToCommon() const void LL_COORD_TYPE_SCREEN::convertFromCommon(const LLCoordCommon& from) { - LLCoordScreen& self = static_cast(*this); + LLCoordScreen& self = LLCoordScreen::getTypedCoords(*this); LLWindow* windowp = &(*LLWindow::beginInstances()); LLCoordGL from_gl(from); -- cgit v1.3 From 0fc6c5df969681659b1cc20bf06e9b1f8708d7a4 Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Fri, 24 Feb 2012 16:54:54 -0800 Subject: EXP-1181 FIX As a designer, I would like to specify default floater positions using relative coordinates floaters given specified positions will stay in that location floaters that stack will treat that as a specified position moving any floater will switch to relative positioning mode cleaned up some XUI where widgets were relying on a default height of 10 pixels --- indra/llui/llfloater.cpp | 120 ++++++----- indra/llui/llfloater.h | 13 +- indra/llui/llview.cpp | 220 +++++++++++---------- indra/llui/llview.h | 2 +- .../newview/skins/default/xui/en/floater_about.xml | 2 +- .../skins/default/xui/en/floater_about_land.xml | 2 +- .../skins/default/xui/en/floater_avatar.xml | 2 +- .../skins/default/xui/en/floater_avatar_picker.xml | 2 +- .../skins/default/xui/en/floater_camera.xml | 7 +- .../skins/default/xui/en/floater_chat_bar.xml | 6 +- .../skins/default/xui/en/floater_critical.xml | 2 +- .../skins/default/xui/en/floater_destinations.xml | 2 +- .../skins/default/xui/en/floater_gesture.xml | 2 +- .../skins/default/xui/en/floater_help_browser.xml | 2 +- .../skins/default/xui/en/floater_joystick.xml | 50 +++++ .../skins/default/xui/en/floater_land_holdings.xml | 2 +- indra/newview/skins/default/xui/en/floater_map.xml | 2 +- .../default/xui/en/floater_merchant_outbox.xml | 2 +- .../skins/default/xui/en/floater_moveview.xml | 6 +- .../skins/default/xui/en/floater_my_appearance.xml | 2 +- .../skins/default/xui/en/floater_my_inventory.xml | 2 +- .../skins/default/xui/en/floater_people.xml | 2 +- .../newview/skins/default/xui/en/floater_picks.xml | 2 +- .../skins/default/xui/en/floater_places.xml | 2 +- .../skins/default/xui/en/floater_preferences.xml | 2 +- .../skins/default/xui/en/floater_search.xml | 2 +- .../skins/default/xui/en/floater_snapshot.xml | 2 +- .../default/xui/en/floater_test_text_editor.xml | 1 + .../skins/default/xui/en/floater_test_widgets.xml | 2 + .../newview/skins/default/xui/en/floater_tools.xml | 3 +- .../skins/default/xui/en/floater_toybox.xml | 2 +- .../default/xui/en/floater_voice_controls.xml | 2 +- .../skins/default/xui/en/floater_world_map.xml | 2 +- .../default/xui/en/panel_postcard_settings.xml | 1 + .../default/xui/en/panel_snapshot_inventory.xml | 1 + .../skins/default/xui/en/panel_snapshot_local.xml | 1 + .../default/xui/en/panel_snapshot_profile.xml | 1 + indra/newview/skins/default/xui/en/panel_toast.xml | 1 - .../skins/default/xui/en/widgets/floater.xml | 2 +- 39 files changed, 284 insertions(+), 197 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 2a40bbf33c..992f7e1602 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -68,7 +68,7 @@ namespace LLInitParam { void TypeValues::declareValues() { - declare("none", LLFloaterEnums::OPEN_POSITIONING_NONE); + declare("relative", LLFloaterEnums::OPEN_POSITIONING_RELATIVE); declare("cascading", LLFloaterEnums::OPEN_POSITIONING_CASCADING); declare("centered", LLFloaterEnums::OPEN_POSITIONING_CENTERED); declare("specified", LLFloaterEnums::OPEN_POSITIONING_SPECIFIED); @@ -177,9 +177,7 @@ LLFloater::Params::Params() save_visibility("save_visibility", false), can_dock("can_dock", false), show_title("show_title", true), - open_positioning("open_positioning", LLFloaterEnums::OPEN_POSITIONING_NONE), - specified_left("specified_left"), - specified_bottom("specified_bottom"), + positioning("positioning", LLFloaterEnums::OPEN_POSITIONING_RELATIVE), header_height("header_height", 0), legacy_header_height("legacy_header_height", 0), close_image("close_image"), @@ -249,9 +247,7 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p) mCanClose(p.can_close), mDragOnLeft(p.can_drag_on_left), mResizable(p.can_resize), - mOpenPositioning(p.open_positioning), - mSpecifiedLeft(p.specified_left), - mSpecifiedBottom(p.specified_bottom), + mPositioning(p.positioning), mMinWidth(p.min_width), mMinHeight(p.min_height), mHeaderHeight(p.header_height), @@ -877,7 +873,7 @@ bool LLFloater::applyRectControl() { // other floaters in our group, position ourselves relative to them and don't save the rect mRectControl.clear(); - mOpenPositioning = LLFloaterEnums::OPEN_POSITIONING_CASCADE_GROUP; + mPositioning = LLFloaterEnums::OPEN_POSITIONING_CASCADE_GROUP; } else if (mRectControl.size() > 1) { @@ -914,20 +910,14 @@ bool LLFloater::applyDockState() void LLFloater::applyPositioning(LLFloater* other) { // Otherwise position according to the positioning code - switch (mOpenPositioning) + switch (mPositioning) { case LLFloaterEnums::OPEN_POSITIONING_CENTERED: center(); break; case LLFloaterEnums::OPEN_POSITIONING_SPECIFIED: - { - // Translate relative to snap rect - setOrigin(mSpecifiedLeft, mSpecifiedBottom); - const LLRect& snap_rect = gFloaterView->getSnapRect(); - translate(snap_rect.mLeft, snap_rect.mBottom); - translateIntoRect(snap_rect); - } + //translateIntoRect(gFloaterView->getSnapRect()); break; case LLFloaterEnums::OPEN_POSITIONING_CASCADE_GROUP: @@ -950,11 +940,25 @@ void LLFloater::applyPositioning(LLFloater* other) setOrigin(horizontal_offset, vertical_offset - rect_height); translate(snap_rect.mLeft, snap_rect.mBottom); - translateIntoRect(snap_rect); + //translateIntoRect(snap_rect); } + mPositioning = LLFloaterEnums::OPEN_POSITIONING_SPECIFIED; + setFollows(FOLLOWS_TOP | FOLLOWS_LEFT); + break; - case LLFloaterEnums::OPEN_POSITIONING_NONE: + case LLFloaterEnums::OPEN_POSITIONING_RELATIVE: + { + LLRect snap_rect = gFloaterView->getSnapRect(); + LLRect floater_view_screen_rect = gFloaterView->calcScreenRect(); + snap_rect.translate(floater_view_screen_rect.mLeft, floater_view_screen_rect.mBottom); + LLRect floater_screen_rect = calcScreenRect(); + + LLCoordGL new_center = mPosition.convert(); + LLCoordGL cur_center(floater_screen_rect.getCenterX(), floater_screen_rect.getCenterY()); + translate(new_center.mX - cur_center.mX, new_center.mY - cur_center.mY); + break; + } default: // Do nothing break; @@ -1072,7 +1076,9 @@ void LLFloater::handleReshape(const LLRect& new_rect, bool by_user) if (by_user && !isMinimized()) { storeRectControl(); - mOpenPositioning = LLFloaterEnums::OPEN_POSITIONING_NONE; + mPositioning = LLFloaterEnums::OPEN_POSITIONING_RELATIVE; + LLRect screen_rect = calcScreenRect(); + mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert(); } // if not minimized, adjust all snapped dependents to new shape @@ -1590,7 +1596,7 @@ void LLFloater::setDocked(bool docked, bool pop_on_undock) if (mDocked) { setMinimized(FALSE); - mOpenPositioning = LLFloaterEnums::OPEN_POSITIONING_NONE; + mPositioning = LLFloaterEnums::OPEN_POSITIONING_RELATIVE; } updateTitleButtons(); @@ -2164,19 +2170,14 @@ LLFloaterView::LLFloaterView (const Params& p) mSnapOffsetBottom(0), mSnapOffsetRight(0) { + mSnapView = getHandle(); } // By default, adjust vertical. void LLFloaterView::reshape(S32 width, S32 height, BOOL called_from_parent) { - S32 old_right = mLastSnapRect.mRight; - S32 old_top = mLastSnapRect.mTop; - LLView::reshape(width, height, called_from_parent); - S32 new_right = getSnapRect().mRight; - S32 new_top = getSnapRect().mTop; - mLastSnapRect = getSnapRect(); for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) @@ -2189,35 +2190,39 @@ void LLFloaterView::reshape(S32 width, S32 height, BOOL called_from_parent) continue; } - if (!floaterp->isMinimized()) + if (!floaterp->isMinimized() && floaterp->getCanDrag()) { - LLRect r = floaterp->getRect(); + LLRect old_rect = floaterp->getRect(); + floaterp->applyPositioning(NULL); + LLRect new_rect = floaterp->getRect(); - // Compute absolute distance from each edge of screen - S32 left_offset = llabs(r.mLeft - 0); - S32 right_offset = llabs(old_right - r.mRight); + //LLRect r = floaterp->getRect(); - S32 top_offset = llabs(old_top - r.mTop); - S32 bottom_offset = llabs(r.mBottom - 0); + //// Compute absolute distance from each edge of screen + //S32 left_offset = llabs(r.mLeft - 0); + //S32 right_offset = llabs(old_right - r.mRight); - S32 translate_x = 0; - S32 translate_y = 0; + //S32 top_offset = llabs(old_top - r.mTop); + //S32 bottom_offset = llabs(r.mBottom - 0); - if (left_offset > right_offset) - { - translate_x = new_right - old_right; - } + S32 translate_x = new_rect.mLeft - old_rect.mLeft; + S32 translate_y = new_rect.mBottom - old_rect.mBottom; - if (top_offset < bottom_offset) - { - translate_y = new_top - old_top; - } + //if (left_offset > right_offset) + //{ + // translate_x = new_right - old_right; + //} + + //if (top_offset < bottom_offset) + //{ + // translate_y = new_top - old_top; + //} // don't reposition immovable floaters - if (floaterp->getCanDrag()) - { - floaterp->translate(translate_x, translate_y); - } + //if (floaterp->getCanDrag()) + //{ + // floaterp->translate(translate_x, translate_y); + //} BOOST_FOREACH(LLHandle dependent_floater, floaterp->mDependents) { if (dependent_floater.get()) @@ -2972,7 +2977,10 @@ void LLFloater::initFromParams(const LLFloater::Params& p) LLPanel::initFromParams(p); // override any follows flags - setFollows(FOLLOWS_NONE); + if (mPositioning != LLFloaterEnums::OPEN_POSITIONING_SPECIFIED) + { + setFollows(FOLLOWS_NONE); + } mTitle = p.title; mShortTitle = p.short_title; @@ -2991,9 +2999,7 @@ void LLFloater::initFromParams(const LLFloater::Params& p) mSingleInstance = p.single_instance; mReuseInstance = p.reuse_instance.isProvided() ? p.reuse_instance : p.single_instance; - mOpenPositioning = p.open_positioning; - mSpecifiedLeft = p.specified_left; - mSpecifiedBottom = p.specified_bottom; + mPositioning = p.positioning; if (p.save_rect && mRectControl.empty()) { @@ -3113,7 +3119,7 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::str params.rect.left.set(0); } params.from_xui = true; - applyXUILayout(params, parent); + applyXUILayout(params, parent, parent == gFloaterView ? gFloaterView->getSnapRect() : parent->getLocalRect()); initFromParams(params); initFloater(params); @@ -3272,6 +3278,9 @@ void LLFloater::stackWith(LLFloater& other) next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, getRect().getWidth(), getRect().getHeight()); setShape(next_rect); + + other.mPositioning = LLFloaterEnums::OPEN_POSITIONING_SPECIFIED; + other.setFollows(FOLLOWS_LEFT | FOLLOWS_TOP); } LLCoordFloater::LLCoordFloater(F32 x, F32 y, LLFloater& floater) @@ -3309,6 +3318,9 @@ LLCoordCommon LL_COORD_FLOATER::convertToCommon() const const LLCoordFloater& self = static_cast(LLCoordFloater::getTypedCoords(*this)); LLRect snap_rect = gFloaterView->getSnapRect(); + LLRect floater_view_screen_rect = gFloaterView->calcScreenRect(); + snap_rect.translate(floater_view_screen_rect.mLeft, floater_view_screen_rect.mBottom); + LLFloater* floaterp = mFloater.get(); S32 floater_width = floaterp ? floaterp->getRect().getWidth() : 0; S32 floater_height = floaterp ? floaterp->getRect().getHeight() : 0; @@ -3350,6 +3362,10 @@ void LL_COORD_FLOATER::convertFromCommon(const LLCoordCommon& from) { LLCoordFloater& self = static_cast(LLCoordFloater::getTypedCoords(*this)); LLRect snap_rect = gFloaterView->getSnapRect(); + LLRect floater_view_screen_rect = gFloaterView->calcScreenRect(); + snap_rect.translate(floater_view_screen_rect.mLeft, floater_view_screen_rect.mBottom); + + LLFloater* floaterp = mFloater.get(); S32 floater_width = floaterp ? floaterp->getRect().getWidth() : 0; S32 floater_height = floaterp ? floaterp->getRect().getHeight() : 0; diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index a7cc9ae961..9b26adde40 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -64,7 +64,7 @@ namespace LLFloaterEnums { enum EOpenPositioning { - OPEN_POSITIONING_NONE, + OPEN_POSITIONING_RELATIVE, OPEN_POSITIONING_CASCADING, OPEN_POSITIONING_CASCADE_GROUP, OPEN_POSITIONING_CENTERED, @@ -163,10 +163,7 @@ public: can_dock, show_title; - Optional open_positioning; - Optional specified_left; - Optional specified_bottom; - + Optional positioning; Optional header_height, legacy_header_height; // HACK see initFromXML() @@ -355,7 +352,7 @@ public: void enableResizeCtrls(bool enable, bool width = true, bool height = true); - bool isPositioning(LLFloaterEnums::EOpenPositioning p) const { return (p == mOpenPositioning); } + bool isPositioning(LLFloaterEnums::EOpenPositioning p) const { return (p == mPositioning); } protected: void applyControlsAndPosition(LLFloater* other); @@ -453,9 +450,7 @@ private: BOOL mDragOnLeft; BOOL mResizable; - LLFloaterEnums::EOpenPositioning mOpenPositioning; - S32 mSpecifiedLeft; - S32 mSpecifiedBottom; + LLFloaterEnums::EOpenPositioning mPositioning; LLCoordFloater mPosition; S32 mMinWidth; diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 421166dcd4..356d5c31d1 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -2225,145 +2225,163 @@ static bool get_last_child_rect(LLView* parent, LLRect *rect) } //static -void LLView::applyXUILayout(LLView::Params& p, LLView* parent) +void LLView::applyXUILayout(LLView::Params& p, LLView* parent, LLRect layout_rect) { + if (!parent) return; + const S32 VPAD = 4; const S32 MIN_WIDGET_HEIGHT = 10; // *NOTE: This will confuse export of floater/panel coordinates unless // the default is also "topleft". JC - if (p.layout().empty() && parent) + if (p.layout().empty()) { p.layout = parent->getLayout(); } - if (parent) + if (layout_rect.isEmpty()) { - LLRect parent_rect = parent->getLocalRect(); - // overwrite uninitialized rect params, using context - LLRect default_rect = parent->getLocalRect(); + layout_rect = parent->getLocalRect(); + } - bool layout_topleft = (p.layout() == "topleft"); + // overwrite uninitialized rect params, using context + LLRect default_rect = parent->getLocalRect(); - // convert negative or centered coordinates to parent relative values - // Note: some of this logic matches the logic in TypedParam::setValueFromBlock() - if (p.rect.left.isProvided() && p.rect.left < 0) p.rect.left = p.rect.left + parent_rect.getWidth(); - if (p.rect.right.isProvided() && p.rect.right < 0) p.rect.right = p.rect.right + parent_rect.getWidth(); - if (p.rect.bottom.isProvided() && p.rect.bottom < 0) p.rect.bottom = p.rect.bottom + parent_rect.getHeight(); - if (p.rect.top.isProvided() && p.rect.top < 0) p.rect.top = p.rect.top + parent_rect.getHeight(); + bool layout_topleft = (p.layout() == "topleft"); + // convert negative or centered coordinates to parent relative values + // Note: some of this logic matches the logic in TypedParam::setValueFromBlock() + if (p.rect.left.isProvided()) + { + p.rect.left = p.rect.left + ((p.rect.left >= 0) ? layout_rect.mLeft : layout_rect.mRight); + } + if (p.rect.right.isProvided()) + { + p.rect.right = p.rect.right + ((p.rect.right >= 0) ? layout_rect.mLeft : layout_rect.mRight); + } + if (p.rect.bottom.isProvided()) + { + p.rect.bottom = p.rect.bottom + ((p.rect.bottom >= 0) ? layout_rect.mBottom : layout_rect.mTop); if (layout_topleft) { //invert top to bottom - if (p.rect.top.isProvided()) p.rect.top = parent_rect.getHeight() - p.rect.top; - if (p.rect.bottom.isProvided()) p.rect.bottom = parent_rect.getHeight() - p.rect.bottom; + p.rect.bottom = layout_rect.mBottom + layout_rect.mTop - p.rect.bottom; } - - // DEPRECATE: automatically fall back to height of MIN_WIDGET_HEIGHT pixels - if (!p.rect.height.isProvided() && !p.rect.top.isProvided() && p.rect.height == 0) + } + if (p.rect.top.isProvided()) + { + p.rect.top = p.rect.top + ((p.rect.top >= 0) ? layout_rect.mBottom : layout_rect.mTop); + if (layout_topleft) { - p.rect.height = MIN_WIDGET_HEIGHT; + //invert top to bottom + p.rect.top = layout_rect.mBottom + layout_rect.mTop - p.rect.top; } + } - default_rect.translate(0, default_rect.getHeight()); + // DEPRECATE: automatically fall back to height of MIN_WIDGET_HEIGHT pixels + if (!p.rect.height.isProvided() && !p.rect.top.isProvided() && p.rect.height == 0) + { + p.rect.height = MIN_WIDGET_HEIGHT; + } - // If there was a recently constructed child, use its rectangle - get_last_child_rect(parent, &default_rect); + default_rect.translate(0, default_rect.getHeight()); - if (layout_topleft) + // If there was a recently constructed child, use its rectangle + get_last_child_rect(parent, &default_rect); + + if (layout_topleft) + { + // Invert the sense of bottom_delta for topleft layout + if (p.bottom_delta.isProvided()) { - // Invert the sense of bottom_delta for topleft layout - if (p.bottom_delta.isProvided()) - { - p.bottom_delta = -p.bottom_delta; - } - else if (p.top_pad.isProvided()) - { - p.bottom_delta = -(p.rect.height + p.top_pad); - } - else if (p.top_delta.isProvided()) - { - p.bottom_delta = - -(p.top_delta + p.rect.height - default_rect.getHeight()); - } - else if (!p.left_delta.isProvided() - && !p.left_pad.isProvided()) - { - // set default position is just below last rect - p.bottom_delta.set(-(p.rect.height + VPAD), false); - } - else - { - p.bottom_delta.set(0, false); - } - - // default to same left edge - if (!p.left_delta.isProvided()) - { - p.left_delta.set(0, false); - } - if (p.left_pad.isProvided()) - { - // left_pad is based on prior widget's right edge - p.left_delta.set(p.left_pad + default_rect.getWidth(), false); - } - - default_rect.translate(p.left_delta, p.bottom_delta); + p.bottom_delta = -p.bottom_delta; } - else - { - // set default position is just below last rect - if (!p.bottom_delta.isProvided()) - { - p.bottom_delta.set(-(p.rect.height + VPAD), false); - } - if (!p.left_delta.isProvided()) - { - p.left_delta.set(0, false); - } - default_rect.translate(p.left_delta, p.bottom_delta); + else if (p.top_pad.isProvided()) + { + p.bottom_delta = -(p.rect.height + p.top_pad); } - - // this handles case where *both* x and x_delta are provided - // ignore x in favor of default x + x_delta - if (p.bottom_delta.isProvided()) p.rect.bottom.set(0, false); - if (p.left_delta.isProvided()) p.rect.left.set(0, false); - - // selectively apply rectangle defaults, making sure that - // params are not flagged as having been "provided" - // as rect params are overconstrained and rely on provided flags - if (!p.rect.left.isProvided()) + else if (p.top_delta.isProvided()) + { + p.bottom_delta = + -(p.top_delta + p.rect.height - default_rect.getHeight()); + } + else if (!p.left_delta.isProvided() + && !p.left_pad.isProvided()) { - p.rect.left.set(default_rect.mLeft, false); - //HACK: get around the fact that setting a rect param component value won't invalidate the existing rect object value - p.rect.paramChanged(p.rect.left, true); + // set default position is just below last rect + p.bottom_delta.set(-(p.rect.height + VPAD), false); } - if (!p.rect.bottom.isProvided()) + else { - p.rect.bottom.set(default_rect.mBottom, false); - p.rect.paramChanged(p.rect.bottom, true); + p.bottom_delta.set(0, false); } - if (!p.rect.top.isProvided()) + + // default to same left edge + if (!p.left_delta.isProvided()) { - p.rect.top.set(default_rect.mTop, false); - p.rect.paramChanged(p.rect.top, true); + p.left_delta.set(0, false); } - if (!p.rect.right.isProvided()) + if (p.left_pad.isProvided()) { - p.rect.right.set(default_rect.mRight, false); - p.rect.paramChanged(p.rect.right, true); - + // left_pad is based on prior widget's right edge + p.left_delta.set(p.left_pad + default_rect.getWidth(), false); } - if (!p.rect.width.isProvided()) + + default_rect.translate(p.left_delta, p.bottom_delta); + } + else + { + // set default position is just below last rect + if (!p.bottom_delta.isProvided()) { - p.rect.width.set(default_rect.getWidth(), false); - p.rect.paramChanged(p.rect.width, true); + p.bottom_delta.set(-(p.rect.height + VPAD), false); } - if (!p.rect.height.isProvided()) + if (!p.left_delta.isProvided()) { - p.rect.height.set(default_rect.getHeight(), false); - p.rect.paramChanged(p.rect.height, true); + p.left_delta.set(0, false); } + default_rect.translate(p.left_delta, p.bottom_delta); + } + + // this handles case where *both* x and x_delta are provided + // ignore x in favor of default x + x_delta + if (p.bottom_delta.isProvided()) p.rect.bottom.set(0, false); + if (p.left_delta.isProvided()) p.rect.left.set(0, false); + + // selectively apply rectangle defaults, making sure that + // params are not flagged as having been "provided" + // as rect params are overconstrained and rely on provided flags + if (!p.rect.left.isProvided()) + { + p.rect.left.set(default_rect.mLeft, false); + //HACK: get around the fact that setting a rect param component value won't invalidate the existing rect object value + p.rect.paramChanged(p.rect.left, true); + } + if (!p.rect.bottom.isProvided()) + { + p.rect.bottom.set(default_rect.mBottom, false); + p.rect.paramChanged(p.rect.bottom, true); + } + if (!p.rect.top.isProvided()) + { + p.rect.top.set(default_rect.mTop, false); + p.rect.paramChanged(p.rect.top, true); + } + if (!p.rect.right.isProvided()) + { + p.rect.right.set(default_rect.mRight, false); + p.rect.paramChanged(p.rect.right, true); + + } + if (!p.rect.width.isProvided()) + { + p.rect.width.set(default_rect.getWidth(), false); + p.rect.paramChanged(p.rect.width, true); + } + if (!p.rect.height.isProvided()) + { + p.rect.height.set(default_rect.getHeight(), false); + p.rect.paramChanged(p.rect.height, true); } } diff --git a/indra/llui/llview.h b/indra/llui/llview.h index fd19309a56..1c35349510 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -505,7 +505,7 @@ public: // Set up params after XML load before calling new(), // usually to adjust layout. - static void applyXUILayout(Params& p, LLView* parent); + static void applyXUILayout(Params& p, LLView* parent, LLRect layout_rect = LLRect()); // For re-export of floaters and panels, convert the coordinate system // to be top-left based. diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml index c7e9ec781d..060d889003 100644 --- a/indra/newview/skins/default/xui/en/floater_about.xml +++ b/indra/newview/skins/default/xui/en/floater_about.xml @@ -1,6 +1,6 @@