// #include "llviewerprecompiledheaders.h" #include "llfloaterexport.h" #include "lluictrlfactory.h" #include "llsdutil.h" #include "llsdserialize.h" #include "llselectmgr.h" #include "llscrolllistctrl.h" #include "llchat.h" #include "llfloaterchat.h" #include "llfilepicker.h" #include "llagent.h" #include "llvoavatar.h" #include "llvoavatardefines.h" #include "llimportobject.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" std::vector LLFloaterExport::instances; LLExportable::LLExportable(LLViewerObject* object, std::string name, std::map& primNameMap) : mObject(object), mType(EXPORTABLE_OBJECT), mPrimNameMap(&primNameMap) { } LLExportable::LLExportable(LLVOAvatar* avatar, EWearableType type, std::map& primNameMap) : mAvatar(avatar), mType(EXPORTABLE_WEARABLE), mWearableType(type), mPrimNameMap(&primNameMap) { } LLSD LLExportable::asLLSD() { if(mType == EXPORTABLE_OBJECT) { std::list prims; prims.push_back(mObject); LLViewerObject::child_list_t child_list = mObject->getChildren(); for (LLViewerObject::child_list_t::iterator i = child_list.begin(); i != child_list.end(); ++i) { LLViewerObject* child = *i; if(child->getPCode() < LL_PCODE_APP) { prims.push_back(child); } } LLSD llsd; std::list::iterator prim_iter = prims.begin(); std::list::iterator prims_end = prims.end(); for( ; prim_iter != prims_end; ++prim_iter) { LLViewerObject* object = (*prim_iter); LLSD prim_llsd; prim_llsd["type"] = "prim"; if (!object->isRoot()) { if(!object->getSubParent()->isAvatar()) { // Parent id prim_llsd["parent"] = llformat("%d", object->getSubParent()->getLocalID()); } } if(object->getSubParent()) { if(object->getSubParent()->isAvatar()) { // attachment-specific U8 state = object->getState(); S32 attachpt = ((S32)((((U8)state & AGENT_ATTACH_MASK) >> 4) | (((U8)state & ~AGENT_ATTACH_MASK) << 4))); prim_llsd["attach"] = attachpt; } } // Transforms prim_llsd["position"] = object->getPosition().getValue(); prim_llsd["scale"] = object->getScale().getValue(); prim_llsd["rotation"] = ll_sd_from_quaternion(object->getRotation()); // Flags prim_llsd["shadows"] = object->flagCastShadows(); prim_llsd["phantom"] = object->flagPhantom(); prim_llsd["physical"] = (BOOL)(object->mFlags & FLAGS_USE_PHYSICS); // Volume params LLVolumeParams params = object->getVolume()->getParams(); prim_llsd["volume"] = params.asLLSD(); // Extra params if (object->isFlexible()) { // Flexible LLFlexibleObjectData* flex = (LLFlexibleObjectData*)object->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE); prim_llsd["flexible"] = flex->asLLSD(); } if (object->getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT)) { // Light LLLightParams* light = (LLLightParams*)object->getParameterEntry(LLNetworkData::PARAMS_LIGHT); prim_llsd["light"] = light->asLLSD(); } if (object->getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT)) { // Sculpt LLSculptParams* sculpt = (LLSculptParams*)object->getParameterEntry(LLNetworkData::PARAMS_SCULPT); prim_llsd["sculpt"] = sculpt->asLLSD(); } // Textures LLSD te_llsd; U8 te_count = object->getNumTEs(); for (U8 i = 0; i < te_count; i++) { te_llsd.append(object->getTE(i)->asLLSD()); } prim_llsd["textures"] = te_llsd; std::map::iterator pos = (*mPrimNameMap).find(object->getLocalID()); if(pos != (*mPrimNameMap).end()) prim_llsd["name"] = (*mPrimNameMap)[object->getLocalID()]; llsd[llformat("%d", object->getLocalID())] = prim_llsd; } return llsd; } else if(mType == EXPORTABLE_WEARABLE) { LLSD llsd; // pointless map with single key/value LLSD item_sd; // map for wearable item_sd["type"] = "wearable"; S32 type_s32 = (S32)mWearableType; std::string wearable_name = LLWearable::typeToTypeName( mWearableType ); item_sd["name"] = mAvatar->getFullname() + " " + wearable_name; item_sd["wearabletype"] = type_s32; LLSD param_map; for( LLVisualParam* param = mAvatar->getFirstVisualParam(); param; param = mAvatar->getNextVisualParam() ) { LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param; if( (viewer_param->getWearableType() == type_s32) && (viewer_param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE) ) { param_map[llformat("%d", viewer_param->getID())] = viewer_param->getWeight(); } } item_sd["params"] = param_map; LLSD textures_map; for( S32 te = 0; te < LLVOAvatarDefines::TEX_NUM_INDICES; te++ ) { if( LLVOAvatar::getTEWearableType( (LLVOAvatarDefines::ETextureIndex)te ) == mWearableType ) { LLViewerImage* te_image = mAvatar->getTEImage( te ); if( te_image ) { textures_map[llformat("%d", te)] = te_image->getID(); } } } item_sd["textures"] = textures_map; // Generate a unique ID for it... LLUUID myid; myid.generate(); llsd[myid.asString()] = item_sd; return llsd; } return LLSD(); } LLFloaterExport::LLFloaterExport() : LLFloater() { mSelection = LLSelectMgr::getInstance()->getSelection(); LLUICtrlFactory::getInstance()->buildFloater(this, "floater_export.xml"); LLFloaterExport::instances.push_back(this); } LLFloaterExport::~LLFloaterExport() { std::vector::iterator pos = std::find(LLFloaterExport::instances.begin(), LLFloaterExport::instances.end(), this); if(pos != LLFloaterExport::instances.end()) { LLFloaterExport::instances.erase(pos); } } BOOL LLFloaterExport::postBuild(void) { if(!mSelection) return TRUE; if(mSelection->getRootObjectCount() < 1) return TRUE; // New stuff: Populate prim name map for (LLObjectSelection::valid_iterator iter = mSelection->valid_begin(); iter != mSelection->valid_end(); iter++) { LLSelectNode* nodep = *iter; LLViewerObject* objectp = nodep->getObject(); U32 localid = objectp->getLocalID(); std::string name = nodep->mName; mPrimNameMap[localid] = name; } // Older stuff LLScrollListCtrl* list = getChild("export_list"); std::map avatars; for (LLObjectSelection::valid_root_iterator iter = mSelection->valid_root_begin(); iter != mSelection->valid_root_end(); iter++) { LLSelectNode* nodep = *iter; LLViewerObject* objectp = nodep->getObject(); std::string objectp_id = llformat("%d", objectp->getLocalID()); if(list->getItemIndex(objectp->getID()) == -1) { bool is_attachment = false; bool is_root = true; LLViewerObject* parentp = objectp->getSubParent(); if(parentp) { if(!parentp->isAvatar()) { // parent is a prim I guess is_root = false; } else { // parent is an avatar is_attachment = true; if(!avatars[parentp]) avatars[parentp] = true; } } bool is_prim = true; if(objectp->getPCode() >= LL_PCODE_APP) { is_prim = false; } bool is_avatar = objectp->isAvatar(); if(is_root && is_prim) { LLSD element; element["id"] = objectp->getID(); LLSD& check_column = element["columns"][LIST_CHECKED]; check_column["column"] = "checked"; check_column["type"] = "checkbox"; check_column["value"] = true; LLSD& type_column = element["columns"][LIST_TYPE]; type_column["column"] = "type"; type_column["type"] = "icon"; type_column["value"] = "inv_item_object.tga"; LLSD& name_column = element["columns"][LIST_NAME]; name_column["column"] = "name"; if(is_attachment) name_column["value"] = nodep->mName + " (worn on " + utf8str_tolower(objectp->getAttachmentPointName()) + ")"; else name_column["value"] = nodep->mName; LLSD& avatarid_column = element["columns"][LIST_AVATARID]; avatarid_column["column"] = "avatarid"; if(is_attachment) avatarid_column["value"] = parentp->getID(); else avatarid_column["value"] = LLUUID::null; LLExportable* exportable = new LLExportable(objectp, nodep->mName, mPrimNameMap); mExportables[objectp->getID()] = exportable->asLLSD(); list->addElement(element, ADD_BOTTOM); addToPrimList(objectp); } else if(is_avatar) { if(!avatars[objectp]) { avatars[objectp] = true; } } } } std::map::iterator avatar_iter = avatars.begin(); std::map::iterator avatars_end = avatars.end(); for( ; avatar_iter != avatars_end; avatar_iter++) { LLViewerObject* avatar = (*avatar_iter).first; addAvatarStuff((LLVOAvatar*)avatar); } updateNamesProgress(); childSetAction("select_all_btn", onClickSelectAll, this); childSetAction("select_objects_btn", onClickSelectObjects, this); childSetAction("select_wearables_btn", onClickSelectWearables, this); childSetAction("save_as_btn", onClickSaveAs, this); childSetAction("make_copy_btn", onClickMakeCopy, this); return TRUE; } void LLFloaterExport::addAvatarStuff(LLVOAvatar* avatarp) { LLScrollListCtrl* list = getChild("export_list"); for( S32 type = WT_SHAPE; type < WT_COUNT; type++ ) { // guess whether this wearable actually exists // by checking whether it has any textures that aren't default bool exists = false; if(type == WT_SHAPE) { exists = true; } else { for( S32 te = 0; te < LLVOAvatarDefines::TEX_NUM_INDICES; te++ ) { if( (S32)LLVOAvatar::getTEWearableType( (LLVOAvatarDefines::ETextureIndex)te ) == type ) { LLViewerImage* te_image = avatarp->getTEImage( te ); if( te_image->getID() != IMG_DEFAULT_AVATAR) { exists = true; break; } } } } if(exists) { std::string wearable_name = LLWearable::typeToTypeName( (EWearableType)type ); std::string name = avatarp->getFullname() + " " + wearable_name; LLUUID myid; myid.generate(); LLSD element; element["id"] = myid; LLSD& check_column = element["columns"][LIST_CHECKED]; check_column["column"] = "checked"; check_column["type"] = "checkbox"; check_column["value"] = false; LLSD& type_column = element["columns"][LIST_TYPE]; type_column["column"] = "type"; type_column["type"] = "icon"; type_column["value"] = "inv_item_" + wearable_name + ".tga"; LLSD& name_column = element["columns"][LIST_NAME]; name_column["column"] = "name"; name_column["value"] = name; LLSD& avatarid_column = element["columns"][LIST_AVATARID]; avatarid_column["column"] = "avatarid"; avatarid_column["value"] = avatarp->getID(); LLExportable* exportable = new LLExportable(avatarp, (EWearableType)type, mPrimNameMap); mExportables[myid] = exportable->asLLSD(); list->addElement(element, ADD_BOTTOM); } } // Add attachments LLViewerObject::child_list_t child_list = avatarp->getChildren(); for (LLViewerObject::child_list_t::iterator i = child_list.begin(); i != child_list.end(); ++i) { LLViewerObject* childp = *i; if(list->getItemIndex(childp->getID()) == -1) { LLSD element; element["id"] = childp->getID(); LLSD& check_column = element["columns"][LIST_CHECKED]; check_column["column"] = "checked"; check_column["type"] = "checkbox"; check_column["value"] = false; LLSD& type_column = element["columns"][LIST_TYPE]; type_column["column"] = "type"; type_column["type"] = "icon"; type_column["value"] = "inv_item_object.tga"; LLSD& name_column = element["columns"][LIST_NAME]; name_column["column"] = "name"; name_column["value"] = "Object (worn on " + utf8str_tolower(childp->getAttachmentPointName()) + ")"; LLSD& avatarid_column = element["columns"][LIST_AVATARID]; avatarid_column["column"] = "avatarid"; avatarid_column["value"] = avatarp->getID(); LLExportable* exportable = new LLExportable(childp, "Object", mPrimNameMap); mExportables[childp->getID()] = exportable->asLLSD(); list->addElement(element, ADD_BOTTOM); addToPrimList(childp); //LLSelectMgr::getInstance()->selectObjectAndFamily(childp, false); //LLSelectMgr::getInstance()->deselectObjectAndFamily(childp, true, true); LLViewerObject::child_list_t select_list = childp->getChildren(); LLViewerObject::child_list_t::iterator select_iter; int block_counter; gMessageSystem->newMessageFast(_PREHASH_ObjectSelect); gMessageSystem->nextBlockFast(_PREHASH_AgentData); gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); gMessageSystem->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); gMessageSystem->nextBlockFast(_PREHASH_ObjectData); gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, childp->getLocalID()); block_counter = 0; for (select_iter = select_list.begin(); select_iter != select_list.end(); ++select_iter) { block_counter++; if(block_counter >= 254) { // start a new message gMessageSystem->sendReliable(childp->getRegion()->getHost()); gMessageSystem->newMessageFast(_PREHASH_ObjectSelect); gMessageSystem->nextBlockFast(_PREHASH_AgentData); gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); gMessageSystem->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); } gMessageSystem->nextBlockFast(_PREHASH_ObjectData); gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, (*select_iter)->getLocalID()); } gMessageSystem->sendReliable(childp->getRegion()->getHost()); gMessageSystem->newMessageFast(_PREHASH_ObjectDeselect); gMessageSystem->nextBlockFast(_PREHASH_AgentData); gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); gMessageSystem->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); gMessageSystem->nextBlockFast(_PREHASH_ObjectData); gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, childp->getLocalID()); block_counter = 0; for (select_iter = select_list.begin(); select_iter != select_list.end(); ++select_iter) { block_counter++; if(block_counter >= 254) { // start a new message gMessageSystem->sendReliable(childp->getRegion()->getHost()); gMessageSystem->newMessageFast(_PREHASH_ObjectDeselect); gMessageSystem->nextBlockFast(_PREHASH_AgentData); gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); gMessageSystem->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); } gMessageSystem->nextBlockFast(_PREHASH_ObjectData); gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, (*select_iter)->getLocalID()); } gMessageSystem->sendReliable(childp->getRegion()->getHost()); } } } //static void LLFloaterExport::onClickSelectAll(void* user_data) { LLFloaterExport* floater = (LLFloaterExport*)user_data; LLScrollListCtrl* list = floater->getChild("export_list"); std::vector items = list->getAllData(); std::vector::iterator item_iter = items.begin(); std::vector::iterator items_end = items.end(); bool new_value = !((*item_iter)->getColumn(LIST_CHECKED)->getValue()); for( ; item_iter != items_end; ++item_iter) { LLScrollListItem* item = (*item_iter); item->getColumn(LIST_CHECKED)->setValue(new_value); } } //static void LLFloaterExport::onClickSelectObjects(void* user_data) { LLFloaterExport* floater = (LLFloaterExport*)user_data; LLScrollListCtrl* list = floater->getChild("export_list"); std::vector items = list->getAllData(); std::vector::iterator item_iter = items.begin(); std::vector::iterator items_end = items.end(); bool new_value = false; for( ; item_iter != items_end; ++item_iter) { if(((*item_iter)->getColumn(LIST_TYPE)->getValue()).asString() == "inv_item_object.tga") { new_value = !((*item_iter)->getColumn(LIST_CHECKED)->getValue()); break; } } for(item_iter = items.begin(); item_iter != items_end; ++item_iter) { if(((*item_iter)->getColumn(LIST_TYPE)->getValue()).asString() == "inv_item_object.tga") { LLScrollListItem* item = (*item_iter); item->getColumn(LIST_CHECKED)->setValue(new_value); } } } //static void LLFloaterExport::onClickSelectWearables(void* user_data) { LLFloaterExport* floater = (LLFloaterExport*)user_data; LLScrollListCtrl* list = floater->getChild("export_list"); std::vector items = list->getAllData(); std::vector::iterator item_iter = items.begin(); std::vector::iterator items_end = items.end(); bool new_value = false; for( ; item_iter != items_end; ++item_iter) { if(((*item_iter)->getColumn(LIST_TYPE)->getValue()).asString() != "inv_item_object.tga") { new_value = !((*item_iter)->getColumn(LIST_CHECKED)->getValue()); break; } } for(item_iter = items.begin(); item_iter != items_end; ++item_iter) { if(((*item_iter)->getColumn(LIST_TYPE)->getValue()).asString() != "inv_item_object.tga") { LLScrollListItem* item = (*item_iter); item->getColumn(LIST_CHECKED)->setValue(new_value); } } } LLSD LLFloaterExport::getLLSD() { LLScrollListCtrl* list = getChild("export_list"); std::vector items = list->getAllData(); LLSD sd; std::vector::iterator item_iter = items.begin(); std::vector::iterator items_end = items.end(); for( ; item_iter != items_end; ++item_iter) { LLScrollListItem* item = (*item_iter); if(item->getColumn(LIST_CHECKED)->getValue()) { LLSD item_sd = mExportables[item->getUUID()]; LLSD::map_iterator map_iter = item_sd.beginMap(); LLSD::map_iterator map_end = item_sd.endMap(); for( ; map_iter != map_end; ++map_iter) { std::string key((*map_iter).first); LLSD data = (*map_iter).second; // copy it... sd[key] = data; } } } return sd; } //static void LLFloaterExport::onClickSaveAs(void* user_data) { LLFloaterExport* floater = (LLFloaterExport*)user_data; LLSD sd = floater->getLLSD(); if(sd.size()) { std::string default_filename = "untitled"; // set correct names within llsd LLSD::map_iterator map_iter = sd.beginMap(); LLSD::map_iterator map_end = sd.endMap(); for( ; map_iter != map_end; ++map_iter) { std::istringstream keystr((*map_iter).first); U32 key; keystr >> key; LLSD item = (*map_iter).second; if(item["type"].asString() == "prim") { std::string name = floater->mPrimNameMap[key]; item["name"] = name; // I don't understand C++ :( sd[(*map_iter).first] = item; } } // count the number of selected items LLScrollListCtrl* list = floater->getChild("export_list"); std::vector items = list->getAllData(); int item_count = 0; LLUUID avatarid = (*(items.begin()))->getColumn(LIST_AVATARID)->getValue().asUUID(); bool all_same_avatarid = true; std::vector::iterator item_iter = items.begin(); std::vector::iterator items_end = items.end(); for( ; item_iter != items_end; ++item_iter) { LLScrollListItem* item = (*item_iter); if(item->getColumn(LIST_CHECKED)->getValue()) { item_count++; if(item->getColumn(LIST_AVATARID)->getValue().asUUID() != avatarid) { all_same_avatarid = false; } } } if(item_count == 1) { // Exporting one item? Use its name for the filename. // But make sure it's a root! LLSD target = (*(sd.beginMap())).second; if(target.has("parent")) { std::string parentid = target["parent"].asString(); target = sd[parentid]; } if(target.has("name")) { if(target["name"].asString().length() > 0) { default_filename = target["name"].asString(); } } } else { // Multiple items? // If they're all part of the same avatar, use the avatar's name as filename. if(all_same_avatarid) { std::string fullname; if(gCacheName->getFullName(avatarid, fullname)) { default_filename = fullname; } } } LLFilePicker& file_picker = LLFilePicker::instance(); if(file_picker.getSaveFile( LLFilePicker::FFSAVE_XML, LLDir::getScrubbedFileName(default_filename + ".xml"))) { std::string file_name = file_picker.getFirstFile(); llofstream export_file(file_name); LLSDSerialize::toPrettyXML(sd, export_file); export_file.close(); std::string msg = "Saved "; msg.append(file_name); LLChat chat(msg); LLFloaterChat::addChat(chat); } } else { std::string msg = "No exportable items selected"; LLChat chat(msg); LLFloaterChat::addChat(chat); return; } floater->close(); } //static void LLFloaterExport::onClickMakeCopy(void* user_data) { LLFloaterExport* floater = (LLFloaterExport*)user_data; LLSD sd = floater->getLLSD(); if(sd.size()) { LLXmlImport::import(new LLXmlImportOptions(sd)); } else { std::string msg = "No copyable items selected"; LLChat chat(msg); LLFloaterChat::addChat(chat); return; } // I guess close the floater because only one import is allowed at once anyway floater->close(); } void LLFloaterExport::addToPrimList(LLViewerObject* object) { mPrimList.push_back(object->getLocalID()); LLViewerObject::child_list_t child_list = object->getChildren(); for (LLViewerObject::child_list_t::iterator i = child_list.begin(); i != child_list.end(); ++i) { LLViewerObject* child = *i; if(child->getPCode() < LL_PCODE_APP) { mPrimList.push_back(child->getLocalID()); } } } void LLFloaterExport::updateNamesProgress() { childSetText("names_progress_text", llformat("Names retrieved: %d of %d", mPrimNameMap.size(), mPrimList.size())); } void LLFloaterExport::receivePrimName(LLViewerObject* object, std::string name) { LLUUID fullid = object->getID(); U32 localid = object->getLocalID(); if(std::find(mPrimList.begin(), mPrimList.end(), localid) != mPrimList.end()) { mPrimNameMap[localid] = name; LLScrollListCtrl* list = getChild("export_list"); S32 item_index = list->getItemIndex(fullid); if(item_index != -1) { std::vector items = list->getAllData(); std::vector::iterator iter = items.begin(); std::vector::iterator end = items.end(); for( ; iter != end; ++iter) { if((*iter)->getUUID() == fullid) { (*iter)->getColumn(LIST_NAME)->setValue(name + " (worn on " + utf8str_tolower(object->getAttachmentPointName()) + ")"); break; } } } updateNamesProgress(); } } // static void LLFloaterExport::receiveObjectProperties(LLUUID fullid, std::string name, std::string desc) { LLViewerObject* object = gObjectList.findObject(fullid); std::vector::iterator iter = LLFloaterExport::instances.begin(); std::vector::iterator end = LLFloaterExport::instances.end(); for( ; iter != end; ++iter) { (*iter)->receivePrimName(object, name); } } //