From 5c0e632ad59bb5e7741e93c834b9f5d6fdbbfefb Mon Sep 17 00:00:00 2001 From: Cinders Date: Fri, 27 Sep 2013 23:27:00 -0600 Subject: [PATCH] Export improvements: FIRE-9625 - Make Import Linkset work like the other uploaders FIRE-11646 - Option to not backup object contents Combined permission checks into a single namespace Added object export floater for a more consistent workflow with collada export --- indra/newview/CMakeLists.txt | 6 +- indra/newview/app_settings/settings.xml | 13 +- indra/newview/daeexport.cpp | 202 +---- indra/newview/daeexport.h | 1 - indra/newview/fsexportperms.cpp | 226 +++++ indra/newview/fsexportperms.h | 38 + .../{fsexport.cpp => fsfloaterexport.cpp} | 773 ++++++++++-------- .../newview/{fsexport.h => fsfloaterexport.h} | 131 +-- indra/newview/fsfloaterimport.cpp | 158 ++-- indra/newview/fsfloaterimport.h | 19 +- indra/newview/llviewerfloaterreg.cpp | 2 +- indra/newview/llviewermenu.cpp | 8 +- indra/newview/llviewermenufile.cpp | 12 + indra/newview/llviewerobjectlist.cpp | 13 +- indra/newview/llviewerobjectlist.h | 7 + .../newview/skins/default/xui/de/strings.xml | 57 -- .../default/xui/en/floater_fs_export.xml | 179 +++- .../default/xui/en/floater_fs_import.xml | 121 ++- .../skins/default/xui/en/menu_viewer.xml | 8 +- .../skins/default/xui/en/notifications.xml | 12 +- .../newview/skins/default/xui/en/strings.xml | 21 - .../newview/skins/default/xui/pl/strings.xml | 57 -- 22 files changed, 1173 insertions(+), 891 deletions(-) create mode 100644 indra/newview/fsexportperms.cpp create mode 100644 indra/newview/fsexportperms.h rename indra/newview/{fsexport.cpp => fsfloaterexport.cpp} (64%) rename indra/newview/{fsexport.h => fsfloaterexport.h} (54%) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 46457dc8d1..1590856753 100755 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -131,8 +131,9 @@ set(viewer_SOURCE_FILES fsconsoleutils.cpp fscontactsfloater.cpp fsdata.cpp - fsexport.cpp + fsexportperms.cpp fsfloaterblocklist.cpp + fsfloaterexport.cpp fsfloatergroup.cpp fsfloatergrouptitles.cpp fsfloaterimport.cpp @@ -819,8 +820,9 @@ set(viewer_HEADER_FILES fsconsoleutils.h fscontactsfloater.h fsdata.h - fsexport.h + fsexportperms.h fsfloaterblocklist.h + fsfloaterexport.h fsfloatergroup.h fsfloatergrouptitles.h fsfloaterimport.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 361f1111ae..38cb0ff8f8 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -20877,7 +20877,7 @@ Change of this parameter will affect the layout of buttons in notification toast FSBuildPrefs_Temporary Comment - New object created default of tempary + New object created default of temporary Persist 1 Type @@ -21443,5 +21443,16 @@ Change of this parameter will affect the layout of buttons in notification toast 1.0 + FSExportContents + + Comment + Export object contents in linkset backups + Persist + 1 + Type + Boolean + Value + 1 + diff --git a/indra/newview/daeexport.cpp b/indra/newview/daeexport.cpp index fa919a7072..dbcb35a77a 100644 --- a/indra/newview/daeexport.cpp +++ b/indra/newview/daeexport.cpp @@ -74,9 +74,6 @@ #include "llagent.h" #include "llcallbacklist.h" #include "llfilepicker.h" -#include "llinventoryfunctions.h" -#include "llinventorymodel.h" -#include "llmeshrepository.h" #include "llnotificationsutil.h" #include "llselectmgr.h" #include "lltexturecache.h" @@ -86,6 +83,7 @@ #include "llviewernetwork.h" #include "llviewerregion.h" #include "llvovolume.h" +#include "fsexportperms.h" static const F32 TEXTURE_DOWNLOAD_TIMEOUT = 60.f; @@ -105,178 +103,6 @@ namespace DAEExportUtil ft_png, ft_j2c }; - - static bool canExportTexture(const LLUUID& asset_id, std::string* name = NULL) - { - bool exportable = false; - - LLViewerInventoryCategory::cat_array_t cats; - LLViewerInventoryItem::item_array_t items; - LLAssetIDMatches asset_id_matches(asset_id); - gInventory.collectDescendentsIf(LLUUID::null, - cats, - items, - LLInventoryModel::INCLUDE_TRASH, - asset_id_matches); - - for (S32 i = 0; i < items.count(); i++) - { - const LLPermissions perms = items[i]->getPermissions(); - if (LLGridManager::getInstance()->isInSecondLife()) - { - exportable = (perms.getCreator() == gAgentID); - } -#ifdef OPENSIM - else if (LLGridManager::getInstance()->isInOpenSim()) - { - LLViewerRegion* region = gAgent.getRegion(); - if (!region) - { - LL_WARNS("export") << "No region found to check export caps!" << LL_ENDL; - return false; - } - if (region->regionSupportsExport() == LLViewerRegion::EXPORT_ALLOWED) - { - exportable = (perms.getMaskOwner() & PERM_EXPORT) == PERM_EXPORT; - } - else if (region->regionSupportsExport() == LLViewerRegion::EXPORT_DENIED) - { - exportable = perms.getCreator() == gAgentID; - } - /// TODO: Once enough grids adopt a version supporting the exports cap, get consensus - /// on whether we should allow full perm exports anymore. - else - { - exportable = (perms.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED; - } - if (!exportable) - LL_INFOS("export") << "Texture has failed permissions check." << LL_ENDL; - } -#endif - if (exportable && name != NULL) - (*name) = items[i]->getName(); - else if (name != NULL) - (*name) = asset_id.getString(); - } - return exportable; - } - - static bool canExportNode(LLSelectNode* node) - { - bool exportable = false; - - LLViewerObject* object = node->getObject(); - if (LLGridManager::getInstance()->isInSecondLife()) - { - exportable = (object->permYouOwner() - && gAgentID == node->mPermissions->getCreator()); - } -#ifdef OPENSIM - else if (LLGridManager::getInstance()->isInOpenSim()) - { - LLViewerRegion* region = gAgent.getRegion(); - if (region && region->regionSupportsExport() == LLViewerRegion::EXPORT_ALLOWED) - { - exportable = node->mPermissions->allowExportBy(gAgent.getID()); - } - else if (region && region->regionSupportsExport() == LLViewerRegion::EXPORT_DENIED) - { - // Only your own creations if this is explicitly set - exportable = (object->permYouOwner() - && gAgentID == node->mPermissions->getCreator()); - } - /// TODO: Once enough grids adopt a version supporting the exports cap, get consensus - /// on whether we should allow full perm exports anymore. - else // LLViewerRegion::EXPORT_UNDEFINED - { - exportable = (object->permYouOwner() - && object->permModify() - && object->permCopy() - && object->permTransfer()); - } - } -#endif // OPENSIM - // We've got perms on the object itself, let's check for sculptmaps and meshes! - if (exportable) - { - LLVOVolume *volobjp = NULL; - if (object->getPCode() == LL_PCODE_VOLUME) - { - volobjp = (LLVOVolume *)object; - } - if (volobjp && volobjp->isSculpted()) - { - const LLSculptParams *sculpt_params = (const LLSculptParams *)object->getParameterEntry(LLNetworkData::PARAMS_SCULPT); - if (LLGridManager::getInstance()->isInSecondLife()) - { - if(volobjp->isMesh()) - { - LLSD mesh_header = gMeshRepo.getMeshHeader(sculpt_params->getSculptTexture()); - exportable = mesh_header["creator"].asUUID() == gAgentID; - } - else if (sculpt_params) - { - LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(sculpt_params->getSculptTexture()); - exportable = (imagep->mComment.find("a") != imagep->mComment.end() - && LLUUID(imagep->mComment["a"]) == gAgentID); - if (!exportable) - LL_INFOS("export") << "Sculpt map has failed permissions check." << LL_ENDL; - } - } -#ifdef OPENSIM - else if (LLGridManager::getInstance()->isInOpenSim()) - { - if (sculpt_params && !volobjp->isMesh()) - { - LLUUID asset_id = sculpt_params->getSculptTexture(); - LLViewerInventoryCategory::cat_array_t cats; - LLViewerInventoryItem::item_array_t items; - LLAssetIDMatches asset_id_matches(asset_id); - gInventory.collectDescendentsIf(LLUUID::null, cats, items, - LLInventoryModel::INCLUDE_TRASH, - asset_id_matches); - - for (S32 i = 0; i < items.count(); ++i) - { - const LLPermissions perms = items[i]->getPermissions(); - LLViewerRegion* region = gAgent.getRegion(); - if (!region) - { - LL_WARNS("export") << "No region found to check export caps!" << LL_ENDL; - return false; - } - if (region->regionSupportsExport() == LLViewerRegion::EXPORT_ALLOWED) - { - exportable = (perms.getMaskOwner() & PERM_EXPORT) == PERM_EXPORT; - } - else if (region->regionSupportsExport() == LLViewerRegion::EXPORT_DENIED) - { - exportable = perms.getCreator() == gAgentID; - } - /// TODO: Once enough grids adopt a version supporting the exports cap, get consensus - /// on whether we should allow full perm exports anymore. - else - { - exportable = (perms.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED; - } - if (!exportable) - LL_INFOS("export") << "Sculpt map has failed permissions check." << LL_ENDL; - } - } - else - { - exportable = true; - } - } -#endif // OPENSIM - } - else - { - exportable = true; - } - } - return exportable; - } } @@ -384,14 +210,14 @@ void ColladaExportFloater::addSelectedObjects() { mTotal++; LLSelectNode* node = *iter; - if (!node->getObject()->getVolume() || !DAEExportUtil::canExportNode(node)) continue; + if (!node->getObject()->getVolume() || !FSExportPermsCheck::canExportNode(node)) continue; mIncluded++; mSaver.add(node->getObject(), node->mName); } if (mSaver.mObjects.empty()) { - LLNotificationsUtil::add("ExportColladaFailed"); + LLNotificationsUtil::add("ExportFailed"); closeFloater(); return; } @@ -641,9 +467,27 @@ void DAESaver::updateTextureInfo() if (std::find(mTextures.begin(), mTextures.end(), id) != mTextures.end()) continue; mTextures.push_back(id); + bool exportable = false; + LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(id); std::string name; - if (id != DAEExportUtil::LL_TEXTURE_BLANK - && DAEExportUtil::canExportTexture(id, &name)) + std::string description; + if (LLGridManager::getInstance()->isInSecondLife()) + { + if (imagep->mComment.find("a") != imagep->mComment.end()) + { + if (LLUUID(imagep->mComment["a"]) == gAgentID) + { + exportable = true; + LL_DEBUGS("export") << id << " passed texture export comment check." << LL_ENDL; + } + } + } + if (exportable) + FSExportPermsCheck::canExportAsset(id, &name, &description); + else + exportable = FSExportPermsCheck::canExportAsset(id, &name, &description); + + if (id != DAEExportUtil::LL_TEXTURE_BLANK && exportable) { std::string safe_name = gDirUtilp->getScrubbedFileName(name); std::replace(safe_name.begin(), safe_name.end(), ' ', '_'); diff --git a/indra/newview/daeexport.h b/indra/newview/daeexport.h index d59c493b54..1d6dac19f7 100644 --- a/indra/newview/daeexport.h +++ b/indra/newview/daeexport.h @@ -127,7 +127,6 @@ private: virtual ~ColladaExportFloater(); void onClickExport(); void onTextureExportCheck(); - void filepickerCallback(); void onCommitTextureType(); void saveTextures(); void addSelectedObjects(); diff --git a/indra/newview/fsexportperms.cpp b/indra/newview/fsexportperms.cpp new file mode 100644 index 0000000000..f23e9673ae --- /dev/null +++ b/indra/newview/fsexportperms.cpp @@ -0,0 +1,226 @@ +/* + * @file fsexportperms.cpp + * @brief Export permissions check + * @authors Cinder Biscuits + * + * $LicenseInfo:firstyear=2013&license=LGPLV2.1$ + * Copyright (C) 2013 Cinder Biscuits + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 a love letter + * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "llviewerprecompiledheaders.h" + +#include "fsexportperms.h" +#include "llagent.h" +#include "llinventoryfunctions.h" +#include "llmeshrepository.h" +#include "llviewernetwork.h" +#include "llviewerregion.h" +#include "llvovolume.h" +#include "llworld.h" + +#define FOLLOW_PERMS 1 + +bool FSExportPermsCheck::canExportNode(LLSelectNode* node) +{ + if (!node) + { + LL_WARNS("export") << "No node, bailing!" << LL_ENDL; + return false; + } + bool exportable = false; + + LLViewerObject* object = node->getObject(); + if (LLGridManager::getInstance()->isInSecondLife()) + { + LLUUID creator(node->mPermissions->getCreator()); + exportable = (object->permYouOwner() && gAgentID == creator); + if (!exportable) + { + // Megaprim check + F32 max_object_size = LLWorld::getInstance()->getRegionMaxPrimScale(); + LLVector3 vec = object->getScale(); + exportable = (!(vec.mV[VX] > max_object_size || vec.mV[VY] > max_object_size || vec.mV[VZ] > max_object_size)); + exportable = (creator == LLUUID("7ffd02d0-12f4-48b4-9640-695708fd4ae4")); // Zwagoth Klaar + } + } +#ifdef OPENSIM + else if (LLGridManager::getInstance()->isInOpenSim()) + { + LLViewerRegion* region = gAgent.getRegion(); + if (region && region->regionSupportsExport() == LLViewerRegion::EXPORT_ALLOWED) + { + exportable = node->mPermissions->allowExportBy(gAgent.getID()); + } + else if (region && region->regionSupportsExport() == LLViewerRegion::EXPORT_DENIED) + { + // Only your own creations if this is explicitly set + exportable = (object->permYouOwner() + && gAgentID == node->mPermissions->getCreator()); + } + /// TODO: Once enough grids adopt a version supporting the exports cap, get consensus + /// on whether we should allow full perm exports anymore. + else // LLViewerRegion::EXPORT_UNDEFINED + { + exportable = (object->permYouOwner() + && object->permModify() + && object->permCopy() + && object->permTransfer()); + } + } +#endif // OPENSIM + // We've got perms on the object itself, let's check for sculptmaps and meshes! + if (exportable) + { + LLVOVolume *volobjp = NULL; + if (object->getPCode() == LL_PCODE_VOLUME) + { + volobjp = (LLVOVolume *)object; + } + if (volobjp && volobjp->isSculpted()) + { + const LLSculptParams *sculpt_params = (const LLSculptParams *)object->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + if (LLGridManager::getInstance()->isInSecondLife()) + { + if(volobjp->isMesh()) + { + LLSD mesh_header = gMeshRepo.getMeshHeader(sculpt_params->getSculptTexture()); + exportable = mesh_header["creator"].asUUID() == gAgentID; + } + else if (sculpt_params) + { + LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(sculpt_params->getSculptTexture()); + exportable = (imagep->mComment.find("a") != imagep->mComment.end() + && LLUUID(imagep->mComment["a"]) == gAgentID); + if (!exportable) + LL_INFOS("export") << "Sculpt map has failed permissions check." << LL_ENDL; + } + } +#ifdef OPENSIM + else if (LLGridManager::getInstance()->isInOpenSim()) + { + if (sculpt_params && !volobjp->isMesh()) + { + LLUUID asset_id = sculpt_params->getSculptTexture(); + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLAssetIDMatches asset_id_matches(asset_id); + gInventory.collectDescendentsIf(LLUUID::null, cats, items, + LLInventoryModel::INCLUDE_TRASH, + asset_id_matches); + + for (S32 i = 0; i < items.count(); ++i) + { + const LLPermissions perms = items[i]->getPermissions(); + LLViewerRegion* region = gAgent.getRegion(); + if (!region) + { + LL_WARNS("export") << "No region found to check export caps!" << LL_ENDL; + return false; + } + if (region->regionSupportsExport() == LLViewerRegion::EXPORT_ALLOWED) + { + exportable = (perms.getMaskOwner() & PERM_EXPORT) == PERM_EXPORT; + } + else if (region->regionSupportsExport() == LLViewerRegion::EXPORT_DENIED) + { + exportable = perms.getCreator() == gAgentID; + } + /// TODO: Once enough grids adopt a version supporting the exports cap, get consensus + /// on whether we should allow full perm exports anymore. + else + { + exportable = (perms.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED; + } + if (!exportable) + LL_INFOS("export") << "Sculpt map has failed permissions check." << LL_ENDL; + } + } + else + { + exportable = true; + } + } +#endif // OPENSIM + } + else + { + exportable = true; + } + } + return exportable; +} + +#if !FOLLOW_PERMS +You didn't think it would be that easy did you? :P +#endif + +bool FSExportPermsCheck::canExportAsset(LLUUID asset_id, std::string* name, std::string* description) +{ + bool exportable = false; + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLAssetIDMatches asset_id_matches(asset_id); + gInventory.collectDescendentsIf(LLUUID::null, + cats, + items, + LLInventoryModel::INCLUDE_TRASH, + asset_id_matches); + + if (items.count()) + { + // use the name of the first match + (*name) = items[0]->getName(); + (*description) = items[0]->getDescription(); + + for (S32 i = 0; i < items.count(); ++i) + { + if (!exportable) + { + LLPermissions perms = items[i]->getPermissions(); +#ifdef OPENSIM + if (LLGridManager::getInstance()->isInOpenSim()) + { + LLViewerRegion* region = gAgent.getRegion(); + if (!region) return false; + if (region->regionSupportsExport() == LLViewerRegion::EXPORT_ALLOWED) + { + exportable = (perms.getMaskOwner() & PERM_EXPORT) == PERM_EXPORT; + } + else if (region->regionSupportsExport() == LLViewerRegion::EXPORT_DENIED) + { + exportable = perms.getCreator() == gAgentID; + } + /// TODO: Once enough grids adopt a version supporting the exports cap, get consensus + /// on whether we should allow full perm exports anymore. + else + { + exportable = (perms.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED; + } + } +#endif + if (LLGridManager::getInstance()->isInSecondLife() && (perms.getCreator() == gAgentID)) + { + exportable = true; + } + } + } + } + + return exportable; +} + diff --git a/indra/newview/fsexportperms.h b/indra/newview/fsexportperms.h new file mode 100644 index 0000000000..5cf2d6e35c --- /dev/null +++ b/indra/newview/fsexportperms.h @@ -0,0 +1,38 @@ +/* + * @file fsexportperms.h + * @brief Export permissions check definitions + * @authors Cinder Biscuits + * + * $LicenseInfo:firstyear=2013&license=LGPLV2.1$ + * Copyright (C) 2013 Cinder Biscuits + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + */ + +#ifndef FS_EXPORTPERMS_H +#define FS_EXPORTPERMS_H + +#include "llselectmgr.h" + +const S32 OXP_FORMAT_VERSION = 2; + +namespace FSExportPermsCheck +{ + bool canExportNode(LLSelectNode* node); + bool canExportAsset(LLUUID asset_id, std::string* name = NULL, std::string* description = NULL); +}; + +#endif // FS_EXPORTPERMS_H diff --git a/indra/newview/fsexport.cpp b/indra/newview/fsfloaterexport.cpp similarity index 64% rename from indra/newview/fsexport.cpp rename to indra/newview/fsfloaterexport.cpp index 1433abc184..a09d44e5d6 100644 --- a/indra/newview/fsexport.cpp +++ b/indra/newview/fsfloaterexport.cpp @@ -1,10 +1,11 @@ /** - * @file fsexport.cpp + * @file fsfloaterexport.cpp * @brief export selected objects to an file using LLSD. * * $LicenseInfo:firstyear=2013&license=viewerlgpl$ * Phoenix Firestorm Viewer Source Code * Copyright (c) 2013 Techwolf Lupindo + * Copyright (c) 2013 Cinder Roxley * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -27,12 +28,11 @@ #include "llviewerprecompiledheaders.h" -#include "fsexport.h" +#include "fsfloaterexport.h" #include "llagent.h" #include "llagentconstants.h" #include "llagentdata.h" -#include "llappviewer.h" #include "llavatarnamecache.h" #include "llbufferstream.h" #include "llcallbacklist.h" @@ -41,24 +41,26 @@ #include "llfilepicker.h" #include "llimagej2c.h" #include "llinventoryfunctions.h" -#include "llmeshrepository.h" #include "llmultigesture.h" #include "llnotecard.h" #include "llnotificationsutil.h" +#include "llscrollcontainer.h" #include "llsdserialize.h" #include "llsdutil_math.h" #include "llsdutil.h" +#include "lltexturectrl.h" #include "lltrans.h" #include "llversioninfo.h" #include "llvfile.h" +#include "llviewercontrol.h" #include "llviewerinventory.h" +#include "llviewerpartsource.h" #include "llviewernetwork.h" #include "llviewerregion.h" #include "llviewertexturelist.h" #include "llvovolume.h" -#include "llviewerpartsource.h" -#include "llworld.h" -#include "fscommon.h" +#include "fsexportperms.h" + #include "llfloaterreg.h" #include @@ -66,16 +68,14 @@ const F32 MAX_TEXTURE_WAIT_TIME = 30.0f; const F32 MAX_INVENTORY_WAIT_TIME = 30.0f; const F32 MAX_ASSET_WAIT_TIME = 60.0f; -static void updateProgress(const std::string message); - // static -void FSExport::onIdle(void* user_data) +void FSFloaterObjectExport::onIdle(void* user_data) { - FSExport* self = (FSExport*)user_data; + FSFloaterObjectExport* self = (FSFloaterObjectExport*)user_data; self->onIdle(); } -void FSExport::onIdle() +void FSFloaterObjectExport::onIdle() { switch(mExportState) { @@ -97,6 +97,7 @@ void FSExport::onIdle() { mWaitTimer.start(); mLastRequest = mInventoryRequests.size(); + updateTitleProgress(INVENTORY_DOWNLOAD); } else if (mWaitTimer.getElapsedTimeF32() > MAX_INVENTORY_WAIT_TIME) { @@ -107,9 +108,6 @@ void FSExport::onIdle() object->dirtyInventory(); object->requestInventory(); - LLStringUtil::format_map_t args; - args["ITEM"] = (*iter).asString(); - updateProgress(formatString(LLTrans::getString("export_rerequesting_inventory"), args)); LL_DEBUGS("export") << "re-requested inventory of " << (*iter).asString() << LL_ENDL; } } @@ -130,6 +128,7 @@ void FSExport::onIdle() { mWaitTimer.start(); mLastRequest = mAssetRequests.size(); + updateTitleProgress(ASSET_DOWNLOAD); } else if (mWaitTimer.getElapsedTimeF32() > MAX_ASSET_WAIT_TIME) { @@ -158,21 +157,22 @@ void FSExport::onIdle() mWaitTimer.stop(); llofstream file; - file.open(mFileName, std::ios_base::out | std::ios_base::binary); - std::string zip_data = zip_llsd(mFile); + file.open(mFilename, std::ios_base::out | std::ios_base::binary); + std::string zip_data = zip_llsd(mManifest); file.write(zip_data.data(), zip_data.size()); file.close(); - LL_DEBUGS("export") << "Export finished and written to " << mFileName << LL_ENDL; + LL_DEBUGS("export") << "Export finished and written to " << mFilename << LL_ENDL; - updateProgress(LLTrans::getString("export_finished")); LLSD args; - args["FILENAME"] = mFileName; + args["FILENAME"] = mFilename; LLNotificationsUtil::add("ExportFinished", args); + closeFloater(); } else if (mLastRequest != mRequestedTexture.size()) { mWaitTimer.start(); mLastRequest = mRequestedTexture.size(); + updateTitleProgress(TEXTURE_DOWNLOAD); } else if (mWaitTimer.getElapsedTimeF32() > MAX_TEXTURE_WAIT_TIME) { @@ -183,11 +183,8 @@ void FSExport::onIdle() LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(texture_id, FTT_DEFAULT, MIPMAP_TRUE); image->setBoostLevel(LLViewerTexture::BOOST_MAX_LEVEL); image->forceToSaveRawImage(0); - image->setLoadedCallback(FSExport::onImageLoaded, 0, TRUE, FALSE, this, &mCallbackTextureList); - - LLStringUtil::format_map_t args; - args["ITEM"] = texture_id.asString(); - updateProgress(formatString(LLTrans::getString("export_rerequesting_texture"), args)); + image->setLoadedCallback(FSFloaterObjectExport::onImageLoaded, 0, TRUE, FALSE, this, &mCallbackTextureList); + LL_DEBUGS("export") << "re-requested texture " << texture_id.asString() << LL_ENDL; } } @@ -197,32 +194,62 @@ void FSExport::onIdle() } } -void FSExport::exportSelection() +FSFloaterObjectExport::FSFloaterObjectExport(const LLSD& key) +: LLFloater(key), +mTotal(0), +mIncluded(0), +mNumTextures(0), +mNumExportableTextures(0) { - LLObjectSelectionHandle selection = LLSelectMgr::instance().getSelection(); - if (!selection) + addSelectedObjects(); +} + +FSFloaterObjectExport::~FSFloaterObjectExport() +{ + if (gIdleCallbacks.containsFunction(FSFloaterObjectExport::onIdle, this)) + { + gIdleCallbacks.deleteFunction(FSFloaterObjectExport::onIdle, this); + } +} + +BOOL FSFloaterObjectExport::postBuild() +{ + childSetTextArg("exportable_prims", "[COUNT]", llformat("%d", mIncluded)); + childSetTextArg("exportable_prims", "[TOTAL]", llformat("%d", mTotal)); + childSetTextArg("exportable_textures", "[COUNT]", llformat("%d", mNumExportableTextures)); + childSetTextArg("exportable_textures", "[TOTAL]", llformat("%d", mNumTextures)); + + mObjectList = getChild("selected_objects"); + mExportBtn = getChild("export_btn"); + if (mExportBtn) + mExportBtn->setCommitCallback(boost::bind(&FSFloaterObjectExport::onClickExport, this)); + + LLUIString title = getString("title_floater"); + title.setArg("[OBJECT]", mObjectName); + setTitle(title); + populateObjectList(); + addTexturePreview(); + + return TRUE; +} + +bool FSFloaterObjectExport::exportSelection() +{ + if (!mSelection) { LL_WARNS("export") << "Nothing selected; Bailing!" << LL_ENDL; - return; + return false; } - LLObjectSelection::valid_root_iterator iter = selection->valid_root_begin(); + LLObjectSelection::valid_root_iterator iter = mSelection->valid_root_begin(); LLSelectNode* node = *iter; if (!node) { LL_WARNS("export") << "No node selected; Bailing!" << LL_ENDL; - return; + return false; } - - LLFilePicker& file_picker = LLFilePicker::instance(); - if(!file_picker.getSaveFile(LLFilePicker::FFSAVE_EXPORT, LLDir::getScrubbedFileName(node->mName + ".oxp"))) - { - llinfos << "User closed the filepicker, aborting export!" << llendl; - return; - } - mFileName = file_picker.getFirstFile(); - mFilePath = gDirUtilp->getDirName(mFileName); + mFilePath = gDirUtilp->getDirName(mFilename); - mFile.clear(); + mManifest.clear(); mRequestedTexture.clear(); mExported = false; @@ -230,17 +257,23 @@ void FSExport::exportSelection() mInventoryRequests.clear(); mAssetRequests.clear(); mTextureChecked.clear(); - - mFile["format_version"] = 1; - mFile["client"] = LLAppViewer::instance()->getSecondLifeTitle() + LLVersionInfo::getChannel(); - mFile["client_version"] = LLVersionInfo::getVersion(); - mFile["grid"] = LLGridManager::getInstance()->getGridLabel(); - LLFloaterReg::showInstance("fs_export"); - updateProgress(LLTrans::getString("export_started")); - - for ( ; iter != selection->valid_root_end(); ++iter) + + std::string author = "Unknown"; + if (gCacheName) + gCacheName->getFullName(gAgentID, author); + char buff[10]; + time_t now = time(NULL); + strftime(buff, 10, "%Y-%m-%d", localtime(&now)); + std::string date(buff, 10); + mManifest["format_version"] = OXP_FORMAT_VERSION; + mManifest["client"] = LLVersionInfo::getChannelAndVersion(); + mManifest["creation_date"] = date; + mManifest["author"] = author; + mManifest["grid"] = LLGridManager::getInstance()->getGridLabel(); + + for ( ; iter != mSelection->valid_root_end(); ++iter) { - mFile["linkset"].append(getLinkSet((*iter))); + mManifest["linkset"].append(getLinkSet((*iter))); } if (mExported && !mAborted) @@ -252,12 +285,13 @@ void FSExport::exportSelection() } else { - updateProgress(LLTrans::getString("export_nothing_exported")); LL_WARNS("export") << "Nothing was exported. File not created." << LL_ENDL; + return false; } + return true; } -LLSD FSExport::getLinkSet(LLSelectNode* node) +LLSD FSFloaterObjectExport::getLinkSet(LLSelectNode* node) { LLSD linkset; LLViewerObject* object = node->getObject(); @@ -280,7 +314,7 @@ LLSD FSExport::getLinkSet(LLSelectNode* node) return linkset; } -void FSExport::addPrim(LLViewerObject* object, bool root) +void FSFloaterObjectExport::addPrim(LLViewerObject* object, bool root) { LLSD prim; LLUUID object_id = object->getID(); @@ -295,49 +329,9 @@ void FSExport::addPrim(LLViewerObject* object, bool root) return (node->getObject() && node->getObject()->mID == mID); } } func(object_id); + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(&func); - if (node) - { - if ((LLGridManager::getInstance()->isInSecondLife()) - && object->permYouOwner() - && (gAgentID == node->mPermissions->getCreator() || megaPrimCheck(node->mPermissions->getCreator(), object))) - { - default_prim = false; - } -#ifdef OPENSIM - if (LLGridManager::getInstance()->isInOpenSim()) - { - LLViewerRegion* region = gAgent.getRegion(); - if (region && region->regionSupportsExport() == LLViewerRegion::EXPORT_ALLOWED) - { - default_prim = !node->mPermissions->allowExportBy(gAgent.getID()); - } - else if (region && region->regionSupportsExport() == LLViewerRegion::EXPORT_DENIED) - { - // Only your own creations if this is explicitly set - default_prim = (!(object->permYouOwner() - && gAgentID == node->mPermissions->getCreator())); - } - /// TODO: Once enough grids adopt a version supporting the exports cap, get consensus - /// on whether we should allow full perm exports anymore. - else // LLViewerRegion::EXPORT_UNDEFINED - { - default_prim = (!(object->permYouOwner() - && object->permModify() - && object->permCopy() - && object->permTransfer())); - } - } -#endif - } - else - { - LL_WARNS("export") << "LLSelect node for " << object_id.asString() << " not found. Using default prim instead." << LL_ENDL; - LLStringUtil::format_map_t args; - args["OBJECT"] = object_id.asString(); - updateProgress(formatString(LLTrans::getString("export_node_not_found"), args)); - default_prim = true; - } + default_prim = (!FSExportPermsCheck::canExportNode(node)); if (root) { @@ -357,10 +351,6 @@ void FSExport::addPrim(LLViewerObject* object, bool root) if (default_prim) { - LLStringUtil::format_map_t args; - args["OBJECT"] = object_id.asString(); - updateProgress(formatString(LLTrans::getString("export_failed_export_check"), args)); - LL_DEBUGS("export") << object_id.asString() << " failed export check. Using default prim" << LL_ENDL; prim["flags"] = ll_sd_from_U32((U32)0); prim["volume"]["path"] = LLPathParams().asLLSD(); @@ -395,7 +385,6 @@ void FSExport::addPrim(LLViewerObject* object, bool root) { if (!mAborted) { - updateProgress(LLTrans::getString("export_fail_no_mesh")); mAborted = true; } return; @@ -538,20 +527,23 @@ void FSExport::addPrim(LLViewerObject* object, bool root) prim["touch_name"] = node->mTouchName; prim["sit_name"] = node->mSitName; - mInventoryRequests.push_back(object_id); - object->registerInventoryListener(this, NULL); - object->dirtyInventory(); - object->requestInventory(); + static LLCachedControl sExportContents(gSavedSettings, "FSExportContents"); + if (sExportContents) + { + mInventoryRequests.push_back(object_id); + object->registerInventoryListener(this, NULL); + object->dirtyInventory(); + object->requestInventory(); + } } - mFile["prim"][object_id.asString()] = prim; + mManifest["prim"][object_id.asString()] = prim; } -bool FSExport::exportTexture(const LLUUID& texture_id) +bool FSFloaterObjectExport::exportTexture(const LLUUID& texture_id) { if(texture_id.isNull()) { - updateProgress(LLTrans::getString("export_failed_null_texture")); LL_WARNS("export") << "Attempted to export NULL texture." << LL_ENDL; return false; } @@ -564,12 +556,12 @@ bool FSExport::exportTexture(const LLUUID& texture_id) if (gAssetStorage->mStaticVFS->getExists(texture_id, LLAssetType::AT_TEXTURE)) { LL_DEBUGS("export") << "Texture " << texture_id.asString() << " is local static." << LL_ENDL; - // no need to save the texture data as the viewer allready has it in a local file. + // no need to save the texture data as the viewer already has it in a local file. mTextureChecked[texture_id] = true; return true; } - //TODO: check for local file static texture. The above will only get the static texture in the static db, not indevitial texture files. + //TODO: check for local file static texture. The above will only get the static texture in the static db, not individual textures. LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(texture_id); bool texture_export = false; @@ -590,105 +582,53 @@ bool FSExport::exportTexture(const LLUUID& texture_id) if (texture_export) { - assetCheck(texture_id, name, description); + FSExportPermsCheck::canExportAsset(texture_id, &name, &description); } else { - texture_export = assetCheck(texture_id, name, description); + texture_export = FSExportPermsCheck::canExportAsset(texture_id, &name, &description); } mTextureChecked[texture_id] = texture_export; - LLStringUtil::format_map_t args; - args["ITEM"] = name; - if (!texture_export) { - updateProgress(formatString(LLTrans::getString("export_asset_failed_export_check"), args)); - LL_DEBUGS("export") << "Texture " << texture_id << " failed export check." << LL_ENDL; return false; } LL_DEBUGS("export") << "Loading image texture " << texture_id << LL_ENDL; - updateProgress(formatString(LLTrans::getString("export_loading_texture"), args)); mRequestedTexture[texture_id].name = name; mRequestedTexture[texture_id].description = description; LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(texture_id, FTT_DEFAULT, MIPMAP_TRUE); image->setBoostLevel(LLViewerTexture::BOOST_MAX_LEVEL); image->forceToSaveRawImage(0); - image->setLoadedCallback(FSExport::onImageLoaded, 0, TRUE, FALSE, this, &mCallbackTextureList); + image->setLoadedCallback(FSFloaterObjectExport::onImageLoaded, 0, TRUE, FALSE, this, &mCallbackTextureList); return true; } // static -void FSExport::onImageLoaded(BOOL success, LLViewerFetchedTexture* src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) +void FSFloaterObjectExport::onImageLoaded(BOOL success, LLViewerFetchedTexture* src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) { if(final && success) { - const LLUUID& texture_id = src_vi->getID(); - LLImageJ2C* mFormattedImage = new LLImageJ2C; - FSExportCacheReadResponder* responder = new FSExportCacheReadResponder(texture_id, mFormattedImage); - LLAppViewer::getTextureCache()->readFromCache(texture_id, LLWorkerThread::PRIORITY_HIGH, 0, 999999, responder); - LL_DEBUGS("export") << "Fetching " << texture_id << " from the TextureCache" << LL_ENDL; + // *HACK ALERT: I'm lazy so I moved this to a non-static member function. + FSFloaterObjectExport* parent = (FSFloaterObjectExport *)userdata; + parent->fetchTextureFromCache(src_vi); } } - -FSExportCacheReadResponder::FSExportCacheReadResponder(const LLUUID& id, LLImageFormatted* image) : - mFormattedImage(image), - mID(id) +void FSFloaterObjectExport::fetchTextureFromCache(LLViewerFetchedTexture* src_vi) { - setImage(image); + const LLUUID& texture_id = src_vi->getID(); + LLImageJ2C* mFormattedImage = new LLImageJ2C; + FSFloaterObjectExport::FSExportCacheReadResponder* responder = new FSFloaterObjectExport::FSExportCacheReadResponder(texture_id, mFormattedImage, this); + LLAppViewer::getTextureCache()->readFromCache(texture_id, LLWorkerThread::PRIORITY_HIGH, 0, 999999, responder); + LL_DEBUGS("export") << "Fetching " << texture_id << " from the TextureCache" << LL_ENDL; } -void FSExportCacheReadResponder::setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal) -{ - if (imageformat != IMG_CODEC_J2C) - { - LL_WARNS("export") << "Texture " << mID << " is not formatted as J2C." << LL_ENDL; - } - - if (mFormattedImage.notNull()) - { - mFormattedImage->appendData(data, datasize); - } - else - { - mFormattedImage = LLImageFormatted::createFromType(imageformat); - mFormattedImage->setData(data, datasize); - } - mImageSize = imagesize; - mImageLocal = imagelocal; -} - -void FSExportCacheReadResponder::completed(bool success) -{ - LLStringUtil::format_map_t args; - args["TEXTURE"] = mID.asString(); - if (success && mFormattedImage.notNull() && mImageSize > 0) - { - LL_DEBUGS("export") << "SUCCESS getting texture " << mID << LL_ENDL; - FSExport::getInstance()->saveFormattedImage(mFormattedImage, mID); - } - else - { - //NOTE: we can get here due to trying to fetch a static local texture - // do nothing spiachel as importing static local texture just needs an UUID only. - if (!success) - { - LL_WARNS("export") << "FAILED to get texture " << mID << LL_ENDL; - } - if (mFormattedImage.isNull()) - { - LL_WARNS("export") << "FAILED: NULL texture " << mID << LL_ENDL; - } - FSExport::getInstance()->removeRequestedTexture(mID); - } -} - -void FSExport::removeRequestedTexture(LLUUID texture_id) +void FSFloaterObjectExport::removeRequestedTexture(LLUUID texture_id) { if (mRequestedTexture.count(texture_id) != 0) { @@ -696,42 +636,21 @@ void FSExport::removeRequestedTexture(LLUUID texture_id) } } -void FSExport::saveFormattedImage(LLPointer mFormattedImage, LLUUID id) +void FSFloaterObjectExport::saveFormattedImage(LLPointer mFormattedImage, LLUUID id) { std::stringstream texture_str; texture_str.write((const char*) mFormattedImage->getData(), mFormattedImage->getDataSize()); std::string str = texture_str.str(); - mFile["asset"][id.asString()]["name"] = mRequestedTexture[id].name; - mFile["asset"][id.asString()]["description"] = mRequestedTexture[id].description; - mFile["asset"][id.asString()]["type"] = LLAssetType::lookup(LLAssetType::AT_TEXTURE); - mFile["asset"][id.asString()]["data"] = LLSD::Binary(str.begin(),str.end()); - - LLStringUtil::format_map_t args; - args["TEXTURE"] = mRequestedTexture[id].name; - updateProgress(formatString(LLTrans::getString("export_saving_texture"), args)); + mManifest["asset"][id.asString()]["name"] = mRequestedTexture[id].name; + mManifest["asset"][id.asString()]["description"] = mRequestedTexture[id].description; + mManifest["asset"][id.asString()]["type"] = LLAssetType::lookup(LLAssetType::AT_TEXTURE); + mManifest["asset"][id.asString()]["data"] = LLSD::Binary(str.begin(),str.end()); removeRequestedTexture(id); } -bool FSExport::megaPrimCheck(LLUUID creator, LLViewerObject* object) -{ - F32 max_object_size = LLWorld::getInstance()->getRegionMaxPrimScale(); - LLVector3 vec = object->getScale(); - if (!(vec.mV[VX] > max_object_size || vec.mV[VY] > max_object_size || vec.mV[VZ] > max_object_size)) - { - return false; - } - - if (creator == LLUUID("7ffd02d0-12f4-48b4-9640-695708fd4ae4")) // Zwagoth Klaar - { - return true; - } - - return false; -} - -bool FSExport::defaultTextureCheck(const LLUUID asset_id) +bool FSFloaterObjectExport::defaultTextureCheck(const LLUUID asset_id) { if (asset_id == LL_DEFAULT_WOOD_UUID || asset_id == LL_DEFAULT_STONE_UUID || @@ -755,62 +674,7 @@ bool FSExport::defaultTextureCheck(const LLUUID asset_id) return false; } -bool FSExport::assetCheck(LLUUID asset_id, std::string& name, std::string& description) -{ - bool exportable = false; - LLViewerInventoryCategory::cat_array_t cats; - LLViewerInventoryItem::item_array_t items; - LLAssetIDMatches asset_id_matches(asset_id); - gInventory.collectDescendentsIf(LLUUID::null, - cats, - items, - LLInventoryModel::INCLUDE_TRASH, - asset_id_matches); - - if (items.count()) - { - // use the name of the first match - name = items[0]->getName(); - description = items[0]->getDescription(); - - for (S32 i = 0; i < items.count(); ++i) - { - if (!exportable) - { - LLPermissions perms = items[i]->getPermissions(); -#ifdef OPENSIM - if (LLGridManager::getInstance()->isInOpenSim()) - { - LLViewerRegion* region = gAgent.getRegion(); - if (!region) return false; - if (region->regionSupportsExport() == LLViewerRegion::EXPORT_ALLOWED) - { - exportable = (perms.getMaskOwner() & PERM_EXPORT) == PERM_EXPORT; - } - else if (region->regionSupportsExport() == LLViewerRegion::EXPORT_DENIED) - { - exportable = perms.getCreator() == gAgentID; - } - /// TODO: Once enough grids adopt a version supporting the exports cap, get consensus - /// on whether we should allow full perm exports anymore. - else - { - exportable = (perms.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED; - } - } -#endif - if (LLGridManager::getInstance()->isInSecondLife() && (perms.getCreator() == gAgentID)) - { - exportable = true; - } - } - } - } - - return exportable; -} - -void FSExport::inventoryChanged(LLViewerObject* object, LLInventoryObject::object_list_t* inventory, S32 serial_num, void* user_data) +void FSFloaterObjectExport::inventoryChanged(LLViewerObject* object, LLInventoryObject::object_list_t* inventory, S32 serial_num, void* user_data) { uuid_vec_t::iterator v_iter = std::find(mInventoryRequests.begin(), mInventoryRequests.end(), object->getID()); if (v_iter != mInventoryRequests.end()) @@ -819,7 +683,7 @@ void FSExport::inventoryChanged(LLViewerObject* object, LLInventoryObject::objec mInventoryRequests.erase(v_iter); } - LLSD& prim = mFile["prim"][object->getID().asString()]; + LLSD& prim = mManifest["prim"][object->getID().asString()]; for (LLInventoryObject::object_list_t::const_iterator iter = inventory->begin(); iter != inventory->end(); ++iter) { LLInventoryItem* item = dynamic_cast(iter->get()); @@ -860,9 +724,6 @@ void FSExport::inventoryChanged(LLViewerObject* object, LLInventoryObject::objec // Only complain if we're trying to export a non-NULL item and fail if (!item->getUUID().isNull()) { - LLStringUtil::format_map_t args; - args["ITEM"] = item->getName(); - updateProgress(formatString(LLTrans::getString("export_asset_failed_export_check"), args)); LL_DEBUGS("export") << "Item " << item->getName() << ", UUID " << item->getUUID() << " failed export check." << LL_ENDL; } continue; @@ -871,15 +732,12 @@ void FSExport::inventoryChanged(LLViewerObject* object, LLInventoryObject::objec if (item->getType() == LLAssetType::AT_NONE || item->getType() == LLAssetType::AT_OBJECT) { // currentelly not exportable - LLStringUtil::format_map_t args; - args["ITEM"] = item->getName(); - updateProgress(formatString(LLTrans::getString("export_item_not_exportable"), args)); LL_DEBUGS("export") << "Skipping " << LLAssetType::lookup(item->getType()) << " item " << item->getName() << LL_ENDL; continue; } prim["content"].append(item->getUUID()); - mFile["inventory"][item->getUUID().asString()] = ll_create_sd_from_inventory_item(item); + mManifest["inventory"][item->getUUID().asString()] = ll_create_sd_from_inventory_item(item); if (item->getAssetUUID().isNull() && item->getType() == LLAssetType::AT_NOTECARD) { @@ -887,24 +745,21 @@ void FSExport::inventoryChanged(LLViewerObject* object, LLInventoryObject::objec // Blank Notecard item can have NULL asset ID. // Generate a new UUID and save as an empty asset. LLUUID asset_uuid = LLUUID::generateNewID(); - mFile["inventory"][item->getUUID().asString()]["asset_id"] = asset_uuid; + mManifest["inventory"][item->getUUID().asString()]["asset_id"] = asset_uuid; - mFile["asset"][asset_uuid.asString()]["name"] = item->getName(); - mFile["asset"][asset_uuid.asString()]["description"] = item->getDescription(); - mFile["asset"][asset_uuid.asString()]["type"] = LLAssetType::lookup(item->getType()); + mManifest["asset"][asset_uuid.asString()]["name"] = item->getName(); + mManifest["asset"][asset_uuid.asString()]["description"] = item->getDescription(); + mManifest["asset"][asset_uuid.asString()]["type"] = LLAssetType::lookup(item->getType()); LLNotecard nc(255); //don't need to allocate default size of 65536 std::stringstream out_stream; nc.exportStream(out_stream); std::string out_string = out_stream.str(); std::vector buffer(out_string.begin(), out_string.end()); - mFile["asset"][asset_uuid.asString()]["data"] = buffer; + mManifest["asset"][asset_uuid.asString()]["data"] = buffer; } else { - LLStringUtil::format_map_t args; - args["ITEM"] = item->getName(); - updateProgress(formatString(LLTrans::getString("export_requesting_asset"), args)); LL_DEBUGS("export") << "Requesting asset " << item->getAssetUUID() << " for item " << item->getUUID() << LL_ENDL; mAssetRequests.push_back(item->getUUID()); FSAssetResourceData* data = new FSAssetResourceData; @@ -937,48 +792,39 @@ void FSExport::inventoryChanged(LLViewerObject* object, LLInventoryObject::objec } } } - object->removeInventoryListener(this); } // static -void FSExport::onLoadComplete(LLVFS* vfs, const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status) +void FSFloaterObjectExport::onLoadComplete(LLVFS* vfs, const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status) { FSAssetResourceData* data = (FSAssetResourceData*)user_data; - FSExport* self = (FSExport*)data->user_data; + FSFloaterObjectExport* self = (FSFloaterObjectExport*)data->user_data; LLUUID item_uuid = data->uuid; self->removeRequestedAsset(item_uuid); if (status != 0) { - LLStringUtil::format_map_t args; - args["ITEM"] = asset_uuid.asString(); - args["STATUS"] = llformat("%d",status); - args["EXT_STATUS"] = llformat("%d",ext_status); - updateProgress(formatString(LLTrans::getString("export_failed_fetch"), args)); LL_WARNS("export") << "Problem fetching asset: " << asset_uuid << " " << status << " " << ext_status << LL_ENDL; delete data; return; } - LLStringUtil::format_map_t args; - args["ITEM"] = data->name; - updateProgress(formatString(LLTrans::getString("export_saving_asset"), args)); LL_DEBUGS("export") << "Saving asset " << asset_uuid.asString() << " of item " << item_uuid.asString() << LL_ENDL; LLVFile file(vfs, asset_uuid, type); S32 file_length = file.getSize(); std::vector buffer(file_length); file.read(&buffer[0], file_length); - self->mFile["asset"][asset_uuid.asString()]["name"] = data->name; - self->mFile["asset"][asset_uuid.asString()]["description"] = data->description; - self->mFile["asset"][asset_uuid.asString()]["type"] = LLAssetType::lookup(type); - self->mFile["asset"][asset_uuid.asString()]["data"] = buffer; + self->mManifest["asset"][asset_uuid.asString()]["name"] = data->name; + self->mManifest["asset"][asset_uuid.asString()]["description"] = data->description; + self->mManifest["asset"][asset_uuid.asString()]["type"] = LLAssetType::lookup(type); + self->mManifest["asset"][asset_uuid.asString()]["data"] = buffer; - if (self->mFile["inventory"].has(item_uuid.asString())) + if (self->mManifest["inventory"].has(item_uuid.asString())) { - if (self->mFile["inventory"][item_uuid.asString()]["asset_id"].asUUID().isNull()) + if (self->mManifest["inventory"][item_uuid.asString()]["asset_id"].asUUID().isNull()) { - self->mFile["inventory"][item_uuid.asString()]["asset_id"] = asset_uuid; + self->mManifest["inventory"][item_uuid.asString()]["asset_id"] = asset_uuid; } } @@ -1013,9 +859,6 @@ void FSExport::onLoadComplete(LLVFS* vfs, const LLUUID& asset_uuid, LLAssetType: LLDataPackerAsciiBuffer dp((char*)&buffer[0], file_length+1); if (!gesture->deserialize(dp)) { - LLStringUtil::format_map_t args; - args["ITEM"] = asset_uuid.asString(); - updateProgress(formatString(LLTrans::getString("export_failed_to_load"), args)); LL_WARNS("export") << "Unable to load gesture " << asset_uuid << LL_ENDL; break; } @@ -1032,11 +875,8 @@ void FSExport::onLoadComplete(LLVFS* vfs, const LLUUID& asset_uuid, LLAssetType: case STEP_ANIMATION: { LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step; - if (!self->assetCheck(anim_step->mAnimAssetID, name, description)) + if (!FSExportPermsCheck::canExportAsset(anim_step->mAnimAssetID, &name, &description)) { - LLStringUtil::format_map_t args; - args["ITEM"] = data->name; - updateProgress(formatString(LLTrans::getString("export_asset_failed_export_check"), args)); LL_DEBUGS("export") << "Asset in gesture " << data->name << " failed export check." << LL_ENDL; break; } @@ -1045,10 +885,7 @@ void FSExport::onLoadComplete(LLVFS* vfs, const LLUUID& asset_uuid, LLAssetType: anim_data->name = anim_step->mAnimName; anim_data->user_data = self; anim_data->uuid = anim_step->mAnimAssetID; - - LLStringUtil::format_map_t args; - args["ITEM"] = anim_step->mAnimAssetID.asString(); - updateProgress(formatString(LLTrans::getString("export_requesting_asset"), args)); + LL_DEBUGS("export") << "Requesting animation asset " << anim_step->mAnimAssetID.asString() << LL_ENDL; self->mAssetRequests.push_back(anim_step->mAnimAssetID); gAssetStorage->getAssetData(anim_step->mAnimAssetID, @@ -1061,11 +898,8 @@ void FSExport::onLoadComplete(LLVFS* vfs, const LLUUID& asset_uuid, LLAssetType: case STEP_SOUND: { LLGestureStepSound* sound_step = (LLGestureStepSound*)step; - if (!self->assetCheck(sound_step->mSoundAssetID, name, description)) + if (!FSExportPermsCheck::canExportAsset(sound_step->mSoundAssetID, &name, &description)) { - LLStringUtil::format_map_t args; - args["ITEM"] = data->name; - updateProgress(formatString(LLTrans::getString("export_asset_failed_export_check"), args)); LL_DEBUGS("export") << "Asset in gesture " << data->name << " failed export check." << LL_ENDL; break; } @@ -1074,10 +908,7 @@ void FSExport::onLoadComplete(LLVFS* vfs, const LLUUID& asset_uuid, LLAssetType: sound_data->name = sound_step->mSoundName; sound_data->user_data = self; sound_data->uuid = sound_step->mSoundAssetID; - - LLStringUtil::format_map_t args; - args["ITEM"] = sound_step->mSoundAssetID.asString(); - updateProgress(formatString(LLTrans::getString("export_requesting_asset"), args)); + LL_DEBUGS("export") << "Requesting sound asset " << sound_step->mSoundAssetID.asString() << LL_ENDL; self->mAssetRequests.push_back(sound_step->mSoundAssetID); gAssetStorage->getAssetData(sound_step->mSoundAssetID, @@ -1101,7 +932,7 @@ void FSExport::onLoadComplete(LLVFS* vfs, const LLUUID& asset_uuid, LLAssetType: delete data; } -void FSExport::removeRequestedAsset(LLUUID asset_uuid) +void FSFloaterObjectExport::removeRequestedAsset(LLUUID asset_uuid) { uuid_vec_t::iterator iter = std::find(mAssetRequests.begin(), mAssetRequests.end(), asset_uuid); if (iter != mAssetRequests.end()) @@ -1111,53 +942,283 @@ void FSExport::removeRequestedAsset(LLUUID asset_uuid) } } -// static -void updateProgress(const std::string message) +void FSFloaterObjectExport::addObject(const LLViewerObject* prim, const std::string name) { - FSFloaterObjectExport* export_floater = LLFloaterReg::findTypedInstance("fs_export"); - if (export_floater) - export_floater->updateProgress(message); + mObjects.push_back(std::pair((LLViewerObject*)prim, name)); } -//----------------------------------------------------- -// FSFloaterObjectExport -//----------------------------------------------------- - -FSFloaterObjectExport::FSFloaterObjectExport(const LLSD& key) -: LLFloater(key), - mOutputList(NULL) +// *TODO: I know it's really lame to tack this in here, maybe someday it can be integrated properly. +void FSFloaterObjectExport::updateTextureInfo() { -} - -// virtual -FSFloaterObjectExport::~FSFloaterObjectExport() -{ -} - -// virtual -BOOL FSFloaterObjectExport::postBuild() -{ - mOutputList = getChild("export_output"); - if (mOutputList) - mOutputList->deleteAllItems(); - childSetAction("close_btn", boost::bind(&FSFloaterObjectExport::onCloseBtn, this)); - return TRUE; -} - -void FSFloaterObjectExport::onCloseBtn() -{ - mOutputList->deleteAllItems(); - closeFloater(); -} - -void FSFloaterObjectExport::updateProgress(const std::string message) -{ - if (mOutputList) + mTextures.clear(); + //mTextureNames.clear(); + + for (obj_info_t::iterator obj_iter = mObjects.begin(); obj_iter != mObjects.end(); ++obj_iter) { - LLSD row; - row["columns"][0]["value"] = message; - mOutputList->addElement(row); - mOutputList->selectItemByLabel(message); - mOutputList->scrollToShowSelected(); + LLViewerObject* obj = obj_iter->first; + S32 num_faces = obj->getVolume()->getNumVolumeFaces(); + for (S32 face_num = 0; face_num < num_faces; ++face_num) + { + LLTextureEntry* te = obj->getTE(face_num); + const LLUUID id = te->getID(); + + if (std::find(mTextures.begin(), mTextures.end(), id) != mTextures.end()) continue; + + mTextures.push_back(id); + bool exportable = false; + LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(id); + std::string name; + std::string description; + if (LLGridManager::getInstance()->isInSecondLife()) + { + if (imagep->mComment.find("a") != imagep->mComment.end()) + { + if (LLUUID(imagep->mComment["a"]) == gAgentID) + { + exportable = true; + LL_DEBUGS("export") << id << " passed texture export comment check." << LL_ENDL; + } + } + } + if (exportable) + FSExportPermsCheck::canExportAsset(id, &name, &description); + else + exportable = FSExportPermsCheck::canExportAsset(id, &name, &description); + + if (exportable) + { + //std::string safe_name = gDirUtilp->getScrubbedFileName(name); + //std::replace(safe_name.begin(), safe_name.end(), ' ', '_'); + mTextureNames.push_back(name); + } + else + { + mTextureNames.push_back(std::string()); + } + } + } +} + +void FSFloaterObjectExport::updateTitleProgress(FSExportState state) +{ + LLUIString title; + switch (state) + { + case INVENTORY_DOWNLOAD: + { + title = getString("title_inventory"); + break; + } + case ASSET_DOWNLOAD: + { + title = getString("title_assets"); + break; + } + case TEXTURE_DOWNLOAD: + { + title = getString("title_textures"); + break; + } + case IDLE: + default: + LL_WARNS("export") << "Unhandled case: " << state << LL_ENDL; + return; + } + LLSD args; + args["OBJECT"] = mObjectName; + title.setArgs(args); + setTitle(title); +} + +void FSFloaterObjectExport::onClickExport() +{ + LLFilePicker& file_picker = LLFilePicker::instance(); + if(!file_picker.getSaveFile(LLFilePicker::FFSAVE_EXPORT, LLDir::getScrubbedFileName(mObjectName + ".oxp"))) + { + llinfos << "User closed the filepicker, aborting export!" << llendl; + return; + } + mFilename = file_picker.getFirstFile(); + + LLUIString title = getString("title_working"); + title.setArg("[OBJECT]", mObjectName); + setTitle(title); + + if (!exportSelection()) + { + LLNotificationsUtil::add("ExportFailed"); + closeFloater(); + } +} + +void FSFloaterObjectExport::populateObjectList() +{ + if (mObjectList && !mObjects.empty()) + { + for (obj_info_t::iterator obj_iter = mObjects.begin(); obj_iter != mObjects.end(); ++obj_iter) + { + LLSD element; + element["columns"][0]["column"] = "icon"; + element["columns"][0]["type"] = "icon"; + element["columns"][0]["value"] = "Inv_Object"; + element["columns"][1]["column"] = "name"; + element["columns"][1]["value"] = obj_iter->second; + mObjectList->addElement(element, ADD_BOTTOM); + + } + } +} + +// Copypasta from DAE Export. :o +void FSFloaterObjectExport::addSelectedObjects() +{ + if ((mSelection = LLSelectMgr::getInstance()->getSelection())) + { + mObjectName = mSelection->getFirstRootNode()->mName; + for (LLObjectSelection::iterator iter = mSelection->begin(); iter != mSelection->end(); ++iter) + { + LLSelectNode* node = *iter; + mTotal++; + if (!node->getObject()->getVolume() || !FSExportPermsCheck::canExportNode(node)) continue; + mIncluded++; + addObject(node->getObject(), node->mName); + } + + if (mObjects.empty()) + { + LL_WARNS("export") << "Nothing selected passed permissions checks!" << LL_ENDL; + LLNotificationsUtil::add("ExportFailed"); + closeFloater(); + return; + } + + updateTextureInfo(); + mNumTextures = mTextures.size(); + mNumExportableTextures = getNumExportableTextures(); + } + else + { + LL_WARNS("export") << "Nothing selected!" << LL_ENDL; + LLNotificationsUtil::add("ExportFailed"); + closeFloater(); + } +} + +S32 FSFloaterObjectExport::getNumExportableTextures() +{ + S32 res = 0; + for (string_list_t::const_iterator t = mTextureNames.begin(); t != mTextureNames.end(); ++t) + { + std::string name = *t; + if (!name.empty()) + { + ++res; + } + } + + return res; +} + +void FSFloaterObjectExport::addTexturePreview() +{ + S32 num_text = mNumExportableTextures; + if (num_text == 0) return; + S32 img_width = 100; + S32 img_height = img_width + 15; + S32 panel_height = (num_text / 2 + 1) * (img_height) + 10; + LLRect pr(0, panel_height, 230, 0); + LLPanel::Params pp; + pp.rect(pr); + pp.name("textures_panel"); + pp.layout("topleft"); + pp.enabled(false); + LLPanel* texture_panel = LLUICtrlFactory::create(pp); + getChild("selected_textures")->addChild(texture_panel); + S32 img_nr = 0; + for (S32 i=0; i < mTextures.size(); i++) + { + if (mTextureNames[i].empty()) continue; + + S32 left = 8 + (img_nr % 2) * (img_width + 13); + S32 bottom = panel_height - (10 + (img_nr / 2 + 1) * (img_height)); + LLRect r(left, bottom + img_height, left + img_width, bottom); + LLTextureCtrl::Params p; + p.rect(r); + p.layout("topleft"); + p.image_id(mTextures[i]); + p.tool_tip(mTextureNames[i]); + LLTextureCtrl* texture_block = LLUICtrlFactory::create(p); + texture_panel->addChild(texture_block); + img_nr++; + } + // Put 'em in the other list too. + if (mObjectList && !mTextureNames.empty()) + { + for (string_list_t::iterator iter = mTextureNames.begin(); iter != mTextureNames.end(); ++iter) + { + LLSD element; + element["columns"][0]["column"] = "icon"; + element["columns"][0]["type"] = "icon"; + element["columns"][0]["value"] = "Inv_Texture"; + element["columns"][1]["column"] = "name"; + element["columns"][1]["value"] = (*iter); + mObjectList->addElement(element, ADD_BOTTOM); + + } + } +} + +/////////////////////////////////////////// +// FSExportCacheReadResponder + +FSFloaterObjectExport::FSExportCacheReadResponder::FSExportCacheReadResponder(const LLUUID& id, LLImageFormatted* image, FSFloaterObjectExport* parent) +: mFormattedImage(image), +mID(id), +mParent(parent) +{ + setImage(image); +} + +void FSFloaterObjectExport::FSExportCacheReadResponder::setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal) +{ + if (imageformat != IMG_CODEC_J2C) + { + LL_WARNS("export") << "Texture " << mID << " is not formatted as J2C." << LL_ENDL; + } + + if (mFormattedImage.notNull()) + { + mFormattedImage->appendData(data, datasize); + } + else + { + mFormattedImage = LLImageFormatted::createFromType(imageformat); + mFormattedImage->setData(data, datasize); + } + mImageSize = imagesize; + mImageLocal = imagelocal; +} + +void FSFloaterObjectExport::FSExportCacheReadResponder::completed(bool success) +{ + if (success && mFormattedImage.notNull() && mImageSize > 0) + { + LL_DEBUGS("export") << "SUCCESS getting texture " << mID << LL_ENDL; + if (mParent) + mParent->saveFormattedImage(mFormattedImage, mID); + } + else + { + /// NOTE: we can get here due to trying to fetch a static local texture + /// do nothing special as importing static local texture just needs an UUID only. + if (!success) + { + LL_WARNS("export") << "FAILED to get texture " << mID << LL_ENDL; + } + if (mFormattedImage.isNull()) + { + LL_WARNS("export") << "FAILED: NULL texture " << mID << LL_ENDL; + } + mParent->removeRequestedTexture(mID); } } diff --git a/indra/newview/fsexport.h b/indra/newview/fsfloaterexport.h similarity index 54% rename from indra/newview/fsexport.h rename to indra/newview/fsfloaterexport.h index 245db63551..402c528e72 100644 --- a/indra/newview/fsexport.h +++ b/indra/newview/fsfloaterexport.h @@ -1,10 +1,11 @@ /** - * @file fsexport.h + * @file fsfloaterexport.h * @brief export selected objects to an xml file in LLSD format. * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Phoenix Firestorm Viewer Source Code * Copyright (c) 2012 Techwolf Lupindo + * Copyright (c) 2013 Cinder Roxley * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -45,92 +46,104 @@ struct FSAssetResourceData LLUUID uuid; }; -class FSExport : public LLSingleton, public LLVOInventoryListener +class FSFloaterObjectExport : public LLFloater, public LLVOInventoryListener { - LOG_CLASS(FSExport); + LOG_CLASS(FSFloaterObjectExport); public: - void exportSelection(); + FSFloaterObjectExport(const LLSD& key); + BOOL postBuild(); + static void onImageLoaded(BOOL success, - LLViewerFetchedTexture *src_vi, - LLImageRaw* src, - LLImageRaw* aux_src, - S32 discard_level, - BOOL final, - void* userdata); + LLViewerFetchedTexture *src_vi, + LLImageRaw* src, + LLImageRaw* aux_src, + S32 discard_level, + BOOL final, + void* userdata); + void fetchTextureFromCache(LLViewerFetchedTexture* src_vi); void saveFormattedImage(LLPointer mFormattedImage, LLUUID id); void removeRequestedTexture(LLUUID texture_id); static void onIdle(void *user_data); /*virtual*/ void inventoryChanged(LLViewerObject* object, - LLInventoryObject::object_list_t* inventory, - S32 serial_num, - void* user_data); + LLInventoryObject::object_list_t* inventory, + S32 serial_num, + void* user_data); static void onLoadComplete(LLVFS *vfs, const LLUUID& asset_uuid, - LLAssetType::EType type, - void* user_data, S32 status, LLExtStat ext_status); - + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status); + private: - typedef enum - { - IDLE, - INVENTORY_DOWNLOAD, - ASSET_DOWNLOAD, - TEXTURE_DOWNLOAD - } FSExportState; + typedef enum {IDLE, INVENTORY_DOWNLOAD, ASSET_DOWNLOAD, TEXTURE_DOWNLOAD} FSExportState; + virtual ~FSFloaterObjectExport(); + + bool exportSelection(); + void addSelectedObjects(); + void populateObjectList(); + void onClickExport(); + void addTexturePreview(); + S32 getNumExportableTextures(); + void addObject(const LLViewerObject* prim, const std::string name); + void updateTextureInfo(); + void updateTitleProgress(FSExportState state); + FSExportState mExportState; - + typedef std::vector > obj_info_t; + obj_info_t mObjects; + std::string mFilename; + LLObjectSelectionHandle mSelection; + + S32 mTotal; + S32 mIncluded; + S32 mNumTextures; + S32 mNumExportableTextures; + + LLButton* mExportBtn; + LLScrollListCtrl* mObjectList; + LLScrollListCtrl* mTextureList; + + std::string mObjectName; + LLSD getLinkSet(LLSelectNode* node); void addPrim(LLViewerObject* object, bool root); bool exportTexture(const LLUUID& texture_id); - + void onIdle(); void removeRequestedAsset(LLUUID asset_uuid); - bool assetCheck(LLUUID asset_id, std::string& name, std::string& description); - bool megaPrimCheck(LLUUID creator, LLViewerObject* object); bool defaultTextureCheck(const LLUUID asset_id); - LLSD mFile; + LLSD mManifest; std::map mRequestedTexture; - std::string mFileName; + std::map mTextureChecked; std::string mFilePath; LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList; LLFrameTimer mWaitTimer; S32 mLastRequest; - std::map mTextureChecked; bool mExported; bool mAborted; bool mExportError; - + + typedef std::vector id_list_t; + typedef std::vector string_list_t; + id_list_t mTextures; + string_list_t mTextureNames; + uuid_vec_t mInventoryRequests; uuid_vec_t mAssetRequests; -}; - - -class FSExportCacheReadResponder : public LLTextureCache::ReadResponder -{ - LOG_CLASS(FSExportCacheReadResponder); -public: - FSExportCacheReadResponder(const LLUUID& id, LLImageFormatted* image); - - void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal); - virtual void completed(bool success); - -private: - LLPointer mFormattedImage; - LLUUID mID; -}; - -class FSFloaterObjectExport : public LLFloater -{ -public: - FSFloaterObjectExport(const LLSD& key); - virtual ~FSFloaterObjectExport(); - virtual BOOL postBuild(); - void onCloseBtn(); - void updateProgress(const std::string message); - -private: - LLScrollListCtrl* mOutputList; + class FSExportCacheReadResponder : public LLTextureCache::ReadResponder + { + LOG_CLASS(FSExportCacheReadResponder); + public: + FSExportCacheReadResponder(const LLUUID& id, LLImageFormatted* image, FSFloaterObjectExport* parent); + + void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal); + virtual void completed(bool success); + + private: + LLPointer mFormattedImage; + LLUUID mID; + FSFloaterObjectExport* mParent; + }; }; #endif // FS_FSEXPORT_H diff --git a/indra/newview/fsfloaterimport.cpp b/indra/newview/fsfloaterimport.cpp index 14f893ec01..5d3d703803 100644 --- a/indra/newview/fsfloaterimport.cpp +++ b/indra/newview/fsfloaterimport.cpp @@ -64,23 +64,23 @@ #include "llvfile.h" #include "llvfs.h" #include "llvolumemessage.h" +#include "fsexportperms.h" #include "material_codes.h" #include #include -FSFloaterImport::FSFloaterImport(const LLSD& key) : - LLFloater(key), +FSFloaterImport::FSFloaterImport(const LLSD& filename) : + LLFloater(filename), mCreatingActive(false), mLinkset(0), mObject(0), mPrim(0), mImportState(IDLE), - mFileReady(false) + mFileFullName(filename), + mObjectCreatedCallback() { mInstance = this; - mCommitCallbackRegistrar.add("Import.PickFile",boost::bind(&FSFloaterImport::onClickBtnPickFile,this)); - mCommitCallbackRegistrar.add("Import.ImportLinkset",boost::bind(&FSFloaterImport::onClickBtnImport,this)); mCommitCallbackRegistrar.add("Import.UploadAsset",boost::bind(&FSFloaterImport::onClickCheckBoxUploadAsset,this)); mCommitCallbackRegistrar.add("Import.TempAsset",boost::bind(&FSFloaterImport::onClickCheckBoxTempAsset,this)); @@ -95,6 +95,10 @@ FSFloaterImport::~FSFloaterImport() { LL_WARNS("import") << "FSFloaterImport::~FSFloaterImport() failed to delete idle callback" << LL_ENDL; } + if (mObjectCreatedCallback.connected()) + { + mObjectCreatedCallback.disconnect(); + } gSavedSettings.setBOOL("ShowNewInventory", mSavedSettingShowNewInventory); } @@ -107,6 +111,9 @@ BOOL FSFloaterImport::postBuild() getChild("temp_asset")->setVisible(FALSE); getChild("temp_asset")->set(FALSE); } + getChild("import_btn")->setCommitCallback(boost::bind(&FSFloaterImport::onClickBtnImport, this)); + loadFile(); + populateBackupInfo(); return TRUE; } @@ -189,39 +196,30 @@ void FSFloaterImport::onIdle() } } -void FSFloaterImport::onClickBtnPickFile() +void FSFloaterImport::loadFile() { - // pick a file - LLFilePicker& file_picker = LLFilePicker::instance(); - if(!file_picker.getOpenFile(LLFilePicker::FFLOAD_IMPORT)) - { - // User canceled or we failed to acquire file. - return; - } - mFileFullName = file_picker.getFirstFile(); - mFilePath = gDirUtilp->getDirName(mFileName); - mFileName= gDirUtilp->getBaseFileName(mFileFullName); - getChild("filename")->setValue(LLSD(mFileName)); + mFilePath = gDirUtilp->getDirName(mFilename); + mFilename = gDirUtilp->getBaseFileName(mFileFullName); - mFile.clear(); + mManifest.clear(); mTextureQueue.clear(); mAnimQueue.clear(); mSoundQueue.clear(); - mFileReady = false; mLinksetSize = 0; mTexturesTotal = 0; mAnimsTotal = 0; mSoundsTotal = 0; + bool file_loaded = false; llifstream filestream(mFileFullName, std::ios_base::in | std::ios_base::binary); if(filestream.is_open()) { filestream.seekg(0, std::ios::end); S32 file_size = (S32)filestream.tellg(); filestream.seekg(0, std::ios::beg); - if (unzip_llsd(mFile, filestream, file_size)) + if (unzip_llsd(mManifest, filestream, file_size)) { - mFileReady = true; + file_loaded = true; } else { @@ -234,22 +232,22 @@ void FSFloaterImport::onClickBtnPickFile() } filestream.close(); - if (mFileReady) + if (file_loaded) { - if (mFile.has("format_version") && mFile["format_version"].asInteger() == 1) + if (mManifest.has("format_version") && mManifest["format_version"].asInteger() <= OXP_FORMAT_VERSION) { - LLSD& linksetsd = mFile["linkset"]; + LLSD& linksetsd = mManifest["linkset"]; U32 prims = 0; for (LLSD::array_iterator linkset_iter = linksetsd.beginArray(); linkset_iter != linksetsd.endArray(); ++linkset_iter) { - LLSD& objectsd = mFile["linkset"][mLinksetSize]; + LLSD& objectsd = mManifest["linkset"][mLinksetSize]; for (LLSD::array_iterator prim_iter = objectsd.beginArray(); prim_iter != objectsd.endArray(); ++prim_iter) { - processPrim(mFile["prim"][(*prim_iter).asString()]); + processPrim(mManifest["prim"][(*prim_iter).asString()]); prims++; } mLinksetSize++; @@ -277,20 +275,34 @@ void FSFloaterImport::onClickBtnPickFile() LL_DEBUGS("import") << "Linkset size is " << mLinksetSize << LL_ENDL; if (mLinksetSize != 0) { - getChild("import_file")->setEnabled(TRUE); + getChild("import_btn")->setEnabled(TRUE); getChild("do_not_attach")->setEnabled(TRUE); getChild("region_position")->setEnabled(TRUE); getChild("upload_asset")->setEnabled(TRUE); } else { - getChild("import_file")->setEnabled(FALSE); + getChild("import_btn")->setEnabled(FALSE); getChild("do_not_attach")->setEnabled(FALSE); getChild("region_position")->setEnabled(FALSE); getChild("upload_asset")->setEnabled(FALSE); } } +void FSFloaterImport::populateBackupInfo() +{ + childSetTextArg("filename_text", "[FILENAME]", mFilename); + childSetTextArg("client_text", "[VERSION]", mManifest["format_version"].asString()); + childSetTextArg("client_text", "[CLIENT]", (mManifest.has("client") ? mManifest["client"].asString() : LLTrans::getString("Unknown"))); + childSetTextArg("author_text", "[AUTHOR]", (mManifest.has("author") ? mManifest["author"].asString() : LLTrans::getString("Unknown"))); + childSetTextArg("author_text", "[GRID]", (mManifest.has("grid") ? "@ " + mManifest["grid"].asString() : LLTrans::getString("Unknown"))); + childSetTextArg("creation_date_text", "[DATE_STRING]", (mManifest.has("creation_date") ? mManifest["creation_date"].asString(): LLTrans::getString("Unknown"))); + + LLUIString title = getString("floater_title"); + title.setArg("[FILENAME]", mFilename); + setTitle(title); +} + void FSFloaterImport::processPrim(LLSD& prim) { if (prim.has("texture")) @@ -319,21 +331,21 @@ void FSFloaterImport::processPrim(LLSD& prim) content_iter != contentsd.endArray(); ++content_iter) { - if (!mFile["inventory"].has((*content_iter).asString())) + if (!mManifest["inventory"].has((*content_iter).asString())) { continue; } - LLAssetType::EType asset_type = LLAssetType::lookup(mFile["inventory"][(*content_iter).asString()]["type"].asString().c_str()); - LLUUID asset_id = mFile["inventory"][(*content_iter).asString()]["asset_id"].asUUID(); + LLAssetType::EType asset_type = LLAssetType::lookup(mManifest["inventory"][(*content_iter).asString()]["type"].asString().c_str()); + LLUUID asset_id = mManifest["inventory"][(*content_iter).asString()]["asset_id"].asUUID(); - if (!mFile["asset"].has(asset_id.asString())) + if (!mManifest["asset"].has(asset_id.asString())) { continue; } addAsset(asset_id, asset_type); - std::vector buffer = mFile["asset"][asset_id.asString()]["data"].asBinary(); + std::vector buffer = mManifest["asset"][asset_id.asString()]["data"].asBinary(); switch(asset_type) { @@ -405,7 +417,7 @@ void FSFloaterImport::processPrim(LLSD& prim) void FSFloaterImport::addAsset(LLUUID asset_id, LLAssetType::EType asset_type) { - if (!mFile["asset"].has(asset_id.asString())) + if (!mManifest["asset"].has(asset_id.asString())) { LL_DEBUGS("import") << "Missing "<< asset_id.asString() << " asset data." << LL_ENDL; return; @@ -469,8 +481,7 @@ void FSFloaterImport::onClickBtnImport() LL_DEBUGS("import") << "mStartPosition is " << mStartPosition << LL_ENDL; // don't allow change during a long upload/import - getChild("pick_file")->setEnabled(FALSE); - getChild("import_file")->setEnabled(FALSE); + getChild("import_btn")->setEnabled(FALSE); getChild("do_not_attach")->setEnabled(FALSE); getChild("region_position")->setEnabled(FALSE); getChild("upload_asset")->setEnabled(FALSE); @@ -491,8 +502,7 @@ void FSFloaterImport::onClickBtnImport() LLBuyCurrencyHTML::openCurrencyFloater(LLTrans::getString("UploadingCosts", args), expected_upload_cost); // re-enable the controls - getChild("pick_file")->setEnabled(TRUE); - getChild("import_file")->setEnabled(TRUE); + getChild("import_btn")->setEnabled(TRUE); getChild("do_not_attach")->setEnabled(TRUE); getChild("region_position")->setEnabled(TRUE); getChild("upload_asset")->setEnabled(TRUE); @@ -586,7 +596,7 @@ void FSFloaterImport::onClickCheckBoxTempAsset() void FSFloaterImport::importPrims() { mObjectSize = 0; - LLSD& objectsd = mFile["linkset"][mLinkset]; + LLSD& objectsd = mManifest["linkset"][mLinkset]; for (LLSD::array_iterator iter = objectsd.beginArray(); iter != objectsd.endArray(); ++iter) @@ -599,8 +609,8 @@ void FSFloaterImport::importPrims() LL_WARNS("import") << "Object size is to large to link. " << mObjectSize << " is greater then max linking size of " << MAX_PRIMS_PER_OBJECT << LL_ENDL; } mRootPosition = mStartPosition; - LLUUID linkset_root_prim_uuid = mFile["linkset"][0][0].asUUID(); - LLSD& linkset_root_prim = mFile["prim"][linkset_root_prim_uuid.asString()]; + LLUUID linkset_root_prim_uuid = mManifest["linkset"][0][0].asUUID(); + LLSD& linkset_root_prim = mManifest["prim"][linkset_root_prim_uuid.asString()]; mLinksetPosition.setValue(linkset_root_prim["position"]); mCreatingActive = true; createPrim(); @@ -615,9 +625,9 @@ void FSFloaterImport::createPrim() status.setArg("[PRIMS]", llformat("%u", mObjectSize)); getChild("file_status_text")->setText(status.getString()); - LLUUID prim_uuid = mFile["linkset"][mLinkset][mObject].asUUID(); + LLUUID prim_uuid = mManifest["linkset"][mLinkset][mObject].asUUID(); LL_DEBUGS("import") << "Creating prim from " << prim_uuid.asString() << LL_ENDL; - LLSD& prim = mFile["prim"][prim_uuid.asString()]; + LLSD& prim = mManifest["prim"][prim_uuid.asString()]; gMessageSystem->newMessageFast(_PREHASH_ObjectAdd); gMessageSystem->nextBlockFast(_PREHASH_AgentData); @@ -680,6 +690,13 @@ void FSFloaterImport::createPrim() { position = mRootPosition; } + + if (mObjectCreatedCallback.connected()) + { + mObjectCreatedCallback.disconnect(); + } + mObjectCreatedCallback = gObjectList.setNewObjectCallback(boost::bind(&FSFloaterImport::processPrimCreated, this, _1)); + LL_DEBUGS("import") << "Creating prim at position " << position << LL_ENDL; gMessageSystem->addVector3Fast(_PREHASH_RayStart, position); gMessageSystem->addVector3Fast(_PREHASH_RayEnd, position); @@ -701,8 +718,8 @@ bool FSFloaterImport::processPrimCreated(LLViewerObject* object) LLSelectMgr::getInstance()->selectObjectAndFamily(object, TRUE); - LLUUID prim_uuid = mFile["linkset"][mLinkset][mObject].asUUID(); - LLSD& prim = mFile["prim"][prim_uuid.asString()]; + LLUUID prim_uuid = mManifest["linkset"][mLinkset][mObject].asUUID(); + LLSD& prim = mManifest["prim"][prim_uuid.asString()]; LL_DEBUGS("import") << "Processing prim " << prim_uuid.asString() << " for object " << object->getID().asString() << LL_ENDL; mPrimObjectMap[prim_uuid] = object->getID(); U32 object_local_id = object->getLocalID(); @@ -949,13 +966,13 @@ bool FSFloaterImport::processPrimCreated(LLViewerObject* object) content_iter != contentsd.endArray(); ++content_iter) { - if (!mFile["inventory"].has((*content_iter).asString())) + if (!mManifest["inventory"].has((*content_iter).asString())) { LL_WARNS("import") << "Inventory content " << (*content_iter) << " was not found in import file." << LL_ENDL; continue; } - LLSD& item_sd = mFile["inventory"][(*content_iter).asString()]; + LLSD& item_sd = mManifest["inventory"][(*content_iter).asString()]; LLUUID asset_id = item_sd["asset_id"].asUUID(); if (asset_id.isNull()) @@ -1046,8 +1063,8 @@ void FSFloaterImport::postLink() return; } - LLUUID root_prim_uuid = mFile["linkset"][mLinkset][0].asUUID(); - LLSD& root_prim = mFile["prim"][root_prim_uuid.asString()]; + LLUUID root_prim_uuid = mManifest["linkset"][mLinkset][0].asUUID(); + LLSD& root_prim = mManifest["prim"][root_prim_uuid.asString()]; if (root_prim.has("attachment_point") && !getChild("do_not_attach")->get()) { LL_DEBUGS("import") << "Attaching to " << root_prim["attachment_point"].asInteger() << LL_ENDL; @@ -1081,9 +1098,6 @@ void FSFloaterImport::postLink() LL_DEBUGS("import") << "Finished with " << mLinkset << " linksets and " << mObject << " prims in last linkset" << LL_ENDL; mObjectSelection = NULL; getChild("file_status_text")->setText(getString("file_status_done")); - - // re-enable the controls, but force to pick file due to need to re-create the upload queues. - getChild("pick_file")->setEnabled(TRUE); } else { @@ -1091,7 +1105,7 @@ void FSFloaterImport::postLink() mLinkset++; mObjectSize = 0; - LLSD& objectsd = mFile["linkset"][mLinkset]; + LLSD& objectsd = mManifest["linkset"][mLinkset]; for ( LLSD::array_iterator iter = objectsd.beginArray(); iter != objectsd.endArray(); @@ -1101,8 +1115,8 @@ void FSFloaterImport::postLink() } LL_DEBUGS("import") << "Next linkset Object size is " << mObjectSize << LL_ENDL; - LLUUID root_prim_uuid = mFile["linkset"][mLinkset][0].asUUID(); - LLSD& root_prim = mFile["prim"][root_prim_uuid.asString()]; + LLUUID root_prim_uuid = mManifest["linkset"][mLinkset][0].asUUID(); + LLSD& root_prim = mManifest["prim"][root_prim_uuid.asString()]; LLVector3 root_prim_location(root_prim["position"]); mRootPosition = mStartPosition + (root_prim_location - mLinksetPosition); createPrim(); @@ -1143,11 +1157,11 @@ void FSFloaterImport::setPrimPosition(U8 type, LLViewerObject* object, LLVector3 void FSFloaterImport::uploadAsset(LLUUID asset_id, LLUUID inventory_item) { - bool tempary = false; - std::vector asset_data = mFile["asset"][asset_id.asString()]["data"].asBinary(); - std::string name = mFile["asset"][asset_id.asString()]["name"].asString(); - std::string description = mFile["asset"][asset_id.asString()]["description"].asString(); - LLAssetType::EType asset_type = LLAssetType::lookup(mFile["asset"][asset_id.asString()]["type"].asString().c_str()); + bool temporary = false; + std::vector asset_data = mManifest["asset"][asset_id.asString()]["data"].asBinary(); + std::string name = mManifest["asset"][asset_id.asString()]["name"].asString(); + std::string description = mManifest["asset"][asset_id.asString()]["description"].asString(); + LLAssetType::EType asset_type = LLAssetType::lookup(mManifest["asset"][asset_id.asString()]["type"].asString().c_str()); std::string url; LLSD body = LLSD::emptyMap(); LLFolderType::EType folder_type = LLFolderType::assetTypeToFolderType(asset_type); @@ -1165,8 +1179,8 @@ void FSFloaterImport::uploadAsset(LLUUID asset_id, LLUUID inventory_item) { case LLAssetType::AT_TEXTURE: { - tempary = getChild("temp_asset")->get(); - if (tempary) + temporary = getChild("temp_asset")->get(); + if (temporary) { url = gAgent.getRegion()->getCapability("UploadBakedTexture"); } @@ -1180,8 +1194,8 @@ void FSFloaterImport::uploadAsset(LLUUID asset_id, LLUUID inventory_item) break; case LLAssetType::AT_SOUND: { - tempary = getChild("temp_asset")->get(); - if (tempary) + temporary = getChild("temp_asset")->get(); + if (temporary) { // skip upload due to no temp support for sound nextAsset(LLUUID::null, asset_id, asset_type); @@ -1296,8 +1310,8 @@ void FSFloaterImport::uploadAsset(LLUUID asset_id, LLUUID inventory_item) break; case LLAssetType::AT_ANIMATION: { - tempary = getChild("temp_asset")->get(); - if (tempary) + temporary = getChild("temp_asset")->get(); + if (temporary) { // no temp support, skip nextAsset(LLUUID::null, asset_id, asset_type); @@ -1421,7 +1435,7 @@ void FSFloaterImport::uploadAsset(LLUUID asset_id, LLUUID inventory_item) FSResourceData* fs_data = new FSResourceData; fs_data->uuid = asset_id; fs_data->user_data = this; - fs_data->tempary = tempary; + fs_data->temporary = temporary; fs_data->inventory_item = inventory_item; fs_data->wearable_type = wearable_type; fs_data->asset_type = asset_type; @@ -1453,9 +1467,9 @@ void FSFloaterImport::uploadAsset(LLUUID asset_id, LLUUID inventory_item) asset_type, FSFloaterImport::onAssetUploadComplete, data, - tempary, - tempary, - tempary); + temporary, + temporary, + temporary); LL_DEBUGS("import") << "Asset upload via AssetStorage of " << new_asset_id.asString() << " of " << asset_id.asString() << LL_ENDL; } } @@ -1485,7 +1499,7 @@ void FSFloaterImport::onAssetUploadComplete(const LLUUID& uuid, void* userdata, if (fs_data->inventory_item.isNull()) { - if (fs_data->tempary) + if (fs_data->temporary) { LLUUID item_id; item_id.generate(); @@ -1803,7 +1817,7 @@ void FSAssetResponder::uploadComplete(const LLSD& content) if (item_id.isNull()) { - if (fs_data->tempary) + if (fs_data->temporary) { if (result == "complete") { diff --git a/indra/newview/fsfloaterimport.h b/indra/newview/fsfloaterimport.h index 0e842278de..55bdb6a477 100644 --- a/indra/newview/fsfloaterimport.h +++ b/indra/newview/fsfloaterimport.h @@ -31,7 +31,6 @@ #include "llfloater.h" #include "llinventorymodel.h" #include "llresourcedata.h" -#include "llsingleton.h" #include "llselectmgr.h" #include "llviewerinventory.h" #include "llviewerobject.h" @@ -40,7 +39,7 @@ struct FSResourceData { LLUUID uuid; void* user_data; - bool tempary; + bool temporary; LLAssetType::EType asset_type; LLUUID inventory_item; LLWearableType::EType wearable_type; @@ -50,18 +49,17 @@ struct FSResourceData #include "llassetuploadresponders.h" -class FSFloaterImport : public LLFloater, public LLSingleton +class FSFloaterImport : public LLFloater { LOG_CLASS(FSFloaterImport); public: - FSFloaterImport(const LLSD &); + FSFloaterImport(const LLSD &filename); virtual ~FSFloaterImport(); virtual BOOL postBuild(); static void onIdle(void *user_data); - void onClickBtnPickFile(); - void onClickBtnImport(); + void onClickCheckBoxUploadAsset(); void onClickCheckBoxTempAsset(); bool processPrimCreated(LLViewerObject* object); @@ -80,6 +78,9 @@ private: } FSImportState; FSImportState mImportState; + void loadFile(); + void populateBackupInfo(); + void onClickBtnImport(); void createPrim(); void postLink(); void onIdle(); @@ -89,9 +90,9 @@ private: void searchInventory(LLUUID asset_id, LLViewerObject* object, std::string prim_name); void processPrim(LLSD& prim); - LLSD mFile; + LLSD mManifest; std::string mFileFullName; - std::string mFileName; + std::string mFilename; std::string mFilePath; bool mCreatingActive; FSFloaterImport* mInstance; @@ -106,7 +107,6 @@ private: S32 mLinksetSize; S32 mObjectSize; LLObjectSelectionHandle mObjectSelection; - bool mFileReady; uuid_vec_t mTextureQueue; U32 mTexturesTotal; uuid_vec_t mSoundQueue; @@ -117,6 +117,7 @@ private: U32 mAssetsTotal; std::map mAssetMap; BOOL mSavedSettingShowNewInventory; + boost::signals2::connection mObjectCreatedCallback; struct FSInventoryQueue { diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 83577ad051..7331350bff 100755 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -151,7 +151,7 @@ #include "floatermedialists.h" #include "fsareasearch.h" #include "fscontactsfloater.h" -#include "fsexport.h" +#include "fsfloaterexport.h" #include "fsfloaterblocklist.h" #include "fsfloatergroup.h" #include "fsfloatergrouptitles.h" diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index ca8c1116db..707f7b595f 100755 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -136,7 +136,7 @@ // [/RLVa:KB] #include "fslslbridge.h" #include "fscommon.h" -#include "fsexport.h" +#include "fsfloaterexport.h" #include "fscontactsfloater.h" // Display group list in contacts floater #include "fspose.h" // FIRE-4345: Undeform #include "fswsassetblacklist.h" @@ -10060,7 +10060,11 @@ class FSObjectExport : public view_listener_t { bool handleEvent( const LLSD& userdata) { - FSExport::getInstance()->exportSelection(); + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (objectp) + { + LLFloaterReg::showInstance("fs_export", LLSD(objectp->getID()), TAKE_FOCUS_YES); + } return true; } }; diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index cb5d5350d5..938c9a5d87 100755 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -640,6 +640,17 @@ class LLFileUploadBulk : public view_listener_t } }; +// Import Linkset +class FSFileImportLinkset : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + (new LLGenericLoadFilePicker(LLFilePicker::FFLOAD_IMPORT, boost::bind(&show_floater_callback, "fs_import", _1, LLFilePicker::FFLOAD_IMPORT)))->getFile(); + return TRUE; + } +}; +// + void upload_error(const std::string& error_message, const std::string& label, const std::string& filename, const LLSD& args) { llwarns << error_message << llendl; @@ -1588,6 +1599,7 @@ void init_menu_file() view_listener_t::addEnable(new LLFileEnableUploadModel(), "File.EnableUploadModel"); view_listener_t::addMenu(new LLMeshEnabled(), "File.MeshEnabled"); view_listener_t::addMenu(new LLMeshUploadVisible(), "File.VisibleUploadModel"); + view_listener_t::addCommit(new FSFileImportLinkset(), "File.ImportLinkset"); // Import linkset item // "File.SaveTexture" moved to llpanelmaininventory so that it can be properly handled. } diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 234d21ab7f..7237eb84dd 100755 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -226,6 +226,13 @@ void LLViewerObjectList::setUUIDAndLocal(const LLUUID &id, S32 gFullObjectUpdates = 0; S32 gTerseObjectUpdates = 0; +// Object Import +boost::signals2::connection LLViewerObjectList::setNewObjectCallback(new_object_callback_t cb) +{ + return mNewObjectSignal.connect(cb); +} +// + void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp, void** user_data, U32 i, @@ -267,10 +274,10 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp, // import support bool import_handled = false; bool own_full_perm = (objectp->permYouOwner() && objectp->permModify() && objectp->permTransfer() && objectp->permCopy()); - FSFloaterImport* floater_import = LLFloaterReg::getTypedInstance("fs_import"); - if (floater_import && own_full_perm) + if (own_full_perm) { - import_handled = floater_import->processPrimCreated(objectp); + import_handled = mNewObjectSignal(objectp); + mNewObjectSignal.disconnect_all_slots(); } if (!import_handled) { diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index 6518c25d09..f6ecf36c7a 100755 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -135,6 +135,13 @@ public: void removeFromMap(LLViewerObject *objectp); void clearDebugText(); + + // Import + typedef boost::function new_object_callback_t; + typedef boost::signals2::signal new_object_signal_t; + boost::signals2::connection setNewObjectCallback(new_object_callback_t cb); + new_object_signal_t mNewObjectSignal; + // //////////////////////////////////////////// // diff --git a/indra/newview/skins/default/xui/de/strings.xml b/indra/newview/skins/default/xui/de/strings.xml index c28027c760..aef3696cd2 100755 --- a/indra/newview/skins/default/xui/de/strings.xml +++ b/indra/newview/skins/default/xui/de/strings.xml @@ -5771,63 +5771,6 @@ Setzen Sie den Editorpfad in Anführungszeichen Umschalten des Präprozessors wird erst vollständig wirksam, nachdem der Editor geschlossen und neu geöffnet wurde. - - Beginne Export... - - - Export beendet. - - - Der Export von Mesh wird derzeit nicht unterstützt. Export abgebrochen. - - - Kein Export durchgeführt. Backup wurde nicht erstellt. - - - LLSelect-Knoten für [OBJECT] gefunden. Verwende Standard-Prim. - - - Berechtigungen für [OBJECT] unzureichend. Verwende Standard-Prim. - - - Berechtigungen für [ITEM] unzureichend - übersprungen... - - - Versuchter Export einer leeren Textur. - - - Lade Textur [ITEM]... - - - Textur [TEXTURE] erfolgreich gespeichert. - - - Speichere [ITEM]... - - - Fehler beim Laden von Textur [TEXTURE]. - - - Leere Textur [TEXTURE] empfangen. - - - [ITEM] wird aktuell nicht vom Exporter unterstützt - übersprungen... - - - [ITEM] konnte nicht geladen werden. (Status [STATUS] [EXT_STATUS]) - - - Fordere Asset [ITEM] an... - - - Fordere Inventar von [ITEM] erneut an. - - - Fordere Textur [ITEM] erneut an. - - - Asset [ITEM] konnte nicht geladen werden. - Die Anzeige der aktuellen Position in der Menüleiste wurde als Standard für Starlight-Oberflächendesigns deaktiviert. diff --git a/indra/newview/skins/default/xui/en/floater_fs_export.xml b/indra/newview/skins/default/xui/en/floater_fs_export.xml index f66a061573..771410d24d 100644 --- a/indra/newview/skins/default/xui/en/floater_fs_export.xml +++ b/indra/newview/skins/default/xui/en/floater_fs_export.xml @@ -1,32 +1,161 @@ - + + Backup [OBJECT] to Hard Disk... + + + Backup [OBJECT] working - Gathering information... + + + Backup [OBJECT] working - Fetching inventory... + + + Backup [OBJECT] working - Fetching assets... + + + Backup [OBJECT] working - Fetching textures... + + - - + top_pad="1"/> + top_pad="1" > @@ -128,11 +151,29 @@ follows="top|left" height="16" layout="topleft" - left_delta="130" + top_pad="1" + left_delta="15" enabled="false" name="temp_asset" label="Temp" > +