From 4779f91d5d398f136b9d45124bc00e4667c9cde2 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Tue, 9 Jul 2013 03:09:06 +0200 Subject: [PATCH 01/12] Fix Appearance Import button. Params are driven by wearable; changing the base character gets overwritten real quick. Fixed to call the appropriate LLWearable::setVisualParamWeight. I didn't test this in the light of multiwear -but it works for the shape, which is good enough. --- indra/newview/llfloatercustomize.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index 712965961..c757697b3 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -343,8 +343,8 @@ void LLFloaterCustomize::onBtnImport_continued(AIFilePicker* filepicker) llwarns << "Bad parameters list: early end of file" << llendl; return; } - gAgentAvatarp->setVisualParamWeight( param_id, param_weight, TRUE); - gAgentAvatarp->updateVisualParams(); + LLWearable* wearable = gAgentWearables.getTopWearable((LLWearableType::EType)typ); + wearable->setVisualParamWeight(param_id, param_weight, TRUE); } } From 8f3c1af82d8a8a1d1334feac5dd83ae687ceee01 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 10 Jul 2013 02:15:47 -0500 Subject: [PATCH 02/12] Fixed textentry combobox arrow positioning issues. --- indra/llui/llcombobox.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index 6fd7084df..46ba4d93e 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -94,10 +94,6 @@ LLComboBox::LLComboBox( const std::string& name, const LLRect &rect, const std:: mButton->setFont(LLFontGL::getFontSansSerifSmall()); mButton->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM | FOLLOWS_RIGHT); mButton->setHAlign( LLFontGL::LEFT ); - if(mAllowTextEntry) - { - mButton->setRightHPad(2); - } addChild(mButton); @@ -931,6 +927,11 @@ BOOL LLComboBox::handleUnicodeCharHere(llwchar uni_char) void LLComboBox::setAllowTextEntry(BOOL allow, S32 max_chars, BOOL set_tentative) { mAllowTextEntry = allow; + if(allow) + mButton->setRightHPad(2); + else + mButton->setRightHPad(LLBUTTON_H_PAD); + mTextEntryTentative = set_tentative; mMaxChars = max_chars; From b97caa77d462a4c1fd220eb63ecc9c23750b88bf Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Wed, 10 Jul 2013 21:06:45 +0200 Subject: [PATCH 03/12] Add versioning support to AIFilePicker. When saving a file, if the suggested filename has the form PREFIX?000.EXT then the viewer checks if that file already exists and if so, increments the number until it finds a name that does not already exist (in the suggested directory). The '?' is replaced with an underscore. This allows to fast saving of the same data without overwriting previous data. --- indra/newview/statemachine/aifilepicker.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/indra/newview/statemachine/aifilepicker.cpp b/indra/newview/statemachine/aifilepicker.cpp index 3cc3ccbcd..735c1d7ec 100644 --- a/indra/newview/statemachine/aifilepicker.cpp +++ b/indra/newview/statemachine/aifilepicker.cpp @@ -39,6 +39,7 @@ #include "llpluginmessageclasses.h" #include "llsdserialize.h" #include "aifilepicker.h" +#include "lldir.h" #if LL_WINDOWS #include "llviewerwindow.h" #endif @@ -195,9 +196,26 @@ void AIFilePicker::open(ELoadFilter filter, std::string const& default_path, std void AIFilePicker::open(std::string const& filename, ESaveFilter filter, std::string const& default_path, std::string const& context) { - mFilename = filename; + mFilename = LLDir::getScrubbedFileName(filename); mContext = context; mFolder = AIFilePicker::get_folder(default_path, context); + // If the basename of filename ends on "?000", then check if a file with that name exists and if so, increment the number. + std::string basename = gDirUtilp->getBaseFileName(filename, true); + size_t len = basename.size(); + if (len >= 4 && basename.substr(len - 4) == "?000") + { + basename = LLDir::getScrubbedFileName(basename.substr(0, len - 4)); + std::string extension = gDirUtilp->getExtension(mFilename); + for (int n = 0;; ++n) + { + mFilename = llformat("%s_%03u.%s", basename.c_str(), n, extension.c_str()); + std::string fullpath = mFolder + gDirUtilp->getDirDelimiter() + mFilename; + if (n == 999 || !gDirUtilp->fileExists(fullpath)) + { + break; + } + } + } mOpenType = save; switch(filter) { From 96b5f7bdc8458d7d4ba11d598dc04a12e5f9c613 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Wed, 10 Jul 2013 21:19:42 +0200 Subject: [PATCH 04/12] Add wearable exporting / importing in linden_genepool format. As importing has been broken for a long time, I decided to hijack the existing (broken) buttons of the Appearance floater for the following new implementation: The currently selected wearable, if full perm and the agent is owner (of course) and creator, then that wearable can be exported to disk with AIFilePicker in the context "archetype". The used format is now XML, linden_genepool version 1.0, the same format that is used when saving from Advanced --> Character --> Character Tests --> Appearance to XML in any viewer. However, unlike that Advanced option (which normally only works when DebugAvatarAppearanceMessage is set to TRUE, ie in the official Linden Viewer; but that does a lot more, most likely unwanted things: it causes to dump files in this format to the LL_PATH_LOGS directory whenever appearance data comes by and other stuff for debugging purposes only), now ONLY the selected wearable is written to the file. In the case of multiwear with several layers, that means the selected layer, as well. When importing these XML files again, only the selected wearable/layer is overwritten (assuming it is modifiable) with the data in the file that corresponds to that wearable (if the file contains data of another wearable then nothing happens). Note that this file format can be read by blender-avastar: Using this feature to save the shape you created in SL will allow you to import that into blender. Likewise, a shape created or modified in blender can be imported into SL using this feature. --- indra/llappearance/llwearable.cpp | 62 +++--- indra/llappearance/llwearable.h | 6 +- indra/newview/llagent.cpp | 4 +- indra/newview/llfloatercustomize.cpp | 208 ++++++++++-------- indra/newview/llfloatercustomize.h | 4 +- indra/newview/llpaneleditwearable.cpp | 93 ++++---- indra/newview/llpaneleditwearable.h | 2 + indra/newview/llviewermenu.cpp | 2 +- indra/newview/llvoavatar.cpp | 51 +++-- indra/newview/llvoavatar.h | 3 + indra/newview/llvoavatarself.cpp | 4 +- .../default/xui/en-us/floater_customize.xml | 6 +- 12 files changed, 240 insertions(+), 205 deletions(-) diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp index c4704bf06..379465eb2 100644 --- a/indra/llappearance/llwearable.cpp +++ b/indra/llappearance/llwearable.cpp @@ -33,6 +33,7 @@ #include "llvisualparam.h" #include "llavatarappearancedefines.h" #include "llwearable.h" +#include "lldate.h" using namespace LLAvatarAppearanceDefines; @@ -68,47 +69,42 @@ LLAssetType::EType LLWearable::getAssetType() const return LLWearableType::getAssetType(mType); } -// reX: new function -BOOL LLWearable::FileExportParams( FILE* file ) const +extern void dump_visual_param(LLAPRFile& file, LLVisualParam const* viewer_param, F32 value); + +// Replace '--' with '- -', see http://en.wikipedia.org/wiki/XML#Comments +std::string XMLCommentEscape(std::string const& comment) { - // wearable type - S32 type = (S32)mType; - fprintf( file, "type %d\n", type ); - - // parameters - S32 num_parameters = mVisualParamIndexMap.size(); - fprintf( file, "parameters %d\n", num_parameters ); - - for (visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.begin(); - iter != mVisualParamIndexMap.end(); ++iter) - { - S32 param_id = iter->first; - F32 param_weight = iter->second->getWeight(); - fprintf( file, "%d %s\n", param_id, terse_F32_to_string(param_weight).c_str() ); - } - - return TRUE; + std::string result = comment; + std::string::size_type off = std::string::npos; + while ((off = result.rfind("--", off)) != std::string::npos) + { + result.replace(off, 2, "- -"); + } + return result; } -// reX: new function -BOOL LLWearable::FileExportTextures( FILE* file ) const +void LLWearable::archetypeExport(LLAPRFile& file) const { - // wearable type - S32 type = (S32)mType; - fprintf( file, "type %d\n", type ); + apr_file_t* fp = file.getFileHandle(); - // texture entries - S32 num_textures = mTEMap.size(); - fprintf( file, "textures %d\n", num_textures ); - - for (te_map_t::const_iterator iter = mTEMap.begin(); - iter != mTEMap.end(); ++iter) + apr_file_printf(fp, "\n\t\t\n", getTypeName().c_str()); + apr_file_printf(fp, "\t\t\n", XMLCommentEscape(mName).c_str()); + apr_file_printf(fp, "\t\t\n", XMLCommentEscape(mDescription).c_str()); + apr_file_printf(fp, "\t\t\n", LLDate::now().asString().c_str()); + + for (visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.begin(); iter != mVisualParamIndexMap.end(); ++iter) + { + LLVisualParam const* param = iter->second; + dump_visual_param(file, param, param->getWeight()); + } + for (te_map_t::const_iterator iter = mTEMap.begin(); iter != mTEMap.end(); ++iter) { S32 te = iter->first; - fprintf( file, "%d %s\n", te, iter->second->getID().asString().c_str() ); - } + LLUUID const& image_id = iter->second->getID(); + apr_file_printf(fp, "\t\t\n", te, image_id.asString().c_str()); + } - return TRUE; + apr_file_printf(fp, "\n"); } BOOL LLWearable::exportFile(LLFILE* fp) const diff --git a/indra/llappearance/llwearable.h b/indra/llappearance/llwearable.h index e3f54b60e..f381835be 100644 --- a/indra/llappearance/llwearable.h +++ b/indra/llappearance/llwearable.h @@ -35,6 +35,7 @@ #include "llwearabletype.h" #include "lllocaltextureobject.h" +class LLAPRFile; class LLMD5; class LLVisualParam; class LLTexGlobalColorInfo; @@ -77,9 +78,8 @@ public: virtual void writeToAvatar(LLAvatarAppearance* avatarp); - BOOL FileExportParams(FILE* file) const; - BOOL FileExportTextures(FILE* file) const; - + void archetypeExport(LLAPRFile& file) const; + enum EImportResult { FAILURE = 0, diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 25e984503..50c8bc5cc 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -4439,7 +4439,7 @@ void LLAgent::requestLeaveGodMode() sendReliableMessage(); } -extern void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value); +extern void dump_visual_param(LLAPRFile& file, LLVisualParam const* viewer_param, F32 value); extern std::string get_sequential_numbered_file_name(const std::string& prefix, const std::string& suffix); @@ -4465,7 +4465,7 @@ void LLAgent::dumpSentAppearance(const std::string& dump_prefix) if (appearance_version_param) { F32 value = appearance_version_param->getWeight(); - dump_visual_param(file, appearance_version_param, value); + dump_visual_param(outfile, appearance_version_param, value); } for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index c757697b3..0b8b80963 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -81,6 +81,7 @@ #include "llappearancemgr.h" #include "statemachine/aifilepicker.h" +#include "llxmltree.h" using namespace LLAvatarAppearanceDefines; @@ -297,7 +298,7 @@ void LLFloaterCustomize::onBtnImport() { AIFilePicker* filepicker = AIFilePicker::create(); filepicker->open(FFLOAD_XML); - filepicker->run(boost::bind(&LLFloaterCustomize::onBtnImport_continued, filepicker)); + filepicker->run(boost::bind(&LLFloaterCustomize::onBtnImport_continued, this, filepicker)); } void LLFloaterCustomize::onBtnImport_continued(AIFilePicker* filepicker) @@ -308,59 +309,123 @@ void LLFloaterCustomize::onBtnImport_continued(AIFilePicker* filepicker) return; } - const std::string filename = filepicker->getFilename(); + // Find the editted wearable. + LLPanelEditWearable* panel_edit_wearable = getCurrentWearablePanel(); + LLViewerWearable* edit_wearable = panel_edit_wearable->getWearable(); - FILE* fp = LLFile::fopen(filename, "rb"); + std::string const filename = filepicker->getFilename(); - //char text_buffer[2048]; /* Flawfinder: ignore */ - S32 c; - S32 typ; - S32 count; - S32 param_id=0; - F32 param_weight=0; - S32 fields_read; - - for( S32 i=0; i < LLWearableType::WT_COUNT; i++ ) + LLXmlTree xml; + BOOL success = xml.parseFile(filename, FALSE); + if (!success) { - fields_read = fscanf( fp, "type %d\n", &typ); - if( fields_read != 1 ) - { - llwarns << "Bad asset type: early end of file" << llendl; - return; - } + llwarns << "Could not read or parse wearable import file \"" << filename << "\"." << llendl; + return; + } + LLXmlTreeNode* root = xml.getRoot(); + if (!root) + { + llwarns << "No root node found in wearable import file: " << filename << llendl; + return; + } - fields_read = fscanf( fp, "parameters %d\n", &count); - if( fields_read != 1 ) - { - llwarns << "Bad parameters : early end of file" << llendl; - return; - } - for(c=0;csetVisualParamWeight(param_id, param_weight, TRUE); - } + //------------------------------------------------------------------------- + // (root) + //------------------------------------------------------------------------- + if (!root->hasName("linden_genepool")) + { + llwarns << "Invalid wearable import file (missing linden_genepool header): " << filename << llendl; + return; + } + static LLStdStringHandle const version_string = LLXmlTree::addAttributeString("version"); + std::string version; + if (!root->getFastAttributeString(version_string, version) || (version != "1.0")) + { + llwarns << "Invalid linden_genepool version: " << version << " in file: " << filename << llendl; + return; } - fclose(fp); - return; + //------------------------------------------------------------------------- + // + //------------------------------------------------------------------------- + LLXmlTreeNode* archetype_node = root->getChildByName("archetype"); + if (!archetype_node) + { + llwarns << "No archetype in wearable import file: " << filename << llendl; + return; + } + + // Parse the XML content. + static LLStdStringHandle const id_string = LLXmlTree::addAttributeString("id"); + static LLStdStringHandle const value_string = LLXmlTree::addAttributeString("value"); + for(LLXmlTreeNode* child = archetype_node->getFirstChild(); child; child = archetype_node->getNextChild()) + { + if (!child->hasName("param")) + { + continue; + } + std::string id_s; + U32 id; + std::string value_s; + F32 value; + if (!child->getFastAttributeString(id_string, id_s) || !LLStringUtil::convertToU32(id_s, id) || + !child->getFastAttributeString(value_string, value_s) || !LLStringUtil::convertToF32(value_s, value)) + { + llwarns << "Possible syntax error or corruption for node in " << filename << llendl; + continue; + } + LLVisualParam* visual_param = edit_wearable->getVisualParam(id); + if (visual_param) + { + visual_param->setWeight(value, FALSE); + } + } + edit_wearable->writeToAvatar(gAgentAvatarp); + gAgentAvatarp->updateVisualParams(); + panel_edit_wearable->updateScrollingPanelUI(); } // reX: new function void LLFloaterCustomize::onBtnExport() { + // Find the editted wearable. + LLPanelEditWearable* panel_edit_wearable = getCurrentWearablePanel(); + LLViewerWearable* edit_wearable = panel_edit_wearable->getWearable(); + U32 edit_index = panel_edit_wearable->getIndex(); + std::string const& name = edit_wearable->getName(); + + // Determine if the currently selected wearable is modifiable. + LLWearableType::EType edit_type = getCurrentWearableType(); + bool is_modifiable = false; + LLViewerWearable* old_wearable = gAgentWearables.getViewerWearable(edit_type, edit_index); + if (old_wearable) + { + LLViewerInventoryItem* item = gInventory.getItem(old_wearable->getItemID()); + if (item) + { + LLPermissions const& perm = item->getPermissions(); + // Modifiable means the user can see the sliders and type them over into a file anyway. + is_modifiable = perm.allowModifyBy(gAgent.getID(), gAgent.getGroupID()); + } + } + + if (!is_modifiable) + { + // We should never get here, because in that case the Export button is disabled. + llwarns << "Cannot export current wearable \"" << name << "\" of type " << (int)edit_type << "because user lacks modify permissions." << llendl; + return; + } + + std::string file_name = edit_wearable->getName() + "_" + edit_wearable->getTypeName() + "?000.xml"; + std::string default_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); + AIFilePicker* filepicker = AIFilePicker::create(); - filepicker->open("", FFSAVE_XML); - filepicker->run(boost::bind(&LLFloaterCustomize::onBtnExport_continued, filepicker)); + filepicker->open(file_name, FFSAVE_XML, default_path, "archetype"); + filepicker->run(boost::bind(&LLFloaterCustomize::onBtnExport_continued, edit_wearable, filepicker)); } -void LLFloaterCustomize::onBtnExport_continued(AIFilePicker* filepicker) +//static +void LLFloaterCustomize::onBtnExport_continued(LLViewerWearable* edit_wearable, AIFilePicker* filepicker) { if (!filepicker->hasFilename()) { @@ -368,62 +433,17 @@ void LLFloaterCustomize::onBtnExport_continued(AIFilePicker* filepicker) return; } - LLViewerInventoryItem* item; - BOOL is_modifiable; - - const std::string filename = filepicker->getFilename(); - - FILE* fp = LLFile::fopen(filename, "wb"); - - for( S32 i=0; i < LLWearableType::WT_COUNT; i++ ) + LLAPRFile outfile; + outfile.open(filepicker->getFilename(), LL_APR_WB); + if (!outfile.getFileHandle()) { - is_modifiable = FALSE; - LLViewerWearable* old_wearable = gAgentWearables.getViewerWearable((LLWearableType::EType)i, 0); // TODO: MULTI-WEARABLE - if( old_wearable ) - { - item = gInventory.getItem(old_wearable->getItemID()); - if(item) - { - const LLPermissions& perm = item->getPermissions(); - is_modifiable = perm.allowModifyBy(gAgent.getID(), gAgent.getGroupID()); - } - } - if (is_modifiable) - { - old_wearable->FileExportParams(fp); - } - if (!is_modifiable) - { - fprintf( fp, "type %d\n",i); - fprintf( fp, "parameters 0\n"); - } - } + llwarns << "Could not open \"" << filepicker->getFilename() << "\" for writing." << llendl; + return; + } - for( S32 i=0; i < LLWearableType::WT_COUNT; i++ ) - { - is_modifiable = FALSE; - LLViewerWearable* old_wearable = gAgentWearables.getViewerWearable((LLWearableType::EType)i, 0); // TODO: MULTI-WEARABLE - if( old_wearable ) - { - item = gInventory.getItem(old_wearable->getItemID()); - if(item) - { - const LLPermissions& perm = item->getPermissions(); - is_modifiable = perm.allowModifyBy(gAgent.getID(), gAgent.getGroupID()); - } - } - if (is_modifiable) - { - old_wearable->FileExportTextures(fp); - } - if (!is_modifiable) - { - fprintf( fp, "type %d\n",i); - fprintf( fp, "textures 0\n"); - } - } - - fclose(fp); + LLVOAvatar::dumpArchetypeXML_header(outfile); + edit_wearable->archetypeExport(outfile); + LLVOAvatar::dumpArchetypeXML_footer(outfile); } void LLFloaterCustomize::onBtnOk() diff --git a/indra/newview/llfloatercustomize.h b/indra/newview/llfloatercustomize.h index 34eee55fe..115ad61ac 100644 --- a/indra/newview/llfloatercustomize.h +++ b/indra/newview/llfloatercustomize.h @@ -125,9 +125,9 @@ private: void onBtnOk(); void onBtnMakeOutfit(); void onBtnImport(); - static void onBtnImport_continued(AIFilePicker* filepicker); + void onBtnImport_continued(AIFilePicker* filepicker); void onBtnExport(); - static void onBtnExport_continued(AIFilePicker* filepicker); + static void onBtnExport_continued(LLViewerWearable* edit_wearable, AIFilePicker* filepicker); void onTabChanged( const LLSD& param ); bool onTabPrecommit( LLUICtrl* ctrl, const LLSD& param ); bool onSaveDialog(const LLSD& notification, const LLSD& response); diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index 78ef25eed..7719b2dfa 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -953,22 +953,8 @@ void LLPanelEditWearable::setWearableIndex(S32 index) if(mActiveModal) mActiveModal->close(); - U32 perm_mask = wearable ? PERM_NONE : PERM_ALL; - BOOL is_complete = wearable ? FALSE : TRUE; - if(wearable) - { - LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(wearable->getItemID()); - if(item) - { - perm_mask = item->getPermissions().getMaskOwner(); - is_complete = item->isComplete(); - if(!is_complete) - { - item->fetchFromServer(); - } - } - } - setUIPermissions(perm_mask, is_complete); + bool editable = updatePermissions(); + if (mType == LLWearableType::WT_ALPHA) { initPreviousAlphaTextures(); @@ -980,7 +966,7 @@ void LLPanelEditWearable::setWearableIndex(S32 index) if(subpart_entry) { value_map_t sorted_params; - getSortedParams(sorted_params, subpart_entry->mEditGroup, ((perm_mask & PERM_MODIFY) && is_complete) ? TRUE : FALSE); + getSortedParams(sorted_params, subpart_entry->mEditGroup, editable); buildParamList(mCustomizeFloater->getScrollingPanelList(), sorted_params); } @@ -1144,6 +1130,10 @@ LLViewerWearable* LLPanelEditWearable::getWearable() const return mCurrentWearable;//gAgentWearables.getWearable(mType, mCurrentIndex); // TODO: MULTI-WEARABLE } +U32 LLPanelEditWearable::getIndex() const +{ + return mCurrentIndex; +} void LLPanelEditWearable::onTexturePickerCommit(const LLUICtrl* ctrl) { @@ -1386,39 +1376,11 @@ void LLPanelEditWearable::changeCamera(U8 subpart) } // Update the thumbnails we display - LLViewerWearable* wearable = getWearable(); - LLViewerInventoryItem* item = wearable ? gInventory.getItem(wearable->getItemID()) : NULL; - U32 perm_mask = 0x0; - BOOL is_complete = FALSE; - bool can_export = false; - bool can_import = false; - if(item) - { - perm_mask = item->getPermissions().getMaskOwner(); - is_complete = item->isComplete(); - - if (subpart_e < SUBPART_EYES) // body parts only - { - can_import = true; - - if (is_complete && - gAgent.getID() == item->getPermissions().getOwner() && - gAgent.getID() == item->getPermissions().getCreator() && - (PERM_ITEM_UNRESTRICTED & - perm_mask) == PERM_ITEM_UNRESTRICTED) - { - can_export = true; - } - } - } - setUIPermissions(perm_mask, is_complete); - + bool editable = updatePermissions(); value_map_t sorted_params; - getSortedParams(sorted_params, subpart_entry->mEditGroup, ((perm_mask & PERM_MODIFY) && is_complete) ? TRUE : FALSE); + getSortedParams(sorted_params, subpart_entry->mEditGroup, editable); buildParamList(mCustomizeFloater->getScrollingPanelList(), sorted_params); updateScrollingPanelUI(); - mCustomizeFloater->childSetEnabled("Export", can_export); - mCustomizeFloater->childSetEnabled("Import", can_import); // Update the camera if(gMorphView) @@ -1434,6 +1396,43 @@ void LLPanelEditWearable::changeCamera(U8 subpart) } } +//Singu note: this function was split off from LLPanelEditWearable::changeCamera +// Return true if the current wearable is editable and update state accordingly. +bool LLPanelEditWearable::updatePermissions() +{ + LLViewerWearable* wearable = getWearable(); + LLViewerInventoryItem* item = wearable ? gInventory.getItem(wearable->getItemID()) : NULL; + U32 perm_mask = wearable ? PERM_NONE : PERM_ALL; + BOOL is_complete = wearable ? FALSE : TRUE; + bool can_export = false; + bool can_import = false; + if (item) + { + perm_mask = item->getPermissions().getMaskOwner(); + is_complete = item->isComplete(); + + //Singu note: allow to import values over any modifiable wearable (why not?). + { + can_import = true; + + // Exporting (of slider values) is allowed when the wearable is full perm, and owned by and created by the user. + // Of course, only modifiable is enough for the user to write down the values and enter them else where... but why make it easy for them to break the ToS. + if (is_complete && + gAgent.getID() == item->getPermissions().getOwner() && + gAgent.getID() == item->getPermissions().getCreator() && + (PERM_ITEM_UNRESTRICTED & + perm_mask) == PERM_ITEM_UNRESTRICTED) + { + can_export = true; + } + } + } + setUIPermissions(perm_mask, is_complete); + mCustomizeFloater->childSetEnabled("Export", can_export); + mCustomizeFloater->childSetEnabled("Import", can_import); + return (perm_mask & PERM_MODIFY) && is_complete; +} + void LLPanelEditWearable::updateScrollingPanelList() { updateScrollingPanelUI(); diff --git a/indra/newview/llpaneleditwearable.h b/indra/newview/llpaneleditwearable.h index 0509b8e30..f7e9dbade 100644 --- a/indra/newview/llpaneleditwearable.h +++ b/indra/newview/llpaneleditwearable.h @@ -62,10 +62,12 @@ public: // changes camera angle to default for selected subpart void changeCamera(U8 subpart); + bool updatePermissions(); const std::string& getLabel() { return LLWearableType::getTypeLabel( mType ); } LLWearableType::EType getType() const{ return mType; } LLViewerWearable* getWearable() const; + U32 getIndex() const; void onTabChanged(LLUICtrl* ctrl); bool onTabPrecommit(); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 389b02629..857d48636 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -4376,7 +4376,7 @@ void handle_dump_archetype_xml(void *) avatar = gAgentAvatarp; } - std::string file_name = avatar->getFullname() + (avatar->isSelf() ? "_s" : "_o") + ".xml"; + std::string file_name = avatar->getFullname() + (avatar->isSelf() ? "_s" : "_o") + "?000.xml"; std::string default_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); AIFilePicker* filepicker = AIFilePicker::create(); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index b406c9eaa..0164c722c 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -7618,34 +7618,33 @@ bool LLVOAvatar::visualParamWeightsAreDefault() return rtn; } -void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value) +void dump_visual_param(LLAPRFile& file, LLVisualParam const* viewer_param, F32 value) { std::string type_string = "unknown"; - if (dynamic_cast(viewer_param)) + if (dynamic_cast(viewer_param)) type_string = "param_alpha"; - if (dynamic_cast(viewer_param)) + if (dynamic_cast(viewer_param)) type_string = "param_color"; - if (dynamic_cast(viewer_param)) + if (dynamic_cast(viewer_param)) type_string = "param_driver"; - if (dynamic_cast(viewer_param)) + if (dynamic_cast(viewer_param)) type_string = "param_morph"; - if (dynamic_cast(viewer_param)) + if (dynamic_cast(viewer_param)) type_string = "param_skeleton"; S32 wtype = -1; - LLViewerVisualParam *vparam = dynamic_cast(viewer_param); + LLViewerVisualParam const* vparam = dynamic_cast(viewer_param); if (vparam) { wtype = vparam->getWearableType(); } S32 u8_value = F32_to_U8(value,viewer_param->getMinWeight(),viewer_param->getMaxWeight()); - apr_file_printf(file, "\t\t\n", + apr_file_printf(file.getFileHandle(), "\t\t\n", viewer_param->getID(), viewer_param->getName().c_str(), value, u8_value, type_string.c_str(), LLWearableType::getTypeName(LLWearableType::EType(wtype)).c_str() // param_location_name(vparam->getParamLocation()).c_str() ); } - void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix, const std::vector& params_for_dump, const LLTEContents& tec) @@ -7675,7 +7674,7 @@ void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix, } LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param; F32 value = params_for_dump[i]; - dump_visual_param(file, viewer_param, value); + dump_visual_param(outfile, viewer_param, value); param = getNextVisualParam(); } for (U32 i = 0; i < tec.face_count; i++) @@ -8301,7 +8300,24 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara dumpArchetypeXML_cont(fullpath, group_by_wearables); } -void LLVOAvatar::dumpArchetypeXML_cont(std::string const& fullpath, bool group_by_wearables ) +//static +void LLVOAvatar::dumpArchetypeXML_header(LLAPRFile& file) +{ + apr_file_t* fp = file.getFileHandle(); + apr_file_printf(fp, "\n"); + apr_file_printf(fp, "\n"); + apr_file_printf(fp, "\n\t\n"); +} + +//static +void LLVOAvatar::dumpArchetypeXML_footer(LLAPRFile& file) +{ + apr_file_t* fp = file.getFileHandle(); + apr_file_printf(fp, "\t\n"); + apr_file_printf(fp, "\n\n"); +} + +void LLVOAvatar::dumpArchetypeXML_cont(std::string const& fullpath, bool group_by_wearables) { LLAPRFile outfile; outfile.open(fullpath, LL_APR_WB ); @@ -8315,9 +8331,7 @@ void LLVOAvatar::dumpArchetypeXML_cont(std::string const& fullpath, bool group_b llinfos << "xmlfile write handle obtained : " << fullpath << llendl; } - apr_file_printf( file, "\n" ); - apr_file_printf( file, "\n" ); - apr_file_printf( file, "\n\t\n" ); + LLVOAvatar::dumpArchetypeXML_header(outfile); if (group_by_wearables) { @@ -8332,7 +8346,7 @@ void LLVOAvatar::dumpArchetypeXML_cont(std::string const& fullpath, bool group_b if( (viewer_param->getWearableType() == type) && (viewer_param->isTweakable() ) ) { - dump_visual_param(file, viewer_param, viewer_param->getWeight()); + dump_visual_param(outfile, viewer_param, viewer_param->getWeight()); } } @@ -8358,7 +8372,7 @@ void LLVOAvatar::dumpArchetypeXML_cont(std::string const& fullpath, bool group_b for (LLVisualParam* param = getFirstVisualParam(); param; param = getNextVisualParam()) { LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param; - dump_visual_param(file, viewer_param, viewer_param->getWeight()); + dump_visual_param(outfile, viewer_param, viewer_param->getWeight()); } for (U8 te = 0; te < TEX_NUM_INDICES; te++) @@ -8376,8 +8390,8 @@ void LLVOAvatar::dumpArchetypeXML_cont(std::string const& fullpath, bool group_b } } - apr_file_printf( file, "\t\n" ); - apr_file_printf( file, "\n\n" ); + + LLVOAvatar::dumpArchetypeXML_footer(outfile); bool ultra_verbose = false; if (isSelf() && ultra_verbose) @@ -8388,7 +8402,6 @@ void LLVOAvatar::dumpArchetypeXML_cont(std::string const& fullpath, bool group_b // File will close when handle goes out of scope } - void LLVOAvatar::setVisibilityRank(U32 rank) { if (mDrawable.isNull() || mDrawable->isDead()) diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index a6c2e4c7b..23964a77e 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -66,6 +66,7 @@ extern const LLUUID ANIM_AGENT_PELVIS_FIX; extern const LLUUID ANIM_AGENT_TARGET; extern const LLUUID ANIM_AGENT_WALK_ADJUST; +class LLAPRFile; class LLViewerWearable; class LLVoiceVisualizer; class LLHUDNameTag; @@ -986,6 +987,8 @@ private: // General //-------------------------------------------------------------------- public: + static void dumpArchetypeXML_header(LLAPRFile& file); + static void dumpArchetypeXML_footer(LLAPRFile& file); void dumpArchetypeXML(const std::string& prefix, bool group_by_wearables = false); void dumpArchetypeXML_cont(std::string const& fullpath, bool group_by_wearables); void dumpAppearanceMsgParams( const std::string& dump_prefix, diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 49e9eba37..fc53d4091 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -3195,7 +3195,7 @@ void LLVOAvatarSelf::dumpScratchTextureByteCount() llinfos << "Scratch Texture GL: " << (sScratchTexBytes/1024) << "KB" << llendl; } -void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value); +void dump_visual_param(LLAPRFile& file, LLVisualParam const* viewer_param, F32 value); void LLVOAvatarSelf::dumpWearableInfo(LLAPRFile& outfile) { @@ -3223,7 +3223,7 @@ void LLVOAvatarSelf::dumpWearableInfo(LLAPRFile& outfile) it != v_params.end(); ++it) { LLVisualParam *param = *it; - dump_visual_param(file, param, param->getWeight()); + dump_visual_param(outfile, param, param->getWeight()); } } } diff --git a/indra/newview/skins/default/xui/en-us/floater_customize.xml b/indra/newview/skins/default/xui/en-us/floater_customize.xml index e0f6df5b5..b1194eb89 100644 --- a/indra/newview/skins/default/xui/en-us/floater_customize.xml +++ b/indra/newview/skins/default/xui/en-us/floater_customize.xml @@ -1435,10 +1435,12 @@ one from scratch and wear it.