diff --git a/indra/llvfs/llvfile.h b/indra/llvfs/llvfile.h index 5f69a4104..8db45d30b 100644 --- a/indra/llvfs/llvfile.h +++ b/indra/llvfs/llvfile.h @@ -80,10 +80,11 @@ public: static const S32 READ_WRITE; static const S32 APPEND; -protected: LLAssetType::EType mFileType; LLUUID mFileID; + +protected: S32 mPosition; S32 mMode; LLVFS *mVFS; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index a38a746cc..8c89e75f6 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -76,6 +76,7 @@ set(viewer_SOURCE_FILES llanimstatelabels.cpp llao.cpp llappviewer.cpp + llassetconverter.cpp llassetuploadresponders.cpp llassetuploadqueue.cpp llaudiosourcevo.cpp @@ -213,6 +214,7 @@ set(viewer_SOURCE_FILES llfloatertos.cpp llfloaterurldisplay.cpp llfloaterurlentry.cpp + llfloatervfs.cpp llfloatervoicedevicesettings.cpp llfloaterwater.cpp llfloaterwindlight.cpp @@ -511,6 +513,7 @@ set(viewer_HEADER_FILES llao.h llappearance.h llappviewer.h + llassetconverter.h llassetuploadresponders.h llassetuploadqueue.h llaudiosourcevo.h @@ -649,6 +652,7 @@ set(viewer_HEADER_FILES llfloatertos.h llfloaterurldisplay.h llfloaterurlentry.h + llfloatervfs.h llfloatervoicedevicesettings.h llfloaterwater.h llfloaterwindlight.h diff --git a/indra/newview/llassetconverter.cpp b/indra/newview/llassetconverter.cpp new file mode 100644 index 000000000..b0a14dbc7 --- /dev/null +++ b/indra/newview/llassetconverter.cpp @@ -0,0 +1,178 @@ +// +#include "llviewerprecompiledheaders.h" +#include "llvfs.h" +#include "llapr.h" +#include "llvfile.h" +#include "llassetconverter.h" +#include "llviewerimagelist.h" +#include "llvorbisencode.h" +#include "llbvhloader.h" +// static +LLAssetType::EType LLAssetConverter::convert(std::string src_filename, std::string filename) +{ + std::string exten = gDirUtilp->getExtension(src_filename); + LLAssetType::EType asset_type = LLAssetType::AT_NONE; + if (exten.empty()) + return LLAssetType::AT_NONE; + else if(exten == "bmp") + { + asset_type = LLAssetType::AT_TEXTURE; + if (!LLViewerImageList::createUploadFile(src_filename, + filename, + IMG_CODEC_BMP )) + { + return LLAssetType::AT_NONE; + } + } + else if( exten == "tga") + { + asset_type = LLAssetType::AT_TEXTURE; + if (!LLViewerImageList::createUploadFile(src_filename, + filename, + IMG_CODEC_TGA )) + { + return LLAssetType::AT_NONE; + } + } + else if( exten == "jpg" || exten == "jpeg") + { + asset_type = LLAssetType::AT_TEXTURE; + if (!LLViewerImageList::createUploadFile(src_filename, + filename, + IMG_CODEC_JPEG )) + { + return LLAssetType::AT_NONE; + } + } + else if( exten == "png") + { + asset_type = LLAssetType::AT_TEXTURE; + if (!LLViewerImageList::createUploadFile(src_filename, + filename, + IMG_CODEC_PNG )) + { + return LLAssetType::AT_NONE; + } + } + else if(exten == "wav") + { + asset_type = LLAssetType::AT_SOUND; + if(encode_vorbis_file(src_filename, filename) != LLVORBISENC_NOERR) + { + return LLAssetType::AT_NONE; + } + } + else if(exten == "ogg") + { + asset_type = LLAssetType::AT_SOUND; + if(!copyFile(src_filename, filename)) + { + return LLAssetType::AT_NONE; + } + } + //else if(exten == "tmp") FIXME + else if (exten == "bvh") + { + asset_type = LLAssetType::AT_ANIMATION; + S32 file_size; + LLAPRFile fp; + fp.open(src_filename, LL_APR_RB, LLAPRFile::global, &file_size); + if(!fp.getFileHandle()) return LLAssetType::AT_NONE; + char* file_buffer = new char[file_size + 1]; + if(fp.read(file_buffer, file_size) == 0) //not sure if this is right, gotta check this one + { + fp.close(); + delete[] file_buffer; + return LLAssetType::AT_NONE; + } + LLBVHLoader* loaderp = new LLBVHLoader(file_buffer); + if(!loaderp->isInitialized()) + { + fp.close(); + delete[] file_buffer; + return LLAssetType::AT_NONE; + } + S32 buffer_size = loaderp->getOutputSize(); + U8* buffer = new U8[buffer_size]; + LLDataPackerBinaryBuffer dp(buffer, buffer_size); + loaderp->serialize(dp); + LLAPRFile apr_file(filename, LL_APR_WB, LLAPRFile::global); + apr_file.write(buffer, buffer_size); + delete[] file_buffer; + delete[] buffer; + fp.close(); + apr_file.close(); + } + else if (exten == "animatn") + { + asset_type = LLAssetType::AT_ANIMATION; + if(!copyFile(src_filename, filename)) + { + return LLAssetType::AT_NONE; + } + } + else if(exten == "jp2" || exten == "j2k" || exten == "j2c") + { + asset_type = LLAssetType::AT_TEXTURE; + if(!copyFile(src_filename, filename)) + { + return LLAssetType::AT_NONE; + } + } + else if(exten == "gesture") + { + asset_type = LLAssetType::AT_GESTURE; + if(!copyFile(src_filename, filename)) + { + return LLAssetType::AT_NONE; + } + } + else if(exten == "notecard") + { + asset_type = LLAssetType::AT_NOTECARD; + if(!copyFile(src_filename, filename)) + { + return LLAssetType::AT_NONE; + } + } + else if(exten == "lsl") + { + asset_type = LLAssetType::AT_LSL_TEXT; + if(!copyFile(src_filename, filename)) + { + return LLAssetType::AT_NONE; + } + } + else if(exten == "eyes" || exten == "gloves" || exten == "hair" || exten == "jacket" || exten == "pants" || exten == "shape" || exten == "shirt" || exten == "shoes" || exten == "skin" || exten == "skirt" || exten == "socks" || exten == "underpants" || exten == "undershirt" || exten == "bodypart" || exten == "clothing") + { + asset_type = LLAssetType::AT_CLOTHING; + if(!copyFile(src_filename, filename)) + { + return LLAssetType::AT_NONE; + } + } + else + { + llwarns << "Unhandled extension" << llendl; + return LLAssetType::AT_NONE; + } + return asset_type; +} +BOOL LLAssetConverter::copyFile(std::string src_filename, std::string dst_filename) +{ + S32 src_size; + LLAPRFile src_fp; + src_fp.open(src_filename, LL_APR_RB, LLAPRFile::global, &src_size); + if(!src_fp.getFileHandle()) return FALSE; + LLAPRFile dst_fp; + dst_fp.open(dst_filename, LL_APR_WB, LLAPRFile::global); + if(!dst_fp.getFileHandle()) return FALSE; + char* buffer = new char[src_size + 1]; + src_fp.read(buffer, src_size); + dst_fp.write(buffer, src_size); + src_fp.close(); + dst_fp.close(); + delete[] buffer; + return TRUE; +} +// diff --git a/indra/newview/llassetconverter.h b/indra/newview/llassetconverter.h new file mode 100644 index 000000000..87f264b1d --- /dev/null +++ b/indra/newview/llassetconverter.h @@ -0,0 +1,15 @@ +// +#ifndef LL_LLASSETCONVERTER_H +#define LL_LLASSETCONVERTER_H + +#include "llcommon.h" +#include "llassettype.h" + +class LLAssetConverter +{ +public: + static LLAssetType::EType convert(std::string src_filename, std::string filename); + static BOOL copyFile(std::string src_filename, std::string dest_filename); +}; +#endif +// diff --git a/indra/newview/llfloatervfs.cpp b/indra/newview/llfloatervfs.cpp new file mode 100644 index 000000000..b7e75e89c --- /dev/null +++ b/indra/newview/llfloatervfs.cpp @@ -0,0 +1,332 @@ +// +#include "llviewerprecompiledheaders.h" +#include "llfloatervfs.h" +#include "lluictrlfactory.h" +#include "llscrolllistctrl.h" +#include "llfilepicker.h" +#include "lllocalinventory.h" +#include "llviewerwindow.h" +#include "llassetconverter.h" +LLFloaterVFS* LLFloaterVFS::sInstance; +std::list LLFloaterVFS::mFiles; +LLFloaterVFS::LLFloaterVFS() +: LLFloater(), + mEditID(LLUUID::null) +{ + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_vfs.xml"); +} +LLFloaterVFS::~LLFloaterVFS() +{ + sInstance = NULL; +} +// static +void LLFloaterVFS::show() +{ + if(sInstance) + sInstance->open(); + else + { + sInstance = new LLFloaterVFS(); + sInstance->open(); + } +} +BOOL LLFloaterVFS::postBuild() +{ + childSetAction("add_btn", onClickAdd, this); + childSetAction("clear_btn", onClickClear, this); + childSetAction("reload_all_btn", onClickReloadAll, this); + childSetCommitCallback("file_list", onCommitFileList, this); + childSetCommitCallback("name_edit", onCommitEdit, this); + childSetCommitCallback("id_edit", onCommitEdit, this); + childSetCommitCallback("type_combo", onCommitEdit, this); + childSetAction("copy_uuid_btn", onClickCopyUUID, this); + childSetAction("item_btn", onClickItem, this); + childSetAction("reload_btn", onClickReload, this); + childSetAction("remove_btn", onClickRemove, this); + refresh(); + return TRUE; +} +void LLFloaterVFS::refresh() +{ + LLScrollListCtrl* list = getChild("file_list"); + list->clearRows(); + std::list::iterator end = mFiles.end(); + for(std::list::iterator iter = mFiles.begin(); iter != end; ++iter) + { + entry file = (*iter); + LLSD element; + element["id"] = file.mID; + LLSD& name_column = element["columns"][0]; + name_column["column"] = "name"; + name_column["value"] = file.mName.empty() ? file.mID.asString() : file.mName; + LLSD& type_column = element["columns"][1]; + type_column["column"] = "type"; + type_column["value"] = std::string(LLAssetType::lookup(file.mType)); + list->addElement(element, ADD_BOTTOM); + } + setMassEnabled(!mFiles.empty()); + setEditID(mEditID); +} +void LLFloaterVFS::add(entry file) +{ + mFiles.push_back(file); + refresh(); +} +void LLFloaterVFS::clear() +{ + std::list::iterator end = mFiles.end(); + for(std::list::iterator iter = mFiles.begin(); iter != end; ++iter) + { + gVFS->removeFile((*iter).mID, (*iter).mType); + } + mFiles.clear(); + refresh(); +} +void LLFloaterVFS::reloadAll() +{ + std::list::iterator end = mFiles.end(); + for(std::list::iterator iter = mFiles.begin(); iter != end; ++iter) + { + entry file = (*iter); + reloadEntry(file); + } + refresh(); +} +void LLFloaterVFS::reloadEntry(entry file) +{ + gVFS->removeFile(file.mID, file.mType); + std::string file_name = file.mFilename; + S32 file_size; + LLAPRFile fp; + fp.open(file_name, LL_APR_RB, LLAPRFile::global, &file_size); + if(fp.getFileHandle()) + { + LLVFile file(gVFS, file.mFileID, file.mFileType, LLVFile::WRITE); + file.setMaxSize(file_size); + const S32 buf_size = 65536; + U8 copy_buf[buf_size]; + while ((file_size = fp.read(copy_buf, buf_size))) + file.write(copy_buf, file_size); + fp.close(); + } + else + { + // todo: show a warning, couldn't open the original file + return; + } + refresh(); +} +void LLFloaterVFS::setEditID(LLUUID edit_id) +{ + LLScrollListCtrl* list = getChild("file_list"); + bool found_in_list = (list->getItemIndex(edit_id) != -1); + bool found_in_files = false; + entry file; + std::list::iterator end = mFiles.end(); + for(std::list::iterator iter = mFiles.begin(); iter != end; ++iter) + { + if((*iter).mID == edit_id) + { + found_in_files = true; + file = (*iter); + break; + } + } + if(found_in_files && found_in_list) + { + mEditID = edit_id; + list->selectByID(edit_id); + setEditEnabled(true); + childSetText("name_edit", file.mName); + childSetText("id_edit", file.mID.asString()); + childSetValue("type_combo", std::string(LLAssetType::lookup(file.mType))); + } + else + { + mEditID = LLUUID::null; + list->deselectAllItems(TRUE); + setEditEnabled(false); + childSetText("name_edit", std::string("")); + childSetText("id_edit", std::string("")); + childSetValue("type_combo", std::string("animatn")); + } +} +LLFloaterVFS::entry LLFloaterVFS::getEditEntry() +{ + std::list::iterator end = mFiles.end(); + for(std::list::iterator iter = mFiles.begin(); iter != end; ++iter) + { + if((*iter).mID == mEditID) + return (*iter); + } + entry file; + file.mID = LLUUID::null; + return file; +} +void LLFloaterVFS::commitEdit() +{ + bool found = false; + entry file; + std::list::iterator iter; + std::list::iterator end = mFiles.end(); + for(iter = mFiles.begin(); iter != end; ++iter) + { + if((*iter).mID == mEditID) + { + found = true; + file = (*iter); + break; + } + } + if(!found) return; + entry edited_file; + edited_file.mName = childGetValue("name_edit").asString(); + edited_file.mID = LLUUID(childGetValue("id_edit").asString()); + edited_file.mType = LLAssetType::lookup(getChild("type_combo")->getValue().asString()); + if((edited_file.mID != file.mID) || (edited_file.mType != file.mType)) + { + gVFS->renameFile(file.mID, file.mType, edited_file.mID, edited_file.mType); + mEditID = edited_file.mID; + } + (*iter) = edited_file; + refresh(); +} +void LLFloaterVFS::removeEntry() +{ + for(std::list::iterator iter = mFiles.begin(); iter != mFiles.end(); ) + { + if((*iter).mID == mEditID) + { + gVFS->removeFile((*iter).mID, (*iter).mType); + iter = mFiles.erase(iter); + } + else ++iter; + } + refresh(); +} +void LLFloaterVFS::setMassEnabled(bool enabled) +{ + childSetEnabled("clear_btn", enabled); + childSetEnabled("reload_all_btn", false); // DOESN'T WORK +} +void LLFloaterVFS::setEditEnabled(bool enabled) +{ + childSetEnabled("name_edit", enabled); + childSetEnabled("id_edit", false); // DOESN'T WORK + childSetEnabled("type_combo", false); // DOESN'T WORK + childSetEnabled("copy_uuid_btn", enabled); + childSetEnabled("item_btn", enabled); + childSetEnabled("reload_btn", false); // DOESN'T WORK + childSetEnabled("remove_btn", enabled); +} +// static +void LLFloaterVFS::onClickAdd(void* user_data) +{ + LLFloaterVFS* floaterp = (LLFloaterVFS*)user_data; + if(!floaterp) return; + LLUUID asset_id; + LLAssetType::EType asset_type = LLAssetType::AT_NONE; + asset_id.generate(); + LLFilePicker& file_picker = LLFilePicker::instance(); + if(file_picker.getOpenFile(LLFilePicker::FFLOAD_ALL)) + { + std::string file_name = file_picker.getFirstFile(); + std::string temp_filename = file_name + ".tmp"; + asset_type = LLAssetConverter::convert(file_name, temp_filename); + if(asset_type == LLAssetType::AT_NONE) + { + // todo: show a warning + return; + } + S32 file_size; + LLAPRFile fp; + fp.open(temp_filename, LL_APR_RB, LLAPRFile::global, &file_size); + if(fp.getFileHandle()) + { + LLVFile file(gVFS, asset_id, asset_type, LLVFile::WRITE); + file.setMaxSize(file_size); + const S32 buf_size = 65536; + U8 copy_buf[buf_size]; + while ((file_size = fp.read(copy_buf, buf_size))) + file.write(copy_buf, file_size); + fp.close(); + } + else + { + if(temp_filename != file_name) + { + LLFile::remove(temp_filename); + } + // todo: show a warning, couldn't open the selected file + return; + } + if(temp_filename != file_name) + { + LLFile::remove(temp_filename); + } + entry file; + file.mFilename = file_name; + file.mID = asset_id; + file.mType = asset_type; + file.mName = gDirUtilp->getBaseFileName(file_name, true); + floaterp->add(file); + } +} +// static +void LLFloaterVFS::onClickClear(void* user_data) +{ + LLFloaterVFS* floaterp = (LLFloaterVFS*)user_data; + if(!floaterp) return; + floaterp->clear(); +} +// static +void LLFloaterVFS::onClickReloadAll(void* user_data) +{ + LLFloaterVFS* floaterp = (LLFloaterVFS*)user_data; + if(!floaterp) return; + floaterp->reloadAll(); +} +// static +void LLFloaterVFS::onCommitFileList(LLUICtrl* ctrl, void* user_data) +{ + LLFloaterVFS* floaterp = (LLFloaterVFS*)user_data; + LLScrollListCtrl* list = floaterp->getChild("file_list"); + LLUUID selected_id(LLUUID::null); + if(list->getFirstSelected()) + selected_id = list->getFirstSelected()->getUUID(); + floaterp->setEditID(selected_id); +} +// static +void LLFloaterVFS::onCommitEdit(LLUICtrl* ctrl, void* user_data) +{ + LLFloaterVFS* floaterp = (LLFloaterVFS*)user_data; + floaterp->commitEdit(); +} +// static +void LLFloaterVFS::onClickCopyUUID(void* user_data) +{ + LLFloaterVFS* floaterp = (LLFloaterVFS*)user_data; + entry file = floaterp->getEditEntry(); + gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(file.mID.asString())); +} +// static +void LLFloaterVFS::onClickItem(void* user_data) +{ + LLFloaterVFS* floaterp = (LLFloaterVFS*)user_data; + entry file = floaterp->getEditEntry(); + LLLocalInventory::addItem(file.mName, (int)file.mType, file.mID, true); +} +// static +void LLFloaterVFS::onClickReload(void* user_data) +{ + LLFloaterVFS* floaterp = (LLFloaterVFS*)user_data; + entry file = floaterp->getEditEntry(); + floaterp->reloadEntry(file); +} +// static +void LLFloaterVFS::onClickRemove(void* user_data) +{ + LLFloaterVFS* floaterp = (LLFloaterVFS*)user_data; + floaterp->removeEntry(); +} +// diff --git a/indra/newview/llfloatervfs.h b/indra/newview/llfloatervfs.h new file mode 100644 index 000000000..7218b1090 --- /dev/null +++ b/indra/newview/llfloatervfs.h @@ -0,0 +1,46 @@ +// +#ifndef LL_LLFLOATERVFS_H +#define LL_LLFLOATERVFS_H +#include "llfloater.h" +#include "llassettype.h" +class LLFloaterVFS : LLFloater +{ +typedef struct +{ + std::string mFilename; + std::string mName; + LLUUID mID; + LLAssetType::EType mType; +} entry; +public: + LLFloaterVFS(); + ~LLFloaterVFS(); + static void show(); + BOOL postBuild(); + void refresh(); + void add(entry file); + void clear(); + void reloadAll(); + void setEditID(LLUUID edit_id); + entry getEditEntry(); + void commitEdit(); + void reloadEntry(entry file); + void removeEntry(); + static void onClickAdd(void* user_data); + static void onClickClear(void* user_data); + static void onClickReloadAll(void* user_data); + static void onCommitFileList(LLUICtrl* ctrl, void* user_data); + static void onCommitEdit(LLUICtrl* ctrl, void* user_data); + static void onClickCopyUUID(void* user_data); + static void onClickItem(void* user_data); + static void onClickReload(void* user_data); + static void onClickRemove(void* user_data); +private: + static LLFloaterVFS* sInstance; + static std::list mFiles; + LLUUID mEditID; + void setMassEnabled(bool enabled); + void setEditEnabled(bool enabled); +}; +#endif +// diff --git a/indra/newview/llinventoryactions.cpp b/indra/newview/llinventoryactions.cpp index 58b5e289f..619b0cf1b 100644 --- a/indra/newview/llinventoryactions.cpp +++ b/indra/newview/llinventoryactions.cpp @@ -550,6 +550,18 @@ class LLLoadInvCacheFloater : public inventory_listener_t return true; } }; + +class LLRefreshInvModel : public inventory_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) + { + LLInventoryModel* model = mPtr->getPanel()->getModel(); + if(!model) return false; + model->empty(); + model->startBackgroundFetch(); + return true; + } +}; // class LLSetSortBy : public inventory_listener_t { diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 291a230aa..59f000dd0 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -391,7 +391,7 @@ public: void addCategory(LLViewerInventoryCategory* category); void addItem(LLViewerInventoryItem* item); // -protected: +//protected: // // Internal method which looks for a category with the specified diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 29017b3b4..79298762f 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -234,6 +234,7 @@ #include "llfloatermessagelog.h" #include "llfloatermessagebuilder.h" #include "llao.h" +#include "llfloatervfs.h" #include "llfloaterexportregion.h" // @@ -402,6 +403,7 @@ void handle_reopen_with_hex_editor(void*); void handle_open_message_log(void*); void handle_open_message_builder(void*); void handle_edit_ao(void*); +void handle_local_assets(void*); // BOOL is_inventory_visible( void* user_data ); @@ -752,6 +754,9 @@ void init_client_menu(LLMenuGL* menu) sub->append(new LLMenuItemCallGL( "Message Log", &handle_open_message_log, NULL)); sub->append(new LLMenuItemCallGL( "Message Builder", &handle_open_message_builder, NULL)); + + sub->append(new LLMenuItemCallGL( "Local Assets...", + &handle_local_assets, NULL)); sub->append(new LLMenuItemCheckGL( "Enable AO", &menu_toggle_control, @@ -3084,6 +3089,11 @@ void handle_edit_ao(void*) LLFloaterAO::show(); } +void handle_local_assets(void*) +{ + LLFloaterVFS::show(); +} + void handle_close_all_notifications(void*) { LLView::child_list_t child_list(*(gNotifyBoxView->getChildList())); diff --git a/indra/newview/skins/default/xui/en-us/floater_inventory.xml b/indra/newview/skins/default/xui/en-us/floater_inventory.xml index 70cd4f2a5..8a69f2f53 100644 --- a/indra/newview/skins/default/xui/en-us/floater_inventory.xml +++ b/indra/newview/skins/default/xui/en-us/floater_inventory.xml @@ -60,6 +60,10 @@ name="Load InvCache..." width="128"> + + + + +