diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..8fa2779de --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +installed.xml diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 102a74c10..b4582fc27 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -67,6 +67,7 @@ set(viewer_SOURCE_FILES dofloaterhex.cpp dohexeditor.cpp doinventorybackup.cpp + hgfloatertexteditor.cpp jcfloaterareasearch.cpp llagent.cpp llagentaccess.cpp @@ -490,6 +491,7 @@ set(viewer_HEADER_FILES dofloaterhex.h dohexeditor.h doinventorybackup.h + hgfloatertexteditor.h jcfloaterareasearch.h llagent.h llagentaccess.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 90daefbf2..dd94cd20f 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -12665,5 +12665,21 @@ Value 16 + FloaterAssetTextEditorRect + + Comment + Rectangle for asset text editor floater. + Persist + 1 + Type + Rect + Value + + 343 + 687 + 901 + 473 + + diff --git a/indra/newview/hgfloatertexteditor.cpp b/indra/newview/hgfloatertexteditor.cpp new file mode 100644 index 000000000..7719de556 --- /dev/null +++ b/indra/newview/hgfloatertexteditor.cpp @@ -0,0 +1,393 @@ +/** + * @file hgfloatertexteditor.cpp + * @brief Asset Text Editor floater made by Hazim Gazov (based on hex editor floater by Day Oh) + * @author Hazim Gazov + * + * $LicenseInfo:firstyear=2010&license=WTFPLV2$ + * + */ + +// + +#include "llviewerprecompiledheaders.h" + +#include "hgfloatertexteditor.h" +#include "lluictrlfactory.h" +#include "doinventorybackup.h" // for downloading +#include "llviewercontrol.h" // gSavedSettings +#include "llviewerwindow.h" // alertXML +#include "llagent.h" // gAgent getID +#include "llviewermenufile.h" +#include "llviewerregion.h" // getCapability +#include "llassetuploadresponders.h" // LLUpdateAgentInventoryResponder +#include "llinventorymodel.h" // gInventory.updateItem +#include "llappviewer.h" // gLocalInventoryRoot +#include "llfloaterperms.h" //get default perms + +std::list HGFloaterTextEditor::sInstances; +S32 HGFloaterTextEditor::sUploadAmount = 10; + +HGFloaterTextEditor::HGFloaterTextEditor(LLInventoryItem* item) +: LLFloater() +{ + sInstances.push_back(this); + mItem = item; + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_asset_text_editor.xml"); +} + +// static +void HGFloaterTextEditor::show(LLUUID item_id) +{ + LLInventoryItem* item = (LLInventoryItem*)gInventory.getItem(item_id); + if(item) + { + S32 left, top; + gFloaterView->getNewFloaterPosition(&left, &top); + LLRect rect = gSavedSettings.getRect("FloaterAssetTextEditorRect"); + rect.translate(left - rect.mLeft, top - rect.mTop); + HGFloaterTextEditor* floaterp = new HGFloaterTextEditor(item); + floaterp->setRect(rect); + gFloaterView->adjustToFitScreen(floaterp, FALSE); + } +} + +HGFloaterTextEditor::~HGFloaterTextEditor() +{ + sInstances.remove(this); +} + +void HGFloaterTextEditor::close(bool app_quitting) +{ + LLFloater::close(app_quitting); +} + +BOOL HGFloaterTextEditor::postBuild(void) +{ + LLTextEditor* editor = getChild("text_editor"); + mEditor = editor; + + childSetEnabled("upload_btn", false); + childSetLabelArg("upload_btn", "[UPLOAD]", std::string("Upload")); + childSetAction("upload_btn", onClickUpload, this); + childSetEnabled("save_btn", false); + childSetAction("save_btn", onClickSave, this); + + if(mItem) + { + std::string title = "Text editor: " + mItem->getName(); + const char* asset_type_name = LLAssetType::lookup(mItem->getType()); + if(asset_type_name) + { + title.append(" (" + std::string(asset_type_name) + ")"); + } + setTitle(title); + } + + if(mItem->getCreatorUUID() == gAgentID) + { + // Load the asset + editor->setVisible(FALSE); + childSetText("status_text", std::string("Loading...")); + DOInventoryBackup::download(mItem, this, imageCallback, assetCallback); + } else { + this->close(false); + } + + return TRUE; +} + +// static +void HGFloaterTextEditor::imageCallback(BOOL success, + LLViewerImage *src_vi, + LLImageRaw* src, + LLImageRaw* aux_src, + S32 discard_level, + BOOL final, + void* userdata) +{ + if(final) + { + DOInventoryBackup::callbackdata* data = static_cast(userdata); + HGFloaterTextEditor* floater = (HGFloaterTextEditor*)(data->floater); + if(!floater) return; + if(std::find(sInstances.begin(), sInstances.end(), floater) == sInstances.end()) return; // no more crash + //LLInventoryItem* item = data->item; + + if(!success) + { + floater->childSetText("status_text", std::string("Unable to download asset.")); + return; + } + + U8* src_data = src->getData(); + S32 size = src->getDataSize(); + std::vector new_data; + for(S32 i = 0; i < size; i++) + new_data.push_back(src_data[i]); + + floater->mEditor->setValue(new_data); + floater->mEditor->setVisible(TRUE); + floater->childSetText("status_text", std::string("Note: Image data shown isn't the actual asset data, yet")); + + floater->childSetEnabled("save_btn", false); + floater->childSetEnabled("upload_btn", true); + floater->childSetLabelArg("upload_btn", "[UPLOAD]", std::string("Upload (L$10)")); + } + else + { + src_vi->setBoostLevel(LLViewerImageBoostLevel::BOOST_UI); + } +} + +// static +void HGFloaterTextEditor::assetCallback(LLVFS *vfs, + const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) +{ + DOInventoryBackup::callbackdata* data = static_cast(user_data); + HGFloaterTextEditor* floater = (HGFloaterTextEditor*)(data->floater); + if(!floater) return; + if(std::find(sInstances.begin(), sInstances.end(), floater) == sInstances.end()) return; // no more crash + LLInventoryItem* item = data->item; + + if(status != 0 && item->getType() != LLAssetType::AT_NOTECARD) + { + floater->childSetText("status_text", std::string("Unable to download asset.")); + 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; + return; + } + + file.read((U8*)buffer, size); + + std::vector new_data; + for(S32 i = 0; i < size; i++) + new_data.push_back(buffer[i]); + + delete[] buffer; + + floater->mEditor->setValue(new_data); + floater->mEditor->setVisible(TRUE); + floater->childSetText("status_text", std::string("")); + + floater->childSetEnabled("upload_btn", true); + floater->childSetEnabled("save_btn", false); + if(item->getPermissions().allowModifyBy(gAgent.getID())) + { + switch(item->getType()) + { + case LLAssetType::AT_TEXTURE: + case LLAssetType::AT_ANIMATION: + case LLAssetType::AT_SOUND: + floater->childSetLabelArg("upload_btn", "[UPLOAD]", std::string("Upload (L$10)")); + break; + case LLAssetType::AT_LANDMARK: + case LLAssetType::AT_CALLINGCARD: + floater->childSetEnabled("upload_btn", false); + floater->childSetEnabled("save_btn", false); + break; + default: + floater->childSetEnabled("save_btn", true); + break; + } + } + else + { + switch(item->getType()) + { + case LLAssetType::AT_TEXTURE: + case LLAssetType::AT_ANIMATION: + case LLAssetType::AT_SOUND: + floater->childSetLabelArg("upload_btn", "[UPLOAD]", std::string("Upload (L$10)")); + break; + default: + break; + } + } + + // Never enable save if it's a pretend item + /* if(gInventory.isObjectDescendentOf(item->getUUID(), gLocalInventoryRoot)) + { + floater->childSetEnabled("save_btn", false); + } */ +} + +// static +void HGFloaterTextEditor::onClickUpload(void* user_data) +{ + HGFloaterTextEditor* floater = (HGFloaterTextEditor*)user_data; + LLInventoryItem* item = floater->mItem; + + LLTransactionID transaction_id; + transaction_id.generate(); + LLUUID fake_asset_id = transaction_id.makeAssetID(gAgent.getSecureSessionID()); + + std::vector value = floater->mEditor->getValue(); + int size = value.size(); + U8* buffer = new U8[size]; + for(int i = 0; i < size; i++) + buffer[i] = value[i]; + value.clear(); + + LLVFile file(gVFS, fake_asset_id, item->getType(), LLVFile::APPEND); + file.setMaxSize(size); + if (!file.write(buffer, size)) + { + LLSD args; + args["ERROR_MESSAGE"] = "Couldn't write data to file"; + LLNotifications::instance().add("ErrorMessage", args); + return; + } + delete[] buffer; + + LLAssetStorage::LLStoreAssetCallback callback = NULL; + void *fake_user_data = NULL; + + if(item->getType() != LLAssetType::AT_GESTURE && item->getType() != LLAssetType::AT_LSL_TEXT + && item->getType() != LLAssetType::AT_NOTECARD) + { + //U32 const std::string &display_name, LLAssetStorage::LLStoreAssetCallback callback, S32 expected_upload_cost, void *userdata) + upload_new_resource(transaction_id, + item->getType(), + item->getName(), + item->getDescription(), + 0, + item->getType(), + item->getInventoryType(), + LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(), + item->getName(), + callback, + sUploadAmount, + fake_user_data); + } + else // gestures and scripts, create an item first + { // AND notecards + //if(item->getType() == LLAssetType::AT_NOTECARD) gDontOpenNextNotecard = true; + create_inventory_item( gAgent.getID(), + gAgent.getSessionID(), + item->getParentUUID(), //gInventory.findCategoryUUIDForType(item->getType()), + LLTransactionID::tnull, + item->getName(), + fake_asset_id.asString(), + item->getType(), + item->getInventoryType(), + (EWearableType)item->getFlags(), + PERM_ITEM_UNRESTRICTED, + new NewResourceItemCallback); + } +} + +struct LLSaveInfo +{ + LLSaveInfo(HGFloaterTextEditor* floater, LLTransactionID transaction_id) + : mFloater(floater), mTransactionID(transaction_id) + { + } + + HGFloaterTextEditor* mFloater; + LLTransactionID mTransactionID; +}; + +// static +void HGFloaterTextEditor::onClickSave(void* user_data) +{ + HGFloaterTextEditor* floater = (HGFloaterTextEditor*)user_data; + LLInventoryItem* item = floater->mItem; + + LLTransactionID transaction_id; + transaction_id.generate(); + LLUUID fake_asset_id = transaction_id.makeAssetID(gAgent.getSecureSessionID()); + + std::vector value = floater->mEditor->getValue(); + int size = value.size(); + U8* buffer = new U8[size]; + for(int i = 0; i < size; i++) + buffer[i] = value[i]; + value.clear(); + + LLVFile file(gVFS, fake_asset_id, item->getType(), LLVFile::APPEND); + file.setMaxSize(size); + if (!file.write(buffer, size)) + { + LLSD args; + args["ERROR_MESSAGE"] = "Couldn't write data to file"; + LLNotifications::instance().add("ErrorMessage", args); + return; + } + delete[] buffer; + + + bool caps = false; + std::string url; + LLSD body; + body["item_id"] = item->getUUID(); + + switch(item->getType()) + { + case LLAssetType::AT_GESTURE: + url = gAgent.getRegion()->getCapability("UpdateGestureAgentInventory"); + caps = true; + break; + case LLAssetType::AT_LSL_TEXT: + url = gAgent.getRegion()->getCapability("UpdateScriptAgent"); + body["target"] = "mono"; + caps = true; + break; + case LLAssetType::AT_NOTECARD: + url = gAgent.getRegion()->getCapability("UpdateNotecardAgentInventory"); + caps = true; + break; + default: // wearables & notecards, Oct 12 2009 + // ONLY WEARABLES, Oct 15 2009 + floater->childSetText("status_text", std::string("Saving...")); + LLSaveInfo* info = new LLSaveInfo(floater, transaction_id); + gAssetStorage->storeAssetData(transaction_id, item->getType(), onSaveComplete, info); + caps = false; + break; + } + + if(caps) + { + LLHTTPClient::post(url, body, + new LLUpdateAgentInventoryResponder(body, fake_asset_id, item->getType())); + } +} + +void HGFloaterTextEditor::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) +{ + LLSaveInfo* info = (LLSaveInfo*)user_data; + HGFloaterTextEditor* floater = info->mFloater; + if(std::find(sInstances.begin(), sInstances.end(), floater) == sInstances.end()) return; // no more crash + LLInventoryItem* item = floater->mItem; + + floater->childSetText("status_text", std::string("")); + + if(item && (status == 0)) + { + LLPointer new_item = new LLViewerInventoryItem(item); + new_item->setDescription(item->getDescription()); + new_item->setTransactionID(info->mTransactionID); + new_item->setAssetUUID(asset_uuid); + new_item->updateServer(FALSE); + gInventory.updateItem(new_item); + gInventory.notifyObservers(); + } + else + { + LLSD args; + args["ERROR_MESSAGE"] = llformat("Upload failed with status %d, also %d", status, ext_status); + LLNotifications::instance().add("ErrorMessage", args); + } +} + +// diff --git a/indra/newview/hgfloatertexteditor.h b/indra/newview/hgfloatertexteditor.h new file mode 100644 index 000000000..dd796c1c8 --- /dev/null +++ b/indra/newview/hgfloatertexteditor.h @@ -0,0 +1,50 @@ +/** + * @file hgfloatertexteditor.h + * @brief Asset Text Editor floater made by Hazim Gazov (based on hex editor floater by Day Oh) + * @author Hazim Gazov + * + * $LicenseInfo:firstyear=2010&license=WTFPLV2$ + * + */ + + +#ifndef HG_HGFLOATERHEX_H +#define HG_HGFLOATERHEX_H + +#include "llfloater.h" +#include "lltexteditor.h" +#include "llinventory.h" +#include "llviewerimage.h" + +class HGFloaterTextEditor +: public LLFloater +{ +public: + HGFloaterTextEditor(LLInventoryItem* item); + static void show(LLUUID item_id); + BOOL postBuild(void); + void close(bool app_quitting); + static void imageCallback(BOOL success, + LLViewerImage *src_vi, + LLImageRaw* src, + LLImageRaw* aux_src, + S32 discard_level, + BOOL final, + void* userdata); + static void assetCallback(LLVFS *vfs, + const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status); + static void onClickSave(void* user_data); + static void onClickUpload(void* user_data); + static void onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status); + LLInventoryItem* mItem; + LLTextEditor* mEditor; + static std::list sInstances; +private: + virtual ~HGFloaterTextEditor(); +protected: + static S32 sUploadAmount; +}; + +#endif diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 44a05dde5..058e23167 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -87,6 +87,7 @@ #include "llselectmgr.h" #include "llfloateropenobject.h" #include "dofloaterhex.h" +#include "hgfloatertexteditor.h" // Helpers // bug in busy count inc/dec right now, logic is complex... do we really need it? @@ -774,6 +775,13 @@ void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model, if(item->getCreatorUUID() != gAgentID) return; DOFloaterHex::show(mUUID); } + else if("open text" == action) + { + LLInventoryItem* item = model->getItem(mUUID); + if(!item) return; + if(item->getCreatorUUID() != gAgentID) return; + HGFloaterTextEditor::show(mUUID); + } else if ("copy_uuid" == action) { // Single item only diff --git a/indra/newview/skins/default/xui/en-us/floater_asset_text_editor.xml b/indra/newview/skins/default/xui/en-us/floater_asset_text_editor.xml new file mode 100644 index 000000000..e9f0fbf8a --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/floater_asset_text_editor.xml @@ -0,0 +1,9 @@ + + + Loading... +