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
+
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...
+
+
+
+
diff --git a/indra/newview/skins/default/xui/en-us/menu_inventory.xml b/indra/newview/skins/default/xui/en-us/menu_inventory.xml
index 72101a59a..8e43ca7aa 100644
--- a/indra/newview/skins/default/xui/en-us/menu_inventory.xml
+++ b/indra/newview/skins/default/xui/en-us/menu_inventory.xml
@@ -136,6 +136,10 @@
name="Hex Open" width="128">
+
+
+