// #include "llviewerprecompiledheaders.h" #include "llinventorybackup.h" #include "llinventorymodel.h" #include "llviewerinventory.h" #include "statemachine/aifilepicker.h" #include "statemachine/aidirpicker.h" #include "llviewertexturelist.h" // gTextureList #include "llagent.h" // gAgent #include "llviewerwindow.h" // gViewerWindow #include "llfloater.h" #include "lluictrlfactory.h" #include "llscrolllistctrl.h" #include "llimagetga.h" #include "llnotificationsutil.h" std::list LLFloaterInventoryBackup::sInstances; LLInventoryBackupOrder::LLInventoryBackupOrder() { // My personal defaults based on what is assumed to not work mDownloadTextures = true; mDownloadSounds = true; mDownloadCallingCards = false; mDownloadLandmarks = true; mDownloadScripts = true; mDownloadWearables = true; mDownloadObjects = false; mDownloadNotecards = true; mDownloadAnimations = true; mDownloadGestures = true; //mDownloadOthers = true; } LLFloaterInventoryBackupSettings::LLFloaterInventoryBackupSettings(LLInventoryBackupOrder* order) : LLFloater(), mOrder(order) { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inventory_backup_settings.xml"); } LLFloaterInventoryBackupSettings::~LLFloaterInventoryBackupSettings() { } BOOL LLFloaterInventoryBackupSettings::postBuild(void) { childSetValue("chk_textures", mOrder->mDownloadTextures); childSetValue("chk_sounds", mOrder->mDownloadSounds); childSetValue("chk_callingcards", mOrder->mDownloadCallingCards); childSetValue("chk_landmarks", mOrder->mDownloadLandmarks); childSetValue("chk_scripts", mOrder->mDownloadScripts); childSetValue("chk_wearables", mOrder->mDownloadWearables); childSetValue("chk_objects", mOrder->mDownloadObjects); childSetValue("chk_notecards", mOrder->mDownloadNotecards); childSetValue("chk_animations", mOrder->mDownloadAnimations); childSetValue("chk_gestures", mOrder->mDownloadGestures); //childSetValue("chk_others", mOrder->mDownloadOthers); childSetAction("next_btn", LLFloaterInventoryBackupSettings::onClickNext, this); return TRUE; } // static void LLFloaterInventoryBackupSettings::onClickNext(void* userdata) { LLFloaterInventoryBackupSettings* floater = (LLFloaterInventoryBackupSettings*)userdata; LLInventoryBackupOrder* order = floater->mOrder; // Apply changes to filters order->mDownloadAnimations = floater->childGetValue("chk_animations"); order->mDownloadCallingCards = floater->childGetValue("chk_callingcards"); order->mDownloadGestures = floater->childGetValue("chk_gestures"); order->mDownloadLandmarks = floater->childGetValue("chk_landmarks"); order->mDownloadNotecards = floater->childGetValue("chk_notecards"); order->mDownloadObjects = floater->childGetValue("chk_objects"); //order->mDownloadOthers = floater->childGetValue("chk_others"); order->mDownloadScripts = floater->childGetValue("chk_scripts"); order->mDownloadSounds = floater->childGetValue("chk_sounds"); order->mDownloadTextures = floater->childGetValue("chk_textures"); order->mDownloadWearables = floater->childGetValue("chk_wearables"); // Make filters std::map type_remove; type_remove[LLAssetType::AT_ANIMATION] = !order->mDownloadAnimations; type_remove[LLAssetType::AT_BODYPART] = !order->mDownloadWearables; type_remove[LLAssetType::AT_CALLINGCARD] = !order->mDownloadCallingCards; type_remove[LLAssetType::AT_CLOTHING] = !order->mDownloadWearables; type_remove[LLAssetType::AT_GESTURE] = !order->mDownloadGestures; type_remove[LLAssetType::AT_IMAGE_JPEG] = !order->mDownloadTextures; type_remove[LLAssetType::AT_IMAGE_TGA] = !order->mDownloadTextures; type_remove[LLAssetType::AT_LANDMARK] = !order->mDownloadLandmarks; type_remove[LLAssetType::AT_LSL_TEXT] = !order->mDownloadScripts; type_remove[LLAssetType::AT_NOTECARD] = !order->mDownloadNotecards; type_remove[LLAssetType::AT_OBJECT] = !order->mDownloadObjects; type_remove[LLAssetType::AT_SCRIPT] = !order->mDownloadScripts; type_remove[LLAssetType::AT_SOUND] = !order->mDownloadSounds; type_remove[LLAssetType::AT_SOUND_WAV] = !order->mDownloadSounds; type_remove[LLAssetType::AT_TEXTURE] = !order->mDownloadTextures; type_remove[LLAssetType::AT_TEXTURE_TGA] = !order->mDownloadTextures; // Apply filters std::vector::iterator item_iter = order->mItems.begin(); for( ; item_iter != order->mItems.end(); ) { if(type_remove[(*item_iter)->getType()]) order->mItems.erase(item_iter); else ++item_iter; } if(order->mItems.size() < 1) { LLSD args; args["ERROR_MESSAGE"] = "No items passed the filter \\o/"; LLNotificationsUtil::add("ErrorMessage", args); return; } // Get dir name AIDirPicker* dirpicker = new AIDirPicker("New Folder"); dirpicker->run(boost::bind(&LLFloaterInventoryBackupSettings::onClickNext_continued, userdata, dirpicker)); } // static void LLFloaterInventoryBackupSettings::onClickNext_continued(void* userdata, AIDirPicker* dirpicker) { LLFloaterInventoryBackupSettings* floater = (LLFloaterInventoryBackupSettings*)userdata; LLInventoryBackupOrder* order = floater->mOrder; if (!dirpicker->hasDirname()) { floater->close(); return; } std::string dirname = dirpicker->getDirname(); // Make local directory tree LLFile::mkdir(dirname); std::vector::iterator _cat_iter = order->mCats.begin(); std::vector::iterator _cat_end = order->mCats.end(); for( ; _cat_iter != _cat_end; ++_cat_iter) { std::string path = dirname + OS_SEP + LLInventoryBackup::getPath(*_cat_iter, order->mCats); LLFile::mkdir(path); } // Go go backup floater LLFloaterInventoryBackup* backup_floater = new LLFloaterInventoryBackup(dirname, order->mCats, order->mItems); backup_floater->center(); // Close myself floater->close(); } // static bool LLInventoryBackup::itemIsFolder(LLInventoryItem* item) { return ((item->getInventoryType() == LLInventoryType::IT_CATEGORY) || (item->getInventoryType() == LLInventoryType::IT_ROOT_CATEGORY)); } // static ESaveFilter LLInventoryBackup::getSaveFilter(LLInventoryItem* item) { LLAssetType::EType type = item->getType(); LLWearableType::EType wear = (LLWearableType::EType)(item->getFlags() & 0xFF); switch(type) { case LLAssetType::AT_TEXTURE: return FFSAVE_TGA; case LLAssetType::AT_SOUND: return FFSAVE_OGG; case LLAssetType::AT_SCRIPT: case LLAssetType::AT_LSL_TEXT: return FFSAVE_LSL; case LLAssetType::AT_ANIMATION: return FFSAVE_ANIMATN; case LLAssetType::AT_GESTURE: return FFSAVE_GESTURE; case LLAssetType::AT_NOTECARD: return FFSAVE_NOTECARD; case LLAssetType::AT_LANDMARK: return FFSAVE_LANDMARK; case LLAssetType::AT_BODYPART: case LLAssetType::AT_CLOTHING: switch(wear) { case LLWearableType::WT_EYES: return FFSAVE_EYES; case LLWearableType::WT_GLOVES: return FFSAVE_GLOVES; case LLWearableType::WT_HAIR: return FFSAVE_HAIR; case LLWearableType::WT_JACKET: return FFSAVE_JACKET; case LLWearableType::WT_PANTS: return FFSAVE_PANTS; case LLWearableType::WT_SHAPE: return FFSAVE_SHAPE; case LLWearableType::WT_SHIRT: return FFSAVE_SHIRT; case LLWearableType::WT_SHOES: return FFSAVE_SHOES; case LLWearableType::WT_SKIN: return FFSAVE_SKIN; case LLWearableType::WT_SKIRT: return FFSAVE_SKIRT; case LLWearableType::WT_SOCKS: return FFSAVE_SOCKS; case LLWearableType::WT_UNDERPANTS: return FFSAVE_UNDERPANTS; case LLWearableType::WT_UNDERSHIRT: return FFSAVE_UNDERSHIRT; case LLWearableType::WT_PHYSICS: return FFSAVE_PHYSICS; default: return FFSAVE_ALL; } default: return FFSAVE_ALL; } } // static std::string LLInventoryBackup::getExtension(LLInventoryItem* item) { LLAssetType::EType type = item->getType(); LLWearableType::EType wear = (LLWearableType::EType)(item->getFlags() & 0xFF); std::string scratch; switch(type) { case LLAssetType::AT_TEXTURE: return ".tga"; case LLAssetType::AT_SOUND: return ".ogg"; case LLAssetType::AT_SCRIPT: case LLAssetType::AT_LSL_TEXT: return ".lsl"; case LLAssetType::AT_ANIMATION: return ".animatn"; case LLAssetType::AT_GESTURE: return ".gesture"; case LLAssetType::AT_NOTECARD: return ".notecard"; case LLAssetType::AT_LANDMARK: return ".landmark"; case LLAssetType::AT_BODYPART: case LLAssetType::AT_CLOTHING: scratch = LLWearableType::getTypeName(wear); if(scratch == "invalid") { if(type == LLAssetType::AT_BODYPART) scratch = "bodypart"; else scratch = "clothing"; } return "." + scratch; default: return ""; } } // static std::string LLInventoryBackup::getUniqueFilename(std::string filename, std::string extension) { if(LLFile::isfile( (filename + extension).c_str() )) { int i = 1; while(LLFile::isfile( (filename + llformat(" %d", i) + extension).c_str() )) { i++; } return filename + llformat(" %d", i) + extension; } return filename + extension; } // static std::string LLInventoryBackup::getUniqueDirname(std::string dirname) { if(LLFile::isdir(dirname.c_str())) { int i = 1; while(LLFile::isdir( (dirname + llformat(" %d", i)).c_str() )) { i++; } return dirname + llformat(" %d", i); } return dirname; } // static void LLInventoryBackup::download(LLInventoryItem* item, LLFloater* floater, loaded_callback_func onImage, LLGetAssetCallback onAsset) { LLInventoryBackup::callbackdata* userdata = new LLInventoryBackup::callbackdata(); userdata->floater = floater; userdata->item = item; LLViewerFetchedTexture* imagep; switch(item->getType()) { case LLAssetType::AT_TEXTURE: imagep = LLViewerTextureManager::getFetchedTexture(item->getAssetUUID(), MIPMAP_TRUE, LLViewerTexture::BOOST_UI); imagep->setLoadedCallback( onImage, 0, TRUE, FALSE, userdata, NULL ); // was setLoadedCallbackNoAuth break; case LLAssetType::AT_NOTECARD: case LLAssetType::AT_SCRIPT: case LLAssetType::AT_LSL_TEXT: // normal script download case LLAssetType::AT_LSL_BYTECODE: gAssetStorage->getInvItemAsset(LLHost::invalid, gAgent.getID(), gAgent.getSessionID(), item->getPermissions().getOwner(), LLUUID::null, item->getUUID(), item->getAssetUUID(), item->getType(), onAsset, userdata, // user_data TRUE); break; case LLAssetType::AT_SOUND: case LLAssetType::AT_CLOTHING: case LLAssetType::AT_BODYPART: case LLAssetType::AT_ANIMATION: case LLAssetType::AT_GESTURE: default: gAssetStorage->getAssetData(item->getAssetUUID(), item->getType(), onAsset, userdata, TRUE); break; } } // static void LLInventoryBackup::imageCallback(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) { if(final) { LLInventoryBackup::callbackdata* data = static_cast(userdata); LLInventoryItem* item = data->item; if(!success) { LLSD args; args["ERROR_MESSAGE"] = "Download didn't work on " + item->getName() + "."; LLNotificationsUtil::add("ErrorMessage", args); return; } AIFilePicker* filepicker = AIFilePicker::create(); filepicker->open(LLDir::getScrubbedFileName(item->getName()), getSaveFilter(item)); filepicker->run(boost::bind(&LLInventoryBackup::imageCallback_continued, src, filepicker)); } else { src_vi->setBoostLevel(LLViewerTexture::BOOST_UI); } } void LLInventoryBackup::imageCallback_continued(LLImageRaw* src, AIFilePicker* filepicker) { if (!filepicker->hasFilename()) return; std::string filename = filepicker->getFilename(); LLPointer image_tga = new LLImageTGA; if( !image_tga->encode( src ) ) { LLSD args; args["ERROR_MESSAGE"] = "Couldn't encode file."; LLNotificationsUtil::add("ErrorMessage", args); } else if( !image_tga->save( filename ) ) { LLSD args; args["ERROR_MESSAGE"] = "Couldn't write file."; LLNotificationsUtil::add("ErrorMessage", args); } } // static void LLInventoryBackup::assetCallback(LLVFS *vfs, const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status) { LLInventoryBackup::callbackdata* data = static_cast(user_data); LLInventoryItem* item = data->item; if(status != 0) { LLSD args; args["ERROR_MESSAGE"] = "Download didn't work on " + item->getName() + "."; LLNotificationsUtil::add("ErrorMessage", args); return; } // Todo: this doesn't work for static vfs shit LLVFile file(vfs, asset_uuid, type, LLVFile::READ); S32 size = file.getSize(); char* buffer = new char[size]; // Deleted in assetCallback_continued. if (buffer == NULL) { llerrs << "Memory Allocation Failed" << llendl; return; } file.read((U8*)buffer, size); // Write it back out... AIFilePicker* filepicker = AIFilePicker::create(); filepicker->open(LLDir::getScrubbedFileName(item->getName()), getSaveFilter(item)); filepicker->run(boost::bind(&LLInventoryBackup::assetCallback_continued, buffer, size, filepicker)); } // static void LLInventoryBackup::assetCallback_continued(char* buffer, S32 size, AIFilePicker* filepicker) { if (filepicker->hasFilename()) { std::string filename = filepicker->getFilename(); std::ofstream export_file(filename.c_str(), std::ofstream::binary); export_file.write(buffer, size); export_file.close(); } delete [] buffer; } // static void LLInventoryBackup::climb(LLInventoryCategory* cat, std::vector& cats, std::vector& items) { LLInventoryModel* model = &gInventory; // Add this category cats.push_back(cat); LLInventoryModel::cat_array_t *direct_cats; LLInventoryModel::item_array_t *direct_items; model->getDirectDescendentsOf(cat->getUUID(), direct_cats, direct_items); // Add items LLInventoryModel::item_array_t::iterator item_iter = direct_items->begin(); LLInventoryModel::item_array_t::iterator item_end = direct_items->end(); for( ; item_iter != item_end; ++item_iter) { items.push_back(*item_iter); } // Do subcategories LLInventoryModel::cat_array_t::iterator cat_iter = direct_cats->begin(); LLInventoryModel::cat_array_t::iterator cat_end = direct_cats->end(); for( ; cat_iter != cat_end; ++cat_iter) { climb(*cat_iter, cats, items); } } // static std::string LLInventoryBackup::getPath(LLInventoryCategory* cat, std::vector cats) { LLInventoryModel* model = &gInventory; std::string path = LLDir::getScrubbedFileName(cat->getName()); LLInventoryCategory* parent = model->getCategory(cat->getParentUUID()); while(parent && (std::find(cats.begin(), cats.end(), parent) != cats.end())) { path = LLDir::getScrubbedFileName(parent->getName()) + OS_SEP + path; parent = model->getCategory(parent->getParentUUID()); } return path; } // static void LLInventoryBackup::save(LLFolderView* folder) { LLInventoryModel* model = &gInventory; std::set selected_items = folder->getSelectionList(); if(selected_items.size() < 1) { // No items selected? Omg return; } else if(selected_items.size() == 1) { // One item. See if it's a folder LLUUID id = *(selected_items.begin()); LLInventoryItem* item = model->getItem(id); if(item) { if(!itemIsFolder(item)) { // Single item, save it now LLInventoryBackup::download((LLViewerInventoryItem*)item, NULL, imageCallback, assetCallback); return; } } } // We got here? We need to save multiple items or at least make a folder std::vector cats; std::vector items; // Make complete lists of child categories and items std::set::iterator sel_iter = selected_items.begin(); std::set::iterator sel_end = selected_items.end(); for( ; sel_iter != sel_end; ++sel_iter) { LLInventoryCategory* cat = model->getCategory(*sel_iter); if(cat) { climb(cat, cats, items); } } // And what about items inside a folder that wasn't selected? // I guess I will just add selected items, so long as they aren't already added for(sel_iter = selected_items.begin(); sel_iter != sel_end; ++sel_iter) { LLInventoryItem* item = model->getItem(*sel_iter); if(item) { if(std::find(items.begin(), items.end(), item) == items.end()) { items.push_back(item); LLInventoryCategory* parent = model->getCategory(item->getParentUUID()); if(std::find(cats.begin(), cats.end(), parent) == cats.end()) { cats.push_back(parent); } } } } LLInventoryBackupOrder* order = new LLInventoryBackupOrder(); order->mCats = cats; order->mItems = items; LLFloaterInventoryBackupSettings* floater = new LLFloaterInventoryBackupSettings(order); floater->center(); } LLFloaterInventoryBackup::LLFloaterInventoryBackup(std::string path, std::vector cats, std::vector items) : LLFloater(), mPath(path), mCats(cats), mItems(items), mBusy(0) { mItemsTotal = mItems.size(); mItemsCompleted = 0; LLFloaterInventoryBackup::sInstances.push_back(this); LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inventory_backup.xml"); } LLFloaterInventoryBackup::~LLFloaterInventoryBackup() { LLFloaterInventoryBackup::sInstances.remove(this); } BOOL LLFloaterInventoryBackup::postBuild(void) { // Make progress bar /* LLLineEditor* line = new LLLineEditor( std::string("progress_line"), LLRect(4, 80, 396, 60), std::string("Progress")); line->setEnabled(FALSE); addChild(line); LLViewBorder* border = new LLViewBorder( "progress_border", LLRect(4, 79, 395, 60)); addChild(border); */ // Add all items to the list LLScrollListCtrl* list = getChild("item_list"); std::vector::iterator item_iter = mItems.begin(); std::vector::iterator item_end = mItems.end(); for( ; item_iter != item_end; ++item_iter) { LLSD element; element["id"] = (*item_iter)->getUUID(); LLSD& type_column = element["columns"][LIST_TYPE]; type_column["column"] = "type"; type_column["type"] = "icon"; type_column["value"] = "move_down_in.tga"; // FIXME LLSD& name_column = element["columns"][LIST_NAME]; name_column["column"] = "name"; name_column["value"] = (*item_iter)->getName(); LLSD& status_column = element["columns"][LIST_STATUS]; status_column["column"] = "status"; status_column["value"] = "Pending"; LLScrollListItem* scroll_itemp = list->addElement(element, ADD_BOTTOM); //hack to stop crashing LLScrollListIcon* icon = (LLScrollListIcon*)scroll_itemp->getColumn(LIST_TYPE); icon->setClickCallback(NULL, NULL); } // Setup and go! mBusy = 1; mItemIter = mItems.begin(); setStatus((*mItemIter)->getUUID(), "Downloading"); LLInventoryBackup::download(*mItemIter, this, LLFloaterInventoryBackup::imageCallback, LLFloaterInventoryBackup::assetCallback); advance(); return TRUE; } void LLFloaterInventoryBackup::advance() { while((mItemIter != mItems.end()) && (mBusy < 4)) { mBusy++; mItemIter++; if(mItemIter >= mItems.end()) break; setStatus((*mItemIter)->getUUID(), "Downloading"); LLInventoryBackup::download(*mItemIter, this, LLFloaterInventoryBackup::imageCallback, LLFloaterInventoryBackup::assetCallback); } } void LLFloaterInventoryBackup::setStatus(LLUUID itemid, std::string status) { LLScrollListCtrl* list = getChild("item_list"); std::vector items = list->getAllData(); std::vector::iterator iter = items.begin(); std::vector::iterator end = items.end(); for( ; iter != end; ++iter) { if((*iter)->getUUID() == itemid) { (*iter)->getColumn(LIST_STATUS)->setValue(status); break; } } } void LLFloaterInventoryBackup::finishItem(LLUUID itemid, std::string status) { // Update big happy progress bar mItemsCompleted++; LLView* progress_background = getChildView("progress_background", TRUE, TRUE); LLRect rect = progress_background->getRect(); float item_count = (float)mItemsTotal; float item_pos = (float)mItemsCompleted; float rect_width = (float)rect.getWidth(); float incr = rect_width / item_count; incr *= item_pos; rect.mRight = rect.mLeft + (S32)incr; LLView* progress_foreground = getChildView("progress_foreground", TRUE, TRUE); progress_foreground->setRect(rect); if(mItemsCompleted >= mItemsTotal) { childSetText("progress_background", llformat("Completed %d items.", mItemsTotal)); childSetVisible("progress_foreground", false); } // Update item status setStatus(itemid, status); // And advance mBusy--; advance(); } // static void LLFloaterInventoryBackup::imageCallback(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) { if(final) { LLInventoryBackup::callbackdata* data = static_cast(userdata); LLFloaterInventoryBackup* floater = (LLFloaterInventoryBackup*)(data->floater); LLInventoryItem* item = data->item; if(std::find(LLFloaterInventoryBackup::sInstances.begin(), LLFloaterInventoryBackup::sInstances.end(), floater) == LLFloaterInventoryBackup::sInstances.end()) { return; } if(!success) { floater->finishItem(item->getUUID(), "Failed download"); return; } std::string filename = floater->mPath + OS_SEP + LLInventoryBackup::getPath(gInventory.getCategory(item->getParentUUID()), floater->mCats) + OS_SEP + LLDir::getScrubbedFileName(item->getName()); filename = LLInventoryBackup::getUniqueFilename(filename, LLInventoryBackup::getExtension(item)); LLPointer image_tga = new LLImageTGA; if( !image_tga->encode( src ) ) { floater->finishItem(item->getUUID(), "Failed tga encode"); } else if( !image_tga->save( filename ) ) { floater->finishItem(item->getUUID(), "Failed save"); } else { floater->finishItem(item->getUUID(), "Done"); } } else { src_vi->setBoostLevel(LLViewerTexture::BOOST_UI); } } // static void LLFloaterInventoryBackup::assetCallback(LLVFS *vfs, const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status) { LLInventoryBackup::callbackdata* data = static_cast(user_data); LLFloaterInventoryBackup* floater = (LLFloaterInventoryBackup*)(data->floater); LLInventoryItem* item = data->item; if(std::find(LLFloaterInventoryBackup::sInstances.begin(), LLFloaterInventoryBackup::sInstances.end(), floater) == LLFloaterInventoryBackup::sInstances.end()) { return; } if(status != 0) { floater->finishItem(item->getUUID(), "Failed download"); return; } // Todo: this doesn't work for static vfs shit LLVFile file(vfs, asset_uuid, type, LLVFile::READ); S32 size = file.getSize(); char* buffer = new char[size]; if (buffer == NULL) { //llerrs << "Memory Allocation Failed" << llendl; floater->finishItem(item->getUUID(), "Failed memory allocation"); return; } file.read((U8*)buffer, size); // Write it back out... std::string filename = floater->mPath + OS_SEP + LLInventoryBackup::getPath(gInventory.getCategory(item->getParentUUID()), floater->mCats) + OS_SEP + LLDir::getScrubbedFileName(item->getName()); filename = LLInventoryBackup::getUniqueFilename(filename, LLInventoryBackup::getExtension(item)); std::ofstream export_file(filename.c_str(), std::ofstream::binary); export_file.write(buffer, size); export_file.close(); floater->finishItem(item->getUUID(), "Done"); } //