diff --git a/indra/newview/dofloaterhex.cpp b/indra/newview/dofloaterhex.cpp
index 08796782e..e30295b1e 100644
--- a/indra/newview/dofloaterhex.cpp
+++ b/indra/newview/dofloaterhex.cpp
@@ -1,415 +1,431 @@
-/**
- * @file dofloaterhex.h
- * @brief Hex Editor Floater made by Day
- * @author Day Oh
- *
- * $LicenseInfo:firstyear=2009&license=WTFPLV2$
- *
- */
-
-//
-
-#include "llviewerprecompiledheaders.h"
-
-#include "dofloaterhex.h"
-#include "lluictrlfactory.h"
-#include "llinventorybackup.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 DOFloaterHex::sInstances;
-S32 DOFloaterHex::sUploadAmount = 10;
-
-DOFloaterHex::DOFloaterHex(LLInventoryItem* item)
-: LLFloater()
-{
- sInstances.push_back(this);
- mItem = item;
- LLUICtrlFactory::getInstance()->buildFloater(this, "floater_hex.xml");
-}
-
-// static
-void DOFloaterHex::show(LLUUID item_id)
-{
- LLInventoryItem* item = (LLInventoryItem*)gInventory.getItem(item_id);
- if(item)
- {
- S32 left, top;
- gFloaterView->getNewFloaterPosition(&left, &top);
- LLRect rect = gSavedSettings.getRect("FloaterHexRect");
- rect.translate(left - rect.mLeft, top - rect.mTop);
- DOFloaterHex* floaterp = new DOFloaterHex(item);
- floaterp->setRect(rect);
- gFloaterView->adjustToFitScreen(floaterp, FALSE);
- }
-}
-
-DOFloaterHex::~DOFloaterHex()
-{
- sInstances.remove(this);
-}
-
-void DOFloaterHex::close(bool app_quitting)
-{
- LLFloater::close(app_quitting);
-}
-
-BOOL DOFloaterHex::postBuild(void)
-{
- DOHexEditor* editor = getChild("hex");
- mEditor = editor;
-
- // Set number of columns
- U8 columns = U8(gSavedSettings.getU32("HexEditorColumns"));
- editor->setColumns(columns);
- // Reflect clamped U8ness in settings
- gSavedSettings.setU32("HexEditorColumns", U32(columns));
-
- // Reshape a little based on columns
- S32 min_width = S32(editor->getSuggestedWidth()) + 20;
- setResizeLimits(min_width, getMinHeight());
- if(getRect().getWidth() < min_width)
- {
- //LLRect rect = getRect();
- //rect.setOriginAndSize(rect.mLeft, rect.mBottom, min_width, rect.getHeight());
- //setRect(rect);
-
- reshape(min_width, getRect().getHeight(), FALSE);
- editor->reshape(editor->getRect().getWidth(), editor->getRect().getHeight(), TRUE);
- }
-
- 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 = "Hex 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 OPENSIM_RULES!=1
- if(mItem->getCreatorUUID() == gAgentID)
- {
-#endif /* OPENSIM_RULES!=1 */
- // Load the asset
- editor->setVisible(FALSE);
- childSetText("status_text", std::string("Loading..."));
- LLInventoryBackup::download(mItem, this, imageCallback, assetCallback);
-#if OPENSIM_RULES!=1
- } else {
- this->close(false);
- }
-#endif /* OPENSIM_RULES!=1 */
-
- return TRUE;
-}
-
-// static
-void DOFloaterHex::imageCallback(BOOL success,
- LLViewerImage *src_vi,
- LLImageRaw* src,
- LLImageRaw* aux_src,
- S32 discard_level,
- BOOL final,
- void* userdata)
-{
- if(final)
- {
- LLInventoryBackup::callbackdata* data = static_cast(userdata);
- DOFloaterHex* floater = (DOFloaterHex*)(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 DOFloaterHex::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);
- DOFloaterHex* floater = (DOFloaterHex*)(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 DOFloaterHex::onClickUpload(void* user_data)
-{
- DOFloaterHex* floater = (DOFloaterHex*)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)
- {
- 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(DOFloaterHex* floater, LLTransactionID transaction_id)
- : mFloater(floater), mTransactionID(transaction_id)
- {
- }
-
- DOFloaterHex* mFloater;
- LLTransactionID mTransactionID;
-};
-
-// static
-void DOFloaterHex::onClickSave(void* user_data)
-{
- DOFloaterHex* floater = (DOFloaterHex*)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 DOFloaterHex::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status)
-{
- LLSaveInfo* info = (LLSaveInfo*)user_data;
- DOFloaterHex* 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);
- }
-}
-
-//
+/**
+ * @file dofloaterhex.h
+ * @brief Hex Editor Floater made by Day
+ * @author Day Oh
+ *
+ * $LicenseInfo:firstyear=2009&license=WTFPLV2$
+ *
+ */
+
+//
+
+#include "llviewerprecompiledheaders.h"
+
+#include "dofloaterhex.h"
+#include "lluictrlfactory.h"
+#include "llinventorybackup.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 DOFloaterHex::sInstances;
+S32 DOFloaterHex::sUploadAmount = 10;
+
+DOFloaterHex::DOFloaterHex(LLInventoryItem* item)
+: LLFloater()
+{
+ sInstances.push_back(this);
+ mItem = item;
+ LLUICtrlFactory::getInstance()->buildFloater(this, "floater_hex.xml");
+}
+
+// static
+void DOFloaterHex::show(LLUUID item_id)
+{
+ LLInventoryItem* item = (LLInventoryItem*)gInventory.getItem(item_id);
+ if(item)
+ {
+ S32 left, top;
+ gFloaterView->getNewFloaterPosition(&left, &top);
+ LLRect rect = gSavedSettings.getRect("FloaterHexRect");
+ rect.translate(left - rect.mLeft, top - rect.mTop);
+ DOFloaterHex* floaterp = new DOFloaterHex(item);
+ floaterp->setRect(rect);
+ gFloaterView->adjustToFitScreen(floaterp, FALSE);
+ }
+}
+
+DOFloaterHex::~DOFloaterHex()
+{
+ sInstances.remove(this);
+}
+
+void DOFloaterHex::close(bool app_quitting)
+{
+ LLFloater::close(app_quitting);
+}
+
+BOOL DOFloaterHex::postBuild(void)
+{
+ DOHexEditor* editor = getChild("hex");
+ mEditor = editor;
+#ifndef COLUMN_SPAN
+ // Set number of columns
+ U8 columns = U8(gSavedSettings.getU32("HexEditorColumns"));
+ editor->setColumns(columns);
+ // Reflect clamped U8ness in settings
+ gSavedSettings.setU32("HexEditorColumns", U32(columns));
+#endif
+ handleSizing();
+
+ 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 = "Hex 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 OPENSIM_RULES!=1
+ if(mItem->getCreatorUUID() == gAgentID)
+ {
+#endif /* OPENSIM_RULES!=1 */
+ // Load the asset
+ editor->setVisible(FALSE);
+ childSetText("status_text", std::string("Loading..."));
+ LLInventoryBackup::download(mItem, this, imageCallback, assetCallback);
+#if OPENSIM_RULES!=1
+ } else {
+ this->close(false);
+ }
+#endif /* OPENSIM_RULES!=1 */
+
+ return TRUE;
+}
+
+// static
+void DOFloaterHex::imageCallback(BOOL success,
+ LLViewerImage *src_vi,
+ LLImageRaw* src,
+ LLImageRaw* aux_src,
+ S32 discard_level,
+ BOOL final,
+ void* userdata)
+{
+ if(final)
+ {
+ LLInventoryBackup::callbackdata* data = static_cast(userdata);
+ DOFloaterHex* floater = (DOFloaterHex*)(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 DOFloaterHex::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);
+ DOFloaterHex* floater = (DOFloaterHex*)(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 DOFloaterHex::onClickUpload(void* user_data)
+{
+ DOFloaterHex* floater = (DOFloaterHex*)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)
+ {
+ 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(DOFloaterHex* floater, LLTransactionID transaction_id)
+ : mFloater(floater), mTransactionID(transaction_id)
+ {
+ }
+
+ DOFloaterHex* mFloater;
+ LLTransactionID mTransactionID;
+};
+
+// static
+void DOFloaterHex::onClickSave(void* user_data)
+{
+ DOFloaterHex* floater = (DOFloaterHex*)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 DOFloaterHex::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status)
+{
+ LLSaveInfo* info = (LLSaveInfo*)user_data;
+ DOFloaterHex* 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);
+ }
+}
+
+void DOFloaterHex::onCommitColumnCount(LLUICtrl *control, void *user_data)
+{
+ if(control && user_data)
+ {
+ DOFloaterHex *instance = (DOFloaterHex *)user_data;
+ U8 columns = llclamp((U8)llfloor(control->getValue().asReal()), 0x00, 0xFF);
+ instance->mEditor->setColumns(columns);
+ gSavedSettings.setU32("HexEditorColumns", (U32)instance->mEditor->getColumns());
+ instance->handleSizing();
+ }
+}
+
+void DOFloaterHex::handleSizing()
+{
+ // Reshape a little based on columns
+ S32 min_width = S32(mEditor->getSuggestedWidth(MIN_COLS)) + 20;
+ setResizeLimits(min_width, getMinHeight());
+ if(getRect().getWidth() < min_width)
+ {
+ //LLRect rect = getRect();
+ //rect.setOriginAndSize(rect.mLeft, rect.mBottom, min_width, rect.getHeight());
+ //setRect(rect);
+
+ reshape(min_width, getRect().getHeight(), FALSE);
+ mEditor->reshape(mEditor->getRect().getWidth(), mEditor->getRect().getHeight(), TRUE);
+ }
+}
+
+//
diff --git a/indra/newview/dofloaterhex.h b/indra/newview/dofloaterhex.h
index 3fc7e3aff..9c49b3e49 100644
--- a/indra/newview/dofloaterhex.h
+++ b/indra/newview/dofloaterhex.h
@@ -1,44 +1,46 @@
-//
-
-
-#ifndef LL_LLFLOATERHEX_H
-#define LL_LLFLOATERHEX_H
-
-#include "llfloater.h"
-#include "dohexeditor.h"
-#include "llinventory.h"
-#include "llviewerimage.h"
-
-class DOFloaterHex
-: public LLFloater
-{
-public:
- DOFloaterHex(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;
- DOHexEditor* mEditor;
- static std::list sInstances;
-private:
- virtual ~DOFloaterHex();
-protected:
- static S32 sUploadAmount;
-};
-
-#endif
-//
+//
+
+
+#ifndef LL_LLFLOATERHEX_H
+#define LL_LLFLOATERHEX_H
+
+#include "llfloater.h"
+#include "dohexeditor.h"
+#include "llinventory.h"
+#include "llviewerimage.h"
+
+class DOFloaterHex
+: public LLFloater
+{
+public:
+ DOFloaterHex(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);
+ static void onCommitColumnCount(LLUICtrl *control, void *user_data);
+ void handleSizing();
+ LLInventoryItem* mItem;
+ DOHexEditor* mEditor;
+ static std::list sInstances;
+private:
+ virtual ~DOFloaterHex();
+protected:
+ static S32 sUploadAmount;
+};
+
+#endif
+//
diff --git a/indra/newview/dohexeditor.cpp b/indra/newview/dohexeditor.cpp
index 7a59845ce..d03053957 100644
--- a/indra/newview/dohexeditor.cpp
+++ b/indra/newview/dohexeditor.cpp
@@ -1,1241 +1,1245 @@
-/**
- * @file dohexeditor.cpp
- * @brief DOHexEditor Widget
- * @author Day Oh
- *
- * $LicenseInfo:firstyear=2009&license=WTFPLV2$
- *
- */
-
-//
-#include "llviewerprecompiledheaders.h"
-
-#include "linden_common.h"
-#include "dohexeditor.h"
-#include "llfocusmgr.h"
-#include "llkeyboard.h"
-#include "llclipboard.h"
-#include "llwindow.h" // setCursor
-#include "lllocalinventory.h"
-
-static LLRegisterWidget r("hex_editor");
-
-DOHexEditor::DOHexEditor(const std::string& name, const LLRect& rect)
-: LLUICtrl(name, rect, TRUE, NULL, NULL),
- LLEditMenuHandler(),
- mColumns(16),
- mCursorPos(0),
- mSecondNibble(FALSE),
- mSelecting(FALSE),
- mHasSelection(FALSE),
- mInData(FALSE),
- mSelectionStart(0),
- mSelectionEnd(0)
-{
- mGLFont = LLFontGL::getFontMonospace();
-
- mTextRect.setOriginAndSize(
- 5, // border + padding
- 1, // border
- getRect().getWidth() - SCROLLBAR_SIZE - 6,
- getRect().getHeight() - 5);
-
- S32 line_height = llround( mGLFont->getLineHeight() );
- S32 page_size = mTextRect.getHeight() / line_height;
-
- // Init the scrollbar
- LLRect scroll_rect;
- scroll_rect.setOriginAndSize(
- getRect().getWidth() - SCROLLBAR_SIZE,
- 1,
- SCROLLBAR_SIZE,
- getRect().getHeight() - 1);
- S32 lines_in_doc = getLineCount();
- mScrollbar = new LLScrollbar( std::string("Scrollbar"), scroll_rect,
- LLScrollbar::VERTICAL,
- lines_in_doc,
- 0,
- page_size,
- NULL, this );
- mScrollbar->setFollowsRight();
- mScrollbar->setFollowsTop();
- mScrollbar->setFollowsBottom();
- mScrollbar->setEnabled( TRUE );
- mScrollbar->setVisible( TRUE );
- mScrollbar->setOnScrollEndCallback(NULL, NULL);
- addChild(mScrollbar);
-
- mBorder = new LLViewBorder( std::string("text ed border"),
- LLRect(0, getRect().getHeight(), getRect().getWidth(), 0),
- LLViewBorder::BEVEL_IN,
- LLViewBorder::STYLE_LINE,
- 1 ); // border width
- addChild( mBorder );
-
- changedLength();
-
- mUndoBuffer = new LLUndoBuffer(DOUndoHex::create, 128);
-}
-
-DOHexEditor::~DOHexEditor()
-{
- gFocusMgr.releaseFocusIfNeeded(this);
- if(gEditMenuHandler == this)
- {
- gEditMenuHandler = NULL;
- }
-}
-
-LLView* DOHexEditor::fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFactory *factory)
-{
- std::string name("text_editor");
- node->getAttributeString("name", name);
-
- LLRect rect;
- createRect(node, rect, parent, LLRect());
-
- DOHexEditor* editor = new DOHexEditor(name, rect);
-
- editor->initFromXML(node, parent);
-
- return editor;
-}
-
-void DOHexEditor::setValue(const LLSD& value)
-{
- mValue = value.asBinary();
- changedLength();
-}
-
-LLSD DOHexEditor::getValue() const
-{
- return LLSD(mValue);
-}
-
-void DOHexEditor::setColumns(U8 columns)
-{
- mColumns = columns;
- changedLength();
-}
-
-U32 DOHexEditor::getLineCount()
-{
- U32 lines = mValue.size();
- lines /= mColumns;
- lines++; // incomplete or extra line at bottom
- return lines;
-}
-
-void DOHexEditor::getPosAndContext(S32 x, S32 y, BOOL force_context, U32& pos, BOOL& in_data, BOOL& second_nibble)
-{
- pos = 0;
-
- F32 line_height = mGLFont->getLineHeight();
- F32 char_width = mGLFont->getWidthF32(".");
- F32 data_column_width = char_width * 3; // " 00";
- F32 text_x = mTextRect.mLeft;
- F32 text_x_data = text_x + (char_width * 10.1f); // "00000000 ", dunno why it's a fraction off
- F32 text_x_ascii = text_x_data + (data_column_width * mColumns) + (char_width * 2);
- F32 text_y = (F32)(mTextRect.mTop - line_height);
- U32 first_line = mScrollbar->getDocPos();
- //U32 last_line = first_line + mScrollbar->getPageSize(); // don't -2 from scrollbar sizes
- S32 first_line_y = text_y - line_height;
-
- S32 ly = -(y - first_line_y); // negative vector from first line to y
- ly -= 5; // slight skew
- S32 line = ly / line_height;
- if(line < 0) line = 0;
- line += first_line;
-
- if(!force_context)
- {
- in_data = (x < (text_x_ascii - char_width)); // char width for less annoying
- }
- S32 lx = x;
- S32 offset;
- if(in_data)
- {
- lx -= char_width; // subtracting char width because idk
- lx -= text_x_data;
- offset = lx / data_column_width;
-
- // Now, which character
- S32 rem = S32( (F32)lx - (data_column_width * offset) - (char_width * 0.25) );
- if(rem > 0)
- {
- if(rem > char_width)
- {
- offset++; // next byte
- second_nibble = FALSE;
- }
- else second_nibble = TRUE;
- }
- else second_nibble = FALSE;
- }
- else
- {
- second_nibble = FALSE;
- lx += char_width; // adding char width because idk
- lx -= text_x_ascii;
- offset = lx / char_width;
- }
- if(offset < 0) offset = 0;
- if(offset >= mColumns)//offset = mColumns - 1;
- {
- offset = 0;
- line++;
- second_nibble = FALSE;
- }
-
- pos = (line * mColumns) + offset;
- if(pos < 0) pos = 0;
- if(pos > mValue.size()) pos = mValue.size();
- if(pos == mValue.size())
- {
- second_nibble = FALSE;
- }
-}
-
-void DOHexEditor::changedLength()
-{
- S32 line_height = llround( mGLFont->getLineHeight() );
- S32 page_size = mTextRect.getHeight() / line_height;
- page_size -= 2; // don't count the spacer and header
-
- mScrollbar->setDocSize(getLineCount());
- mScrollbar->setPageSize(page_size);
-
- moveCursor(mCursorPos, mSecondNibble); // cursor was off end after undo of paste
-}
-
-void DOHexEditor::reshape(S32 width, S32 height, BOOL called_from_parent)
-{
- LLView::reshape( width, height, called_from_parent );
- mTextRect.setOriginAndSize(
- 5, // border + padding
- 1, // border
- getRect().getWidth() - SCROLLBAR_SIZE - 6,
- getRect().getHeight() - 5);
- LLRect scrollrect;
- scrollrect.setOriginAndSize(
- getRect().getWidth() - SCROLLBAR_SIZE,
- 1,
- SCROLLBAR_SIZE,
- getRect().getHeight() - 1);
- mScrollbar->setRect(scrollrect);
- mBorder->setRect(LLRect(0, getRect().getHeight(), getRect().getWidth(), 0));
- changedLength();
-}
-
-void DOHexEditor::setFocus(BOOL b)
-{
- if(b)
- {
- LLEditMenuHandler::gEditMenuHandler = this;
- }
- else
- {
- mSelecting = FALSE;
- gFocusMgr.releaseFocusIfNeeded(this);
- if(gEditMenuHandler == this)
- {
- gEditMenuHandler = NULL;
- }
- }
- LLUICtrl::setFocus(b);
-}
-
-F32 DOHexEditor::getSuggestedWidth()
-{
- F32 char_width = mGLFont->getWidthF32(".");
- F32 data_column_width = char_width * 3; // " 00";
- F32 text_x = mTextRect.mLeft;
- F32 text_x_data = text_x + (char_width * 10.1f); // "00000000 ", dunno why it's a fraction off
- F32 text_x_ascii = text_x_data + (data_column_width * mColumns) + (char_width * 2);
- F32 suggested_width = text_x_ascii + (char_width * mColumns);
- suggested_width += mScrollbar->getRect().getWidth();
- suggested_width += 10.0f;
- return suggested_width;
-}
-
-U32 DOHexEditor::getProperSelectionStart()
-{
- return (mSelectionStart < mSelectionEnd) ? mSelectionStart : mSelectionEnd;
-}
-
-U32 DOHexEditor::getProperSelectionEnd()
-{
- return (mSelectionStart < mSelectionEnd) ? mSelectionEnd : mSelectionStart;
-}
-
-BOOL DOHexEditor::handleScrollWheel(S32 x, S32 y, S32 clicks)
-{
- return mScrollbar->handleScrollWheel( 0, 0, clicks );
-}
-
-BOOL DOHexEditor::handleMouseDown(S32 x, S32 y, MASK mask)
-{
- BOOL handled = FALSE;
- handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL;
- if(!handled)
- {
- setFocus(TRUE);
- gFocusMgr.setMouseCapture(this);
- handled = TRUE;
- if(!mSelecting)
- {
- if(mask & MASK_SHIFT)
- {
- // extend a selection
- getPosAndContext(x, y, FALSE, mCursorPos, mInData, mSecondNibble);
- mSelectionEnd = mCursorPos;
- mHasSelection = (mSelectionStart != mSelectionEnd);
- mSelecting = TRUE;
- }
- else
- {
- // start selecting
- getPosAndContext(x, y, FALSE, mCursorPos, mInData, mSecondNibble);
- mSelectionStart = mCursorPos;
- mSelectionEnd = mCursorPos;
- mHasSelection = FALSE;
- mSelecting = TRUE;
- }
- }
- }
- return handled;
-}
-
-BOOL DOHexEditor::handleHover(S32 x, S32 y, MASK mask)
-{
- BOOL handled = FALSE;
- if(!hasMouseCapture())
- {
- handled = childrenHandleHover(x, y, mask) != NULL;
- }
- if(!handled && mSelecting && hasMouseCapture())
- {
- // continuation of selecting
- getPosAndContext(x, y, TRUE, mCursorPos, mInData, mSecondNibble);
- mSelectionEnd = mCursorPos;
- mHasSelection = (mSelectionStart != mSelectionEnd);
- handled = TRUE;
- }
- return handled;
-}
-
-BOOL DOHexEditor::handleMouseUp(S32 x, S32 y, MASK mask)
-{
- BOOL handled = FALSE;
- handled = LLView::childrenHandleMouseUp(x, y, mask) != NULL;
- if(!handled && mSelecting && hasMouseCapture())
- {
- gFocusMgr.setMouseCapture(NULL);
- mSelecting = FALSE;
- }
- return handled;
-}
-
-BOOL DOHexEditor::handleKeyHere(KEY key, MASK mask)
-{
- return FALSE;
-}
-
-BOOL DOHexEditor::handleKey(KEY key, MASK mask, BOOL called_from_parent)
-{
- BOOL handled = FALSE;
-
- BOOL moved_cursor = FALSE;
- U32 old_cursor = mCursorPos;
- U32 cursor_line = mCursorPos / mColumns;
- U32 doc_first_line = 0;
- U32 doc_last_line = mValue.size() / mColumns;
- //U32 first_line = mScrollbar->getDocPos();
- //U32 last_line = first_line + mScrollbar->getPageSize(); // don't -2 from scrollbar sizes
- U32 beginning_of_line = mCursorPos - (mCursorPos % mColumns);
- U32 end_of_line = beginning_of_line + mColumns - 1;
-
- handled = TRUE;
- switch( key )
- {
-
- // Movement keys
-
- case KEY_UP:
- if(cursor_line > doc_first_line)
- {
- moveCursor(mCursorPos - mColumns, mSecondNibble);
- moved_cursor = TRUE;
- }
- break;
- case KEY_DOWN:
- if(cursor_line < doc_last_line)
- {
- moveCursor(mCursorPos + mColumns, mSecondNibble);
- moved_cursor = TRUE;
- }
- break;
- case KEY_LEFT:
- if(mCursorPos)
- {
- if(!mSecondNibble) moveCursor(mCursorPos - 1, FALSE);
- else moveCursor(mCursorPos, FALSE);
- moved_cursor = TRUE;
- }
- break;
- case KEY_RIGHT:
- moveCursor(mCursorPos + 1, FALSE);
- moved_cursor = TRUE;
- break;
- case KEY_PAGE_UP:
- mScrollbar->pageUp(1);
- break;
- case KEY_PAGE_DOWN:
- mScrollbar->pageDown(1);
- break;
- case KEY_HOME:
- if(mask & MASK_CONTROL)
- moveCursor(0, FALSE);
- else
- moveCursor(beginning_of_line, FALSE);
- moved_cursor = TRUE;
- break;
- case KEY_END:
- if(mask & MASK_CONTROL)
- moveCursor(mValue.size(), FALSE);
- else
- moveCursor(end_of_line, FALSE);
- moved_cursor = TRUE;
- break;
-
- // Special
-
- case KEY_INSERT:
- gKeyboard->toggleInsertMode();
- break;
-
- case KEY_ESCAPE:
- gFocusMgr.releaseFocusIfNeeded(this);
- break;
-
- // Editing
- case KEY_BACKSPACE:
- if(mHasSelection)
- {
- U32 start = getProperSelectionStart();
- U32 end = getProperSelectionEnd();
- del(start, end - 1, TRUE);
- moveCursor(start, FALSE);
- }
- else if(mCursorPos && (!mSecondNibble))
- {
- del(mCursorPos - 1, mCursorPos - 1, TRUE);
- moveCursor(mCursorPos - 1, FALSE);
- }
- break;
-
- case KEY_DELETE:
- if(mHasSelection)
- {
- U32 start = getProperSelectionStart();
- U32 end = getProperSelectionEnd();
- del(start, end - 1, TRUE);
- moveCursor(start, FALSE);
- }
- else if((mCursorPos != mValue.size()) && (!mSecondNibble))
- {
- del(mCursorPos, mCursorPos, TRUE);
- }
- break;
-
- default:
- handled = FALSE;
- break;
- }
-
- if(moved_cursor)
- {
- // Selecting and deselecting
- if(mask & MASK_SHIFT)
- {
- if(!mHasSelection) mSelectionStart = old_cursor;
- mSelectionEnd = mCursorPos;
- }
- else
- {
- mSelectionStart = mCursorPos;
- mSelectionEnd = mCursorPos;
- }
- mHasSelection = mSelectionStart != mSelectionEnd;
- }
-
- return handled;
-}
-
-BOOL DOHexEditor::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
-{
- U8 c = uni_char & 0xff;
- if(mInData)
- {
- if(c > 0x39)
- {
- if(c > 0x46) c -= 0x20;
- if(c >= 0x41 && c <= 0x46) c = (c & 0x0f) + 0x09;
- else return TRUE;
- }
- else if(c < 0x30) return TRUE;
- else c &= 0x0f;
- }
-
- if(uni_char < 0x20) return FALSE;
-
- if( (LL_KIM_INSERT == gKeyboard->getInsertMode() && (!mHasSelection))
- || (!mHasSelection && (mCursorPos == mValue.size())) )// last byte? always insert
- {
- // Todo: this should overwrite if there's a selection
- if(!mInData)
- {
- std::vector new_data;
- new_data.push_back(c);
- insert(mCursorPos, new_data, TRUE);
- moveCursor(mCursorPos + 1, FALSE);
- }
- else if(!mSecondNibble)
- {
- c <<= 4;
- std::vector new_data;
- new_data.push_back(c);
- insert(mCursorPos, new_data, TRUE);
- moveCursor(mCursorPos, TRUE);
- }
- else
- {
- c |= (mValue[mCursorPos] & 0xF0);
- std::vector new_data;
- new_data.push_back(c);
- overwrite(mCursorPos, mCursorPos, new_data, TRUE);
- moveCursor(mCursorPos + 1, FALSE);
- }
- }
- else // overwrite mode
- {
- if(mHasSelection)
- {
- if(mInData) c <<= 4;
- std::vector new_data;
- new_data.push_back(c);
- U8 start = getProperSelectionStart();
- overwrite(start, getProperSelectionEnd() - 1, new_data, TRUE);
- if(mInData) moveCursor(start, TRUE); // we only entered a nibble
- else moveCursor(start + 1, FALSE); // we only entered a byte
- }
- else if(!mInData)
- {
- std::vector new_data;
- new_data.push_back(c);
- overwrite(mCursorPos, mCursorPos, new_data, TRUE);
- moveCursor(mCursorPos + 1, FALSE);
- }
- else if(!mSecondNibble)
- {
- c <<= 4;
- c |= (mValue[mCursorPos] & 0x0F);
- std::vector new_data;
- new_data.push_back(c);
- overwrite(mCursorPos, mCursorPos, new_data, TRUE);
- moveCursor(mCursorPos, TRUE);
- }
- else
- {
- c |= (mValue[mCursorPos] & 0xF0);
- std::vector new_data;
- new_data.push_back(c);
- overwrite(mCursorPos, mCursorPos, new_data, TRUE);
- moveCursor(mCursorPos + 1, FALSE);
- }
- }
-
- return TRUE;
-}
-
-BOOL DOHexEditor::handleUnicodeCharHere(llwchar uni_char)
-{
- return FALSE;
-}
-
-void DOHexEditor::draw()
-{
- S32 left = 0;
- S32 top = getRect().getHeight();
- S32 right = getRect().getWidth();
- S32 bottom = 0;
-
- BOOL has_focus = gFocusMgr.getKeyboardFocus() == this;
-
-
- F32 line_height = mGLFont->getLineHeight();
- F32 char_width = mGLFont->getWidthF32(".");
- F32 data_column_width = char_width * 3; // " 00";
- F32 text_x = mTextRect.mLeft;
- F32 text_x_data = text_x + (char_width * 10.1f); // "00000000 ", dunno why it's a fraction off
- F32 text_x_ascii = text_x_data + (data_column_width * mColumns) + (char_width * 2);
- F32 text_y = (F32)(mTextRect.mTop - line_height);
-
- U32 data_length = mValue.size();
- U32 line_count = getLineCount();
- U32 first_line = mScrollbar->getDocPos();
- U32 last_line = first_line + mScrollbar->getPageSize(); // don't -2 from scrollbar sizes
-
- LLRect clip(getRect());
- clip.mRight = mScrollbar->getRect().mRight;
- clip.mLeft -= 10;
- clip.mBottom -= 10;
- LLLocalClipRect bgclip(clip);
-
- // Background
- gl_rect_2d(left, top, right, bottom, LLColor4::white);
-
- // Let's try drawing some helpful guides
- LLColor4 guide_color_light = LLColor4(1.0f, 1.0f, 0.9f);
- LLColor4 guide_color_dark = LLColor4(1.0f, 1.0f, 0.8f);
- for(U32 col = 0; col < mColumns; col += 2)
- {
- // Behind hex
- F32 box_left = text_x_data + (col * data_column_width) + 2; // skew 2
- F32 box_right = box_left + data_column_width;
- gl_rect_2d(box_left, top, box_right, bottom, (col & 3) ? guide_color_light : guide_color_dark);
- // Behind ASCII
- //box_left = text_x_ascii + (col * char_width) - 1; // skew 1
- //box_right = box_left + char_width;
- //gl_rect_2d(box_left, top, box_right, bottom, guide_color);
- }
-
-
- // Scrollbar & border (drawn twice?)
- mBorder->setKeyboardFocusHighlight(has_focus);
- LLView::draw();
-
-
- LLLocalClipRect textrect_clip(mTextRect);
-
-
- // Selection stuff is reused
- U32 selection_start = getProperSelectionStart();
- U32 selection_end = getProperSelectionEnd();
- U32 selection_first_line = selection_start / mColumns;
- U32 selection_last_line = selection_end / mColumns;
- U32 selection_start_column = selection_start % mColumns;
- U32 selection_end_column = selection_end % mColumns;
-
- // Don't pretend a selection there is visible
- if(!selection_end_column)
- {
- selection_last_line--;
- selection_end_column = mColumns;
- }
-
- if(mHasSelection)
- {
- LLColor4 selection_color_context(LLColor4::black);
- LLColor4 selection_color_not_context(LLColor4::grey3);
- LLColor4 selection_color_data(selection_color_not_context);
- LLColor4 selection_color_ascii(selection_color_not_context);
- if(mInData) selection_color_data = selection_color_context;
- else selection_color_ascii = selection_color_context;
-
-
- // Setup for selection in data
- F32 selection_pixel_x_base = text_x_data + char_width - 3; // skew 3
- F32 selection_pixel_x_right_base = selection_pixel_x_base + (data_column_width * mColumns) - char_width + 4;
- F32 selection_pixel_x;
- F32 selection_pixel_x_right;
- F32 selection_pixel_y = (F32)(mTextRect.mTop - line_height) - 3; // skew 3;
- selection_pixel_y -= line_height * 2;
- selection_pixel_y -= line_height * (S32(selection_first_line) - S32(first_line));
-
- // Selection in data, First line
- if(selection_first_line >= first_line && selection_first_line <= last_line)
- {
- selection_pixel_x = selection_pixel_x_base;
- selection_pixel_x += (data_column_width * selection_start_column);
- if(selection_first_line == selection_last_line)
- {
- // Select to last character
- selection_pixel_x_right = selection_pixel_x_base + (data_column_width * selection_end_column);
- selection_pixel_x_right -= (char_width - 4);
- }
- else
- {
- // Select to end of line
- selection_pixel_x_right = selection_pixel_x_right_base;
- }
- gl_rect_2d(selection_pixel_x, selection_pixel_y + line_height, selection_pixel_x_right, selection_pixel_y, selection_color_data);
- }
-
- // Selection in data, Middle lines
- for(U32 line = selection_first_line + 1; line < selection_last_line; line++)
- {
- selection_pixel_y -= line_height;
- if(line >= first_line && line <= last_line)
- {
- gl_rect_2d(selection_pixel_x_base, selection_pixel_y + line_height, selection_pixel_x_right_base, selection_pixel_y, selection_color_data);
- }
- }
-
- // Selection in data, Last line
- if(selection_first_line != selection_last_line
- && selection_last_line >= first_line && selection_last_line <= last_line)
- {
- selection_pixel_x_right = selection_pixel_x_base + (data_column_width * selection_end_column);
- selection_pixel_x_right -= (char_width - 4);
- selection_pixel_y -= line_height;
- gl_rect_2d(selection_pixel_x_base, selection_pixel_y + line_height, selection_pixel_x_right, selection_pixel_y, selection_color_data);
- }
-
- selection_pixel_y = (F32)(mTextRect.mTop - line_height) - 3; // skew 3;
- selection_pixel_y -= line_height * 2;
- selection_pixel_y -= line_height * (S32(selection_first_line) - S32(first_line));
-
- // Setup for selection in ASCII
- selection_pixel_x_base = text_x_ascii - 1;
- selection_pixel_x_right_base = selection_pixel_x_base + (char_width * mColumns);
-
- // Selection in ASCII, First line
- if(selection_first_line >= first_line && selection_first_line <= last_line)
- {
- selection_pixel_x = selection_pixel_x_base;
- selection_pixel_x += (char_width * selection_start_column);
- if(selection_first_line == selection_last_line)
- {
- // Select to last character
- selection_pixel_x_right = selection_pixel_x_base + (char_width * selection_end_column);
- }
- else
- {
- // Select to end of line
- selection_pixel_x_right = selection_pixel_x_right_base;
- }
- gl_rect_2d(selection_pixel_x, selection_pixel_y + line_height, selection_pixel_x_right, selection_pixel_y, selection_color_ascii);
- }
-
- // Selection in ASCII, Middle lines
- for(U32 line = selection_first_line + 1; line < selection_last_line; line++)
- {
- selection_pixel_y -= line_height;
- if(line >= first_line && line <= last_line)
- {
- gl_rect_2d(selection_pixel_x_base, selection_pixel_y + line_height, selection_pixel_x_right_base, selection_pixel_y, selection_color_ascii);
- }
- }
-
- // Selection in ASCII, Last line
- if(selection_first_line != selection_last_line
- && selection_last_line >= first_line && selection_last_line <= last_line)
- {
- selection_pixel_x_right = selection_pixel_x_base + (char_width * selection_end_column);
- selection_pixel_y -= line_height;
- gl_rect_2d(selection_pixel_x_base, selection_pixel_y + line_height, selection_pixel_x_right, selection_pixel_y, selection_color_ascii);
- }
- }
-
-
- // Insert/Overwrite
- std::string text = (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) ? "OVERWRITE" : "INSERT";
- mGLFont->renderUTF8(text, 0, text_x, text_y, LLColor4::purple);
- // Offset on top
- text = "";
- for(U32 i = 0; i < mColumns; i++)
- {
- text.append(llformat(" %02X", i));
- }
- mGLFont->renderUTF8(text, 0, text_x_data, text_y, LLColor4::blue);
- // Size
- {
- S32 size = mValue.size();
- std::string size_desc;
- if(size < 1000) size_desc = llformat("%d bytes", size);
- else
- {
- if(size < 1000000)
- {
- size_desc = llformat("%f", F32(size) / 1000.0f);
- int i = size_desc.length() - 1;
- for(; i && size_desc.substr(i, 1) == "0"; i--);
- if(size_desc.substr(i, 1) == ".") i--;
- size_desc = size_desc.substr(0, i + 1);
- size_desc.append(" KB");
- }
- else
- {
- size_desc = llformat("%f", F32(size) / 1000000.0f);
- int i = size_desc.length() - 1;
- for(; i && size_desc.substr(i, 1) == "0"; i--);
- if(size_desc.substr(i, 1) == ".") i--;
- size_desc = size_desc.substr(0, i + 1);
- size_desc.append(" MB");
- }
- }
- F32 x = text_x_ascii;
- x += (char_width * (mColumns - size_desc.length()));
- mGLFont->renderUTF8(size_desc, 0, x, text_y, LLColor4::purple);
- }
- // Leave a blank line
- text_y -= (line_height * 2);
-
- // Everything below "header"
- for(U32 line = first_line; line <= last_line; line++)
- {
- if(line >= line_count) break;
-
- // Offset on left
- text = llformat("%08X", line * mColumns); // offset on left
- mGLFont->renderUTF8(text, 0, text_x, text_y, LLColor4::blue);
-
- // Setup for rendering hex and ascii
- U32 line_char_offset = mColumns * line;
- U32 colstart0 = 0;
- U32 colend0 = mColumns;
- U32 colstart1 = mColumns;
- U32 colend1 = mColumns;
- U32 colstart2 = mColumns;
- U32 colend2 = mColumns;
- if(mHasSelection)
- {
- if(line == selection_first_line)
- {
- colend0 = selection_start_column;
- colstart1 = selection_start_column;
- if(selection_first_line == selection_last_line)
- {
- colend1 = selection_end_column;
- colstart2 = selection_end_column;
- colend2 = mColumns;
- }
- }
- else if(line > selection_first_line && line < selection_last_line)
- {
- colend0 = 0;
- colstart1 = 0;
- colend1 = mColumns;
- }
- else if(line == selection_last_line)
- {
- colend0 = 0;
- colstart1 = 0;
- colend1 = selection_end_column;
- colstart2 = selection_end_column;
- colend2 = mColumns;
- }
- }
-
- // Data in hex
- text = "";
- for(U32 c = colstart0; c < colend0; c++)
- {
- U32 o = line_char_offset + c;
- if(o >= data_length) text.append(" ");
- else text.append(llformat(" %02X", mValue[o]));
- }
- mGLFont->renderUTF8(text, 0, text_x_data + (colstart0 * data_column_width), text_y, LLColor4::black);
- text = "";
- for(U32 c = colstart1; c < colend1; c++)
- {
- U32 o = line_char_offset + c;
- if(o >= data_length) text.append(" ");
- else text.append(llformat(" %02X", mValue[o]));
- }
- mGLFont->renderUTF8(text, 0, text_x_data + (colstart1 * data_column_width), text_y, LLColor4::white);
- text = "";
- for(U32 c = colstart2; c < colend2; c++)
- {
- U32 o = line_char_offset + c;
- if(o >= data_length) text.append(" ");
- else text.append(llformat(" %02X", mValue[o]));
- }
- mGLFont->renderUTF8(text, 0, text_x_data + (colstart2 * data_column_width), text_y, LLColor4::black);
-
- // ASCII
- text = "";
- for(U32 c = colstart0; c < colend0; c++)
- {
- U32 o = line_char_offset + c;
- if(o >= data_length) break;
- if((mValue[o] < 0x20) || (mValue[o] >= 0x7F)) text.append(".");
- else text.append(llformat("%c", mValue[o]));
- }
- mGLFont->renderUTF8(text, 0, text_x_ascii + (colstart0 * char_width), text_y, LLColor4::black);
- text = "";
- for(U32 c = colstart1; c < colend1; c++)
- {
- U32 o = line_char_offset + c;
- if(o >= data_length) break;
- if((mValue[o] < 0x20) || (mValue[o] >= 0x7F)) text.append(".");
- else text.append(llformat("%c", mValue[o]));
- }
- mGLFont->renderUTF8(text, 0, text_x_ascii + (colstart1 * char_width), text_y, LLColor4::white);
- text = "";
- for(U32 c = colstart2; c < colend2; c++)
- {
- U32 o = line_char_offset + c;
- if(o >= data_length) break;
- if((mValue[o] < 0x20) || (mValue[o] >= 0x7F)) text.append(".");
- else text.append(llformat("%c", mValue[o]));
- }
- mGLFont->renderUTF8(text, 0, text_x_ascii + (colstart2 * char_width), text_y, LLColor4::black);
-
- text_y -= line_height;
- }
-
-
-
- // Cursor
- if(has_focus && !mHasSelection && (U32(LLTimer::getElapsedSeconds() * 2.0f) & 0x1))
- {
- U32 cursor_line = mCursorPos / mColumns;
- if((cursor_line >= first_line) && (cursor_line <= last_line))
- {
- F32 pixel_y = (F32)(mTextRect.mTop - line_height);
- pixel_y -= line_height * (2 + (cursor_line - first_line));
-
- U32 cursor_offset = mCursorPos % mColumns; // bytes
- F32 pixel_x = mInData ? text_x_data : text_x_ascii;
- if(mInData)
- {
- pixel_x += data_column_width * cursor_offset;
- pixel_x += char_width;
- if(mSecondNibble) pixel_x += char_width;
- }
- else
- {
- pixel_x += char_width * cursor_offset;
- }
- pixel_x -= 2.0f;
- pixel_y -= 2.0f;
- gl_rect_2d(pixel_x, pixel_y + line_height, pixel_x + 2, pixel_y, LLColor4::black);
- }
- }
-}
-
-void DOHexEditor::deselect()
-{
- mSelectionStart = mCursorPos;
- mSelectionEnd = mCursorPos;
- mHasSelection = FALSE;
- mSelecting = FALSE;
-}
-
-BOOL DOHexEditor::canUndo() const
-{
- return mUndoBuffer->canUndo();
-}
-
-void DOHexEditor::undo()
-{
- mUndoBuffer->undoAction();
-}
-
-BOOL DOHexEditor::canRedo() const
-{
- return mUndoBuffer->canRedo();
-}
-
-void DOHexEditor::redo()
-{
- mUndoBuffer->redoAction();
-}
-
-
-
-
-void DOHexEditor::moveCursor(U32 pos, BOOL second_nibble)
-{
- mCursorPos = pos;
-
- // Clamp and handle second nibble
- if(mCursorPos >= mValue.size())
- {
- mCursorPos = mValue.size();
- mSecondNibble = FALSE;
- }
- else
- {
- mSecondNibble = mInData ? second_nibble : FALSE;
- }
-
- // Change selection
- mSelectionEnd = mCursorPos;
- if(!mHasSelection) mSelectionStart = mCursorPos;
-
- // Scroll
- U32 line = mCursorPos / mColumns;
- U32 first_line = mScrollbar->getDocPos();
- U32 last_line = first_line + mScrollbar->getPageSize(); // don't -2 from scrollbar sizes
- if(line < first_line) mScrollbar->setDocPos(line);
- if(line > (last_line - 2)) mScrollbar->setDocPos(line - mScrollbar->getPageSize() + 1);
-}
-
-BOOL DOHexEditor::canCut() const
-{
- return mHasSelection;
-}
-
-void DOHexEditor::cut()
-{
- if(!canCut()) return;
-
- copy();
-
- U32 start = getProperSelectionStart();
- del(start, getProperSelectionEnd() - 1, TRUE);
-
- moveCursor(start, FALSE);
-}
-
-BOOL DOHexEditor::canCopy() const
-{
- return mHasSelection;
-}
-
-void DOHexEditor::copy()
-{
- if(!canCopy()) return;
-
- std::string text;
- if(mInData)
- {
- U32 start = getProperSelectionStart();
- U32 end = getProperSelectionEnd();
- for(U32 i = start; i < end; i++)
- text.append(llformat("%02X", mValue[i]));
- }
- else
- {
- U32 start = getProperSelectionStart();
- U32 end = getProperSelectionEnd();
- for(U32 i = start; i < end; i++)
- text.append(llformat("%c", mValue[i]));
- }
- LLWString wtext = utf8str_to_wstring(text);
- gClipboard.copyFromSubstring(wtext, 0, wtext.length());
-}
-
-BOOL DOHexEditor::canPaste() const
-{
- return TRUE;
-}
-
-void DOHexEditor::paste()
-{
- if(!canPaste()) return;
-
- std::string clipstr = wstring_to_utf8str(gClipboard.getPasteWString());
- const char* clip = clipstr.c_str();
-
- std::vector new_data;
- if(mInData)
- {
- int len = strlen(clip);
- for(int i = 0; (i + 1) < len; i += 2)
- {
- int c = 0;
- if(sscanf(&(clip[i]), "%02X", &c) != 1) break;
- new_data.push_back(U8(c));
- }
- }
- else
- {
- int len = strlen(clip);
- for(int i = 0; i < len; i++)
- {
- U8 c = 0;
- if(sscanf(&(clip[i]), "%c", &c) != 1) break;
- new_data.push_back(c);
- }
- }
-
- U32 start = mCursorPos;
- if(!mHasSelection)
- insert(start, new_data, TRUE);
- else
- {
- start = getProperSelectionStart();
- overwrite(start, getProperSelectionEnd() - 1, new_data, TRUE);
- }
-
- moveCursor(start + new_data.size(), FALSE);
-}
-
-BOOL DOHexEditor::canDoDelete() const
-{
- return mValue.size() > 0;
-}
-
-void DOHexEditor::doDelete()
-{
- if(!canDoDelete()) return;
-
- U32 start = getProperSelectionStart();
- del(start, getProperSelectionEnd(), TRUE);
-
- moveCursor(start, FALSE);
-}
-
-BOOL DOHexEditor::canSelectAll() const
-{
- return mValue.size() > 0;
-}
-
-void DOHexEditor::selectAll()
-{
- if(!canSelectAll()) return;
-
- mSelectionStart = 0;
- mSelectionEnd = mValue.size();
- mHasSelection = mSelectionStart != mSelectionEnd;
-}
-
-BOOL DOHexEditor::canDeselect() const
-{
- return mHasSelection;
-}
-
-void DOHexEditor::insert(U32 pos, std::vector new_data, BOOL undoable)
-{
- if(pos > mValue.size())
- {
- llwarns << "pos outside data!" << llendl;
- return;
- }
-
- deselect();
-
- if(undoable)
- {
- DOUndoHex* action = (DOUndoHex*)(mUndoBuffer->getNextAction());
- action->set(this, &(DOUndoHex::undoInsert), &(DOUndoHex::redoInsert), pos, pos, std::vector(), new_data);
- }
-
- std::vector::iterator wheres = mValue.begin() + pos;
-
- mValue.insert(wheres, new_data.begin(), new_data.end());
-
- changedLength();
-}
-
-void DOHexEditor::overwrite(U32 first_pos, U32 last_pos, std::vector new_data, BOOL undoable)
-{
- if(first_pos > mValue.size() || last_pos > mValue.size())
- {
- llwarns << "pos outside data!" << llendl;
- return;
- }
-
- deselect();
-
- std::vector::iterator first = mValue.begin() + first_pos;
- std::vector::iterator last = mValue.begin() + last_pos;
-
- std::vector old_data;
- if(last_pos > 0) old_data = std::vector(first, last + 1);
-
- if(undoable)
- {
- DOUndoHex* action = (DOUndoHex*)(mUndoBuffer->getNextAction());
- action->set(this, &(DOUndoHex::undoOverwrite), &(DOUndoHex::redoOverwrite), first_pos, last_pos, old_data, new_data);
- }
-
- mValue.erase(first, last + 1);
- first = mValue.begin() + first_pos;
- mValue.insert(first, new_data.begin(), new_data.end());
-
- changedLength();
-}
-
-void DOHexEditor::del(U32 first_pos, U32 last_pos, BOOL undoable)
-{
- if(first_pos > mValue.size() || last_pos > mValue.size())
- {
- llwarns << "pos outside data!" << llendl;
- return;
- }
-
- deselect();
-
- std::vector::iterator first = mValue.begin() + first_pos;
- std::vector::iterator last = mValue.begin() + last_pos;
-
- std::vector old_data;
- if(last_pos > 0) old_data = std::vector(first, last + 1);
-
- if(undoable)
- {
- DOUndoHex* action = (DOUndoHex*)(mUndoBuffer->getNextAction());
- action->set(this, &(DOUndoHex::undoDel), &(DOUndoHex::redoDel), first_pos, last_pos, old_data, std::vector());
- }
-
- mValue.erase(first, last + 1);
-
- changedLength();
-}
-
-void DOUndoHex::set(DOHexEditor* hex_editor,
- void (*undo_action)(DOUndoHex*),
- void (*redo_action)(DOUndoHex*),
- U32 first_pos,
- U32 last_pos,
- std::vector old_data,
- std::vector new_data)
-{
- mHexEditor = hex_editor;
- mUndoAction = undo_action;
- mRedoAction = redo_action;
- mFirstPos = first_pos;
- mLastPos = last_pos;
- mOldData = old_data;
- mNewData = new_data;
-}
-
-void DOUndoHex::undo()
-{
- mUndoAction(this);
-}
-
-void DOUndoHex::redo()
-{
- mRedoAction(this);
-}
-
-void DOUndoHex::undoInsert(DOUndoHex* action)
-{
- //action->mHexEditor->del(action->mFirstPos, action->mLastPos, FALSE);
- action->mHexEditor->del(action->mFirstPos, action->mFirstPos + action->mNewData.size() - 1, FALSE);
-}
-
-void DOUndoHex::redoInsert(DOUndoHex* action)
-{
- action->mHexEditor->insert(action->mFirstPos, action->mNewData, FALSE);
-}
-
-void DOUndoHex::undoOverwrite(DOUndoHex* action)
-{
- //action->mHexEditor->overwrite(action->mFirstPos, action->mLastPos, action->mOldData, FALSE);
- action->mHexEditor->overwrite(action->mFirstPos, action->mFirstPos + action->mNewData.size() - 1, action->mOldData, FALSE);
-}
-
-void DOUndoHex::redoOverwrite(DOUndoHex* action)
-{
- action->mHexEditor->overwrite(action->mFirstPos, action->mLastPos, action->mNewData, FALSE);
-}
-
-void DOUndoHex::undoDel(DOUndoHex* action)
-{
- action->mHexEditor->insert(action->mFirstPos, action->mOldData, FALSE);
-}
-
-void DOUndoHex::redoDel(DOUndoHex* action)
-{
- action->mHexEditor->del(action->mFirstPos, action->mLastPos, FALSE);
-}
-
-
-//
+/**
+ * @file dohexeditor.cpp
+ * @brief DOHexEditor Widget
+ * @author Day Oh
+ *
+ * $LicenseInfo:firstyear=2009&license=WTFPLV2$
+ *
+ */
+
+//
+#include "llviewerprecompiledheaders.h"
+
+#include "linden_common.h"
+#include "dohexeditor.h"
+#include "llfocusmgr.h"
+#include "llkeyboard.h"
+#include "llclipboard.h"
+#include "llwindow.h" // setCursor
+#include "lllocalinventory.h"
+
+static LLRegisterWidget r("hex_editor");
+
+DOHexEditor::DOHexEditor(const std::string& name, const LLRect& rect)
+: LLUICtrl(name, rect, TRUE, NULL, NULL),
+ LLEditMenuHandler(),
+ mColumns(16),
+ mCursorPos(0),
+ mSecondNibble(FALSE),
+ mSelecting(FALSE),
+ mHasSelection(FALSE),
+ mInData(FALSE),
+ mSelectionStart(0),
+ mSelectionEnd(0)
+{
+ mGLFont = LLFontGL::getFontMonospace();
+
+ mTextRect.setOriginAndSize(
+ 5, // border + padding
+ 1, // border
+ getRect().getWidth() - SCROLLBAR_SIZE - 6,
+ getRect().getHeight() - 5);
+
+ S32 line_height = llround( mGLFont->getLineHeight() );
+ S32 page_size = mTextRect.getHeight() / line_height;
+
+ // Init the scrollbar
+ LLRect scroll_rect;
+ scroll_rect.setOriginAndSize(
+ getRect().getWidth() - SCROLLBAR_SIZE,
+ 1,
+ SCROLLBAR_SIZE,
+ getRect().getHeight() - 1);
+ S32 lines_in_doc = getLineCount();
+ mScrollbar = new LLScrollbar( std::string("Scrollbar"), scroll_rect,
+ LLScrollbar::VERTICAL,
+ lines_in_doc,
+ 0,
+ page_size,
+ NULL, this );
+ mScrollbar->setFollowsRight();
+ mScrollbar->setFollowsTop();
+ mScrollbar->setFollowsBottom();
+ mScrollbar->setEnabled( TRUE );
+ mScrollbar->setVisible( TRUE );
+ mScrollbar->setOnScrollEndCallback(NULL, NULL);
+ addChild(mScrollbar);
+
+ mBorder = new LLViewBorder( std::string("text ed border"),
+ LLRect(0, getRect().getHeight(), getRect().getWidth(), 0),
+ LLViewBorder::BEVEL_IN,
+ LLViewBorder::STYLE_LINE,
+ 1 ); // border width
+ addChild( mBorder );
+
+ changedLength();
+
+ mUndoBuffer = new LLUndoBuffer(DOUndoHex::create, 128);
+}
+
+DOHexEditor::~DOHexEditor()
+{
+ gFocusMgr.releaseFocusIfNeeded(this);
+ if(gEditMenuHandler == this)
+ {
+ gEditMenuHandler = NULL;
+ }
+}
+
+LLView* DOHexEditor::fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFactory *factory)
+{
+ std::string name("text_editor");
+ node->getAttributeString("name", name);
+
+ LLRect rect;
+ createRect(node, rect, parent, LLRect());
+
+ DOHexEditor* editor = new DOHexEditor(name, rect);
+
+ editor->initFromXML(node, parent);
+
+ return editor;
+}
+
+void DOHexEditor::setValue(const LLSD& value)
+{
+ mValue = value.asBinary();
+ changedLength();
+}
+
+LLSD DOHexEditor::getValue() const
+{
+ return LLSD(mValue);
+}
+
+void DOHexEditor::setColumns(U8 columns)
+{
+ //mColumns = columns;
+ mColumns = llclamp(llfloor(columns), 8, 64); //clamp this ffs
+ changedLength();
+}
+
+U32 DOHexEditor::getLineCount()
+{
+ U32 lines = mValue.size();
+ lines /= mColumns;
+ lines++; // incomplete or extra line at bottom
+ return lines;
+}
+
+void DOHexEditor::getPosAndContext(S32 x, S32 y, BOOL force_context, U32& pos, BOOL& in_data, BOOL& second_nibble)
+{
+ pos = 0;
+
+ F32 line_height = mGLFont->getLineHeight();
+ F32 char_width = mGLFont->getWidthF32(".");
+ F32 data_column_width = char_width * 3; // " 00";
+ F32 text_x = mTextRect.mLeft;
+ F32 text_x_data = text_x + (char_width * 10.1f); // "00000000 ", dunno why it's a fraction off
+ F32 text_x_ascii = text_x_data + (data_column_width * mColumns) + (char_width * 2);
+ F32 text_y = (F32)(mTextRect.mTop - line_height);
+ U32 first_line = mScrollbar->getDocPos();
+ //U32 last_line = first_line + mScrollbar->getPageSize(); // don't -2 from scrollbar sizes
+ S32 first_line_y = text_y - line_height;
+
+ S32 ly = -(y - first_line_y); // negative vector from first line to y
+ ly -= 5; // slight skew
+ S32 line = ly / line_height;
+ if(line < 0) line = 0;
+ line += first_line;
+
+ if(!force_context)
+ {
+ in_data = (x < (text_x_ascii - char_width)); // char width for less annoying
+ }
+ S32 lx = x;
+ S32 offset;
+ if(in_data)
+ {
+ lx -= char_width; // subtracting char width because idk
+ lx -= text_x_data;
+ offset = lx / data_column_width;
+
+ // Now, which character
+ S32 rem = S32( (F32)lx - (data_column_width * offset) - (char_width * 0.25) );
+ if(rem > 0)
+ {
+ if(rem > char_width)
+ {
+ offset++; // next byte
+ second_nibble = FALSE;
+ }
+ else second_nibble = TRUE;
+ }
+ else second_nibble = FALSE;
+ }
+ else
+ {
+ second_nibble = FALSE;
+ lx += char_width; // adding char width because idk
+ lx -= text_x_ascii;
+ offset = lx / char_width;
+ }
+ if(offset < 0) offset = 0;
+ if(offset >= mColumns)//offset = mColumns - 1;
+ {
+ offset = 0;
+ line++;
+ second_nibble = FALSE;
+ }
+
+ pos = (line * mColumns) + offset;
+ if(pos < 0) pos = 0;
+ if(pos > mValue.size()) pos = mValue.size();
+ if(pos == mValue.size())
+ {
+ second_nibble = FALSE;
+ }
+}
+
+void DOHexEditor::changedLength()
+{
+ S32 line_height = llround( mGLFont->getLineHeight() );
+ S32 page_size = mTextRect.getHeight() / line_height;
+ page_size -= 2; // don't count the spacer and header
+
+ mScrollbar->setDocSize(getLineCount());
+ mScrollbar->setPageSize(page_size);
+
+ moveCursor(mCursorPos, mSecondNibble); // cursor was off end after undo of paste
+}
+
+void DOHexEditor::reshape(S32 width, S32 height, BOOL called_from_parent)
+{
+ LLView::reshape( width, height, called_from_parent );
+ mTextRect.setOriginAndSize(
+ 5, // border + padding
+ 1, // border
+ getRect().getWidth() - SCROLLBAR_SIZE - 6,
+ getRect().getHeight() - 5);
+ LLRect scrollrect;
+ scrollrect.setOriginAndSize(
+ getRect().getWidth() - SCROLLBAR_SIZE,
+ 1,
+ SCROLLBAR_SIZE,
+ getRect().getHeight() - 1);
+ mScrollbar->setRect(scrollrect);
+ mBorder->setRect(LLRect(0, getRect().getHeight(), getRect().getWidth(), 0));
+ changedLength();
+}
+
+void DOHexEditor::setFocus(BOOL b)
+{
+ if(b)
+ {
+ LLEditMenuHandler::gEditMenuHandler = this;
+ }
+ else
+ {
+ mSelecting = FALSE;
+ gFocusMgr.releaseFocusIfNeeded(this);
+ if(gEditMenuHandler == this)
+ {
+ gEditMenuHandler = NULL;
+ }
+ }
+ LLUICtrl::setFocus(b);
+}
+
+F32 DOHexEditor::getSuggestedWidth(U8 cols)
+{
+ cols = cols>1?cols:mColumns;
+ F32 char_width = mGLFont->getWidthF32(".");
+ F32 data_column_width = char_width * 3; // " 00";
+ F32 text_x = mTextRect.mLeft;
+ F32 text_x_data = text_x + (char_width * 10.1f); // "00000000 ", dunno why it's a fraction off
+ F32 text_x_ascii = text_x_data + (data_column_width * cols) + (char_width * 2);
+ F32 suggested_width = text_x_ascii + (char_width * cols);
+ suggested_width += mScrollbar->getRect().getWidth();
+ suggested_width += 10.0f;
+ return suggested_width;
+}
+
+U32 DOHexEditor::getProperSelectionStart()
+{
+ return (mSelectionStart < mSelectionEnd) ? mSelectionStart : mSelectionEnd;
+}
+
+U32 DOHexEditor::getProperSelectionEnd()
+{
+ return (mSelectionStart < mSelectionEnd) ? mSelectionEnd : mSelectionStart;
+}
+
+BOOL DOHexEditor::handleScrollWheel(S32 x, S32 y, S32 clicks)
+{
+ return mScrollbar->handleScrollWheel( 0, 0, clicks );
+}
+
+BOOL DOHexEditor::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+ BOOL handled = FALSE;
+ handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL;
+ if(!handled)
+ {
+ setFocus(TRUE);
+ gFocusMgr.setMouseCapture(this);
+ handled = TRUE;
+ if(!mSelecting)
+ {
+ if(mask & MASK_SHIFT)
+ {
+ // extend a selection
+ getPosAndContext(x, y, FALSE, mCursorPos, mInData, mSecondNibble);
+ mSelectionEnd = mCursorPos;
+ mHasSelection = (mSelectionStart != mSelectionEnd);
+ mSelecting = TRUE;
+ }
+ else
+ {
+ // start selecting
+ getPosAndContext(x, y, FALSE, mCursorPos, mInData, mSecondNibble);
+ mSelectionStart = mCursorPos;
+ mSelectionEnd = mCursorPos;
+ mHasSelection = FALSE;
+ mSelecting = TRUE;
+ }
+ }
+ }
+ return handled;
+}
+
+BOOL DOHexEditor::handleHover(S32 x, S32 y, MASK mask)
+{
+ BOOL handled = FALSE;
+ if(!hasMouseCapture())
+ {
+ handled = childrenHandleHover(x, y, mask) != NULL;
+ }
+ if(!handled && mSelecting && hasMouseCapture())
+ {
+ // continuation of selecting
+ getPosAndContext(x, y, TRUE, mCursorPos, mInData, mSecondNibble);
+ mSelectionEnd = mCursorPos;
+ mHasSelection = (mSelectionStart != mSelectionEnd);
+ handled = TRUE;
+ }
+ return handled;
+}
+
+BOOL DOHexEditor::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+ BOOL handled = FALSE;
+ handled = LLView::childrenHandleMouseUp(x, y, mask) != NULL;
+ if(!handled && mSelecting && hasMouseCapture())
+ {
+ gFocusMgr.setMouseCapture(NULL);
+ mSelecting = FALSE;
+ }
+ return handled;
+}
+
+BOOL DOHexEditor::handleKeyHere(KEY key, MASK mask)
+{
+ return FALSE;
+}
+
+BOOL DOHexEditor::handleKey(KEY key, MASK mask, BOOL called_from_parent)
+{
+ BOOL handled = FALSE;
+
+ BOOL moved_cursor = FALSE;
+ U32 old_cursor = mCursorPos;
+ U32 cursor_line = mCursorPos / mColumns;
+ U32 doc_first_line = 0;
+ U32 doc_last_line = mValue.size() / mColumns;
+ //U32 first_line = mScrollbar->getDocPos();
+ //U32 last_line = first_line + mScrollbar->getPageSize(); // don't -2 from scrollbar sizes
+ U32 beginning_of_line = mCursorPos - (mCursorPos % mColumns);
+ U32 end_of_line = beginning_of_line + mColumns - 1;
+
+ handled = TRUE;
+ switch( key )
+ {
+
+ // Movement keys
+
+ case KEY_UP:
+ if(cursor_line > doc_first_line)
+ {
+ moveCursor(mCursorPos - mColumns, mSecondNibble);
+ moved_cursor = TRUE;
+ }
+ break;
+ case KEY_DOWN:
+ if(cursor_line < doc_last_line)
+ {
+ moveCursor(mCursorPos + mColumns, mSecondNibble);
+ moved_cursor = TRUE;
+ }
+ break;
+ case KEY_LEFT:
+ if(mCursorPos)
+ {
+ if(!mSecondNibble) moveCursor(mCursorPos - 1, FALSE);
+ else moveCursor(mCursorPos, FALSE);
+ moved_cursor = TRUE;
+ }
+ break;
+ case KEY_RIGHT:
+ moveCursor(mCursorPos + 1, FALSE);
+ moved_cursor = TRUE;
+ break;
+ case KEY_PAGE_UP:
+ mScrollbar->pageUp(1);
+ break;
+ case KEY_PAGE_DOWN:
+ mScrollbar->pageDown(1);
+ break;
+ case KEY_HOME:
+ if(mask & MASK_CONTROL)
+ moveCursor(0, FALSE);
+ else
+ moveCursor(beginning_of_line, FALSE);
+ moved_cursor = TRUE;
+ break;
+ case KEY_END:
+ if(mask & MASK_CONTROL)
+ moveCursor(mValue.size(), FALSE);
+ else
+ moveCursor(end_of_line, FALSE);
+ moved_cursor = TRUE;
+ break;
+
+ // Special
+
+ case KEY_INSERT:
+ gKeyboard->toggleInsertMode();
+ break;
+
+ case KEY_ESCAPE:
+ gFocusMgr.releaseFocusIfNeeded(this);
+ break;
+
+ // Editing
+ case KEY_BACKSPACE:
+ if(mHasSelection)
+ {
+ U32 start = getProperSelectionStart();
+ U32 end = getProperSelectionEnd();
+ del(start, end - 1, TRUE);
+ moveCursor(start, FALSE);
+ }
+ else if(mCursorPos && (!mSecondNibble))
+ {
+ del(mCursorPos - 1, mCursorPos - 1, TRUE);
+ moveCursor(mCursorPos - 1, FALSE);
+ }
+ break;
+
+ case KEY_DELETE:
+ if(mHasSelection)
+ {
+ U32 start = getProperSelectionStart();
+ U32 end = getProperSelectionEnd();
+ del(start, end - 1, TRUE);
+ moveCursor(start, FALSE);
+ }
+ else if((mCursorPos != mValue.size()) && (!mSecondNibble))
+ {
+ del(mCursorPos, mCursorPos, TRUE);
+ }
+ break;
+
+ default:
+ handled = FALSE;
+ break;
+ }
+
+ if(moved_cursor)
+ {
+ // Selecting and deselecting
+ if(mask & MASK_SHIFT)
+ {
+ if(!mHasSelection) mSelectionStart = old_cursor;
+ mSelectionEnd = mCursorPos;
+ }
+ else
+ {
+ mSelectionStart = mCursorPos;
+ mSelectionEnd = mCursorPos;
+ }
+ mHasSelection = mSelectionStart != mSelectionEnd;
+ }
+
+ return handled;
+}
+
+BOOL DOHexEditor::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
+{
+ U8 c = uni_char & 0xff;
+ if(mInData)
+ {
+ if(c > 0x39)
+ {
+ if(c > 0x46) c -= 0x20;
+ if(c >= 0x41 && c <= 0x46) c = (c & 0x0f) + 0x09;
+ else return TRUE;
+ }
+ else if(c < 0x30) return TRUE;
+ else c &= 0x0f;
+ }
+
+ if(uni_char < 0x20) return FALSE;
+
+ if( (LL_KIM_INSERT == gKeyboard->getInsertMode() && (!mHasSelection))
+ || (!mHasSelection && (mCursorPos == mValue.size())) )// last byte? always insert
+ {
+ // Todo: this should overwrite if there's a selection
+ if(!mInData)
+ {
+ std::vector new_data;
+ new_data.push_back(c);
+ insert(mCursorPos, new_data, TRUE);
+ moveCursor(mCursorPos + 1, FALSE);
+ }
+ else if(!mSecondNibble)
+ {
+ c <<= 4;
+ std::vector new_data;
+ new_data.push_back(c);
+ insert(mCursorPos, new_data, TRUE);
+ moveCursor(mCursorPos, TRUE);
+ }
+ else
+ {
+ c |= (mValue[mCursorPos] & 0xF0);
+ std::vector new_data;
+ new_data.push_back(c);
+ overwrite(mCursorPos, mCursorPos, new_data, TRUE);
+ moveCursor(mCursorPos + 1, FALSE);
+ }
+ }
+ else // overwrite mode
+ {
+ if(mHasSelection)
+ {
+ if(mInData) c <<= 4;
+ std::vector new_data;
+ new_data.push_back(c);
+ U8 start = getProperSelectionStart();
+ overwrite(start, getProperSelectionEnd() - 1, new_data, TRUE);
+ if(mInData) moveCursor(start, TRUE); // we only entered a nibble
+ else moveCursor(start + 1, FALSE); // we only entered a byte
+ }
+ else if(!mInData)
+ {
+ std::vector new_data;
+ new_data.push_back(c);
+ overwrite(mCursorPos, mCursorPos, new_data, TRUE);
+ moveCursor(mCursorPos + 1, FALSE);
+ }
+ else if(!mSecondNibble)
+ {
+ c <<= 4;
+ c |= (mValue[mCursorPos] & 0x0F);
+ std::vector new_data;
+ new_data.push_back(c);
+ overwrite(mCursorPos, mCursorPos, new_data, TRUE);
+ moveCursor(mCursorPos, TRUE);
+ }
+ else
+ {
+ c |= (mValue[mCursorPos] & 0xF0);
+ std::vector new_data;
+ new_data.push_back(c);
+ overwrite(mCursorPos, mCursorPos, new_data, TRUE);
+ moveCursor(mCursorPos + 1, FALSE);
+ }
+ }
+
+ return TRUE;
+}
+
+BOOL DOHexEditor::handleUnicodeCharHere(llwchar uni_char)
+{
+ return FALSE;
+}
+
+void DOHexEditor::draw()
+{
+ S32 left = 0;
+ S32 top = getRect().getHeight();
+ S32 right = getRect().getWidth();
+ S32 bottom = 0;
+
+ BOOL has_focus = gFocusMgr.getKeyboardFocus() == this;
+
+ F32 line_height = mGLFont->getLineHeight();
+ F32 char_width = mGLFont->getWidthF32(".");
+ F32 data_column_width = char_width * 3; // " 00";
+ F32 text_x = mTextRect.mLeft;
+ F32 text_x_data = text_x + (char_width * 10.1f); // "00000000 ", dunno why it's a fraction off
+#ifdef COLUMN_SPAN
+ mColumns = (right - char_width * 2 - text_x_data - mScrollbar->getRect().getWidth()) / (char_width * 4); // touch this if you dare...
+#endif
+ F32 text_x_ascii = text_x_data + (data_column_width * mColumns) + (char_width * 2);
+ F32 text_y = (F32)(mTextRect.mTop - line_height);
+
+ U32 data_length = mValue.size();
+ U32 line_count = getLineCount();
+ U32 first_line = mScrollbar->getDocPos();
+ U32 last_line = first_line + mScrollbar->getPageSize(); // don't -2 from scrollbar sizes
+
+ LLRect clip(getRect());
+ clip.mRight = mScrollbar->getRect().mRight;
+ clip.mLeft -= 10;
+ clip.mBottom -= 10;
+ LLLocalClipRect bgclip(clip);
+
+ // Background
+ gl_rect_2d(left, top, right, bottom, LLColor4::white);
+
+ // Let's try drawing some helpful guides
+ LLColor4 guide_color_light = LLColor4(1.0f, 1.0f, 0.9f);
+ LLColor4 guide_color_dark = LLColor4(1.0f, 1.0f, 0.8f);
+ for(U32 col = 0; col < mColumns; col += 2)
+ {
+ // Behind hex
+ F32 box_left = text_x_data + (col * data_column_width) + 2; // skew 2
+ F32 box_right = box_left + data_column_width;
+ gl_rect_2d(box_left, top, box_right, bottom, (col & 3) ? guide_color_light : guide_color_dark);
+ // Behind ASCII
+ //box_left = text_x_ascii + (col * char_width) - 1; // skew 1
+ //box_right = box_left + char_width;
+ //gl_rect_2d(box_left, top, box_right, bottom, guide_color);
+ }
+
+
+ // Scrollbar & border (drawn twice?)
+ mBorder->setKeyboardFocusHighlight(has_focus);
+ LLView::draw();
+
+
+ LLLocalClipRect textrect_clip(mTextRect);
+
+
+ // Selection stuff is reused
+ U32 selection_start = getProperSelectionStart();
+ U32 selection_end = getProperSelectionEnd();
+ U32 selection_first_line = selection_start / mColumns;
+ U32 selection_last_line = selection_end / mColumns;
+ U32 selection_start_column = selection_start % mColumns;
+ U32 selection_end_column = selection_end % mColumns;
+
+ // Don't pretend a selection there is visible
+ if(!selection_end_column)
+ {
+ selection_last_line--;
+ selection_end_column = mColumns;
+ }
+
+ if(mHasSelection)
+ {
+ LLColor4 selection_color_context(LLColor4::black);
+ LLColor4 selection_color_not_context(LLColor4::grey3);
+ LLColor4 selection_color_data(selection_color_not_context);
+ LLColor4 selection_color_ascii(selection_color_not_context);
+ if(mInData) selection_color_data = selection_color_context;
+ else selection_color_ascii = selection_color_context;
+
+
+ // Setup for selection in data
+ F32 selection_pixel_x_base = text_x_data + char_width - 3; // skew 3
+ F32 selection_pixel_x_right_base = selection_pixel_x_base + (data_column_width * mColumns) - char_width + 4;
+ F32 selection_pixel_x;
+ F32 selection_pixel_x_right;
+ F32 selection_pixel_y = (F32)(mTextRect.mTop - line_height) - 3; // skew 3;
+ selection_pixel_y -= line_height * 2;
+ selection_pixel_y -= line_height * (S32(selection_first_line) - S32(first_line));
+
+ // Selection in data, First line
+ if(selection_first_line >= first_line && selection_first_line <= last_line)
+ {
+ selection_pixel_x = selection_pixel_x_base;
+ selection_pixel_x += (data_column_width * selection_start_column);
+ if(selection_first_line == selection_last_line)
+ {
+ // Select to last character
+ selection_pixel_x_right = selection_pixel_x_base + (data_column_width * selection_end_column);
+ selection_pixel_x_right -= (char_width - 4);
+ }
+ else
+ {
+ // Select to end of line
+ selection_pixel_x_right = selection_pixel_x_right_base;
+ }
+ gl_rect_2d(selection_pixel_x, selection_pixel_y + line_height, selection_pixel_x_right, selection_pixel_y, selection_color_data);
+ }
+
+ // Selection in data, Middle lines
+ for(U32 line = selection_first_line + 1; line < selection_last_line; line++)
+ {
+ selection_pixel_y -= line_height;
+ if(line >= first_line && line <= last_line)
+ {
+ gl_rect_2d(selection_pixel_x_base, selection_pixel_y + line_height, selection_pixel_x_right_base, selection_pixel_y, selection_color_data);
+ }
+ }
+
+ // Selection in data, Last line
+ if(selection_first_line != selection_last_line
+ && selection_last_line >= first_line && selection_last_line <= last_line)
+ {
+ selection_pixel_x_right = selection_pixel_x_base + (data_column_width * selection_end_column);
+ selection_pixel_x_right -= (char_width - 4);
+ selection_pixel_y -= line_height;
+ gl_rect_2d(selection_pixel_x_base, selection_pixel_y + line_height, selection_pixel_x_right, selection_pixel_y, selection_color_data);
+ }
+
+ selection_pixel_y = (F32)(mTextRect.mTop - line_height) - 3; // skew 3;
+ selection_pixel_y -= line_height * 2;
+ selection_pixel_y -= line_height * (S32(selection_first_line) - S32(first_line));
+
+ // Setup for selection in ASCII
+ selection_pixel_x_base = text_x_ascii - 1;
+ selection_pixel_x_right_base = selection_pixel_x_base + (char_width * mColumns);
+
+ // Selection in ASCII, First line
+ if(selection_first_line >= first_line && selection_first_line <= last_line)
+ {
+ selection_pixel_x = selection_pixel_x_base;
+ selection_pixel_x += (char_width * selection_start_column);
+ if(selection_first_line == selection_last_line)
+ {
+ // Select to last character
+ selection_pixel_x_right = selection_pixel_x_base + (char_width * selection_end_column);
+ }
+ else
+ {
+ // Select to end of line
+ selection_pixel_x_right = selection_pixel_x_right_base;
+ }
+ gl_rect_2d(selection_pixel_x, selection_pixel_y + line_height, selection_pixel_x_right, selection_pixel_y, selection_color_ascii);
+ }
+
+ // Selection in ASCII, Middle lines
+ for(U32 line = selection_first_line + 1; line < selection_last_line; line++)
+ {
+ selection_pixel_y -= line_height;
+ if(line >= first_line && line <= last_line)
+ {
+ gl_rect_2d(selection_pixel_x_base, selection_pixel_y + line_height, selection_pixel_x_right_base, selection_pixel_y, selection_color_ascii);
+ }
+ }
+
+ // Selection in ASCII, Last line
+ if(selection_first_line != selection_last_line
+ && selection_last_line >= first_line && selection_last_line <= last_line)
+ {
+ selection_pixel_x_right = selection_pixel_x_base + (char_width * selection_end_column);
+ selection_pixel_y -= line_height;
+ gl_rect_2d(selection_pixel_x_base, selection_pixel_y + line_height, selection_pixel_x_right, selection_pixel_y, selection_color_ascii);
+ }
+ }
+
+
+ // Insert/Overwrite
+ std::string text = (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) ? "OVERWRITE" : "INSERT";
+ mGLFont->renderUTF8(text, 0, text_x, text_y, LLColor4::purple);
+ // Offset on top
+ text = "";
+ for(U32 i = 0; i < mColumns; i++)
+ {
+ text.append(llformat(" %02X", i));
+ }
+ mGLFont->renderUTF8(text, 0, text_x_data, text_y, LLColor4::blue);
+ // Size
+ {
+ S32 size = mValue.size();
+ std::string size_desc;
+ if(size < 1000) size_desc = llformat("%d bytes", size);
+ else
+ {
+ if(size < 1000000)
+ {
+ size_desc = llformat("%f", F32(size) / 1000.0f);
+ int i = size_desc.length() - 1;
+ for(; i && size_desc.substr(i, 1) == "0"; i--);
+ if(size_desc.substr(i, 1) == ".") i--;
+ size_desc = size_desc.substr(0, i + 1);
+ size_desc.append(" KB");
+ }
+ else
+ {
+ size_desc = llformat("%f", F32(size) / 1000000.0f);
+ int i = size_desc.length() - 1;
+ for(; i && size_desc.substr(i, 1) == "0"; i--);
+ if(size_desc.substr(i, 1) == ".") i--;
+ size_desc = size_desc.substr(0, i + 1);
+ size_desc.append(" MB");
+ }
+ }
+ F32 x = text_x_ascii;
+ x += (char_width * (mColumns - size_desc.length()));
+ mGLFont->renderUTF8(size_desc, 0, x, text_y, LLColor4::purple);
+ }
+ // Leave a blank line
+ text_y -= (line_height * 2);
+
+ // Everything below "header"
+ for(U32 line = first_line; line <= last_line; line++)
+ {
+ if(line >= line_count) break;
+
+ // Offset on left
+ text = llformat("%08X", line * mColumns); // offset on left
+ mGLFont->renderUTF8(text, 0, text_x, text_y, LLColor4::blue);
+
+ // Setup for rendering hex and ascii
+ U32 line_char_offset = mColumns * line;
+ U32 colstart0 = 0;
+ U32 colend0 = mColumns;
+ U32 colstart1 = mColumns;
+ U32 colend1 = mColumns;
+ U32 colstart2 = mColumns;
+ U32 colend2 = mColumns;
+ if(mHasSelection)
+ {
+ if(line == selection_first_line)
+ {
+ colend0 = selection_start_column;
+ colstart1 = selection_start_column;
+ if(selection_first_line == selection_last_line)
+ {
+ colend1 = selection_end_column;
+ colstart2 = selection_end_column;
+ colend2 = mColumns;
+ }
+ }
+ else if(line > selection_first_line && line < selection_last_line)
+ {
+ colend0 = 0;
+ colstart1 = 0;
+ colend1 = mColumns;
+ }
+ else if(line == selection_last_line)
+ {
+ colend0 = 0;
+ colstart1 = 0;
+ colend1 = selection_end_column;
+ colstart2 = selection_end_column;
+ colend2 = mColumns;
+ }
+ }
+
+ // Data in hex
+ text = "";
+ for(U32 c = colstart0; c < colend0; c++)
+ {
+ U32 o = line_char_offset + c;
+ if(o >= data_length) text.append(" ");
+ else text.append(llformat(" %02X", mValue[o]));
+ }
+ mGLFont->renderUTF8(text, 0, text_x_data + (colstart0 * data_column_width), text_y, LLColor4::black);
+ text = "";
+ for(U32 c = colstart1; c < colend1; c++)
+ {
+ U32 o = line_char_offset + c;
+ if(o >= data_length) text.append(" ");
+ else text.append(llformat(" %02X", mValue[o]));
+ }
+ mGLFont->renderUTF8(text, 0, text_x_data + (colstart1 * data_column_width), text_y, LLColor4::white);
+ text = "";
+ for(U32 c = colstart2; c < colend2; c++)
+ {
+ U32 o = line_char_offset + c;
+ if(o >= data_length) text.append(" ");
+ else text.append(llformat(" %02X", mValue[o]));
+ }
+ mGLFont->renderUTF8(text, 0, text_x_data + (colstart2 * data_column_width), text_y, LLColor4::black);
+
+ // ASCII
+ text = "";
+ for(U32 c = colstart0; c < colend0; c++)
+ {
+ U32 o = line_char_offset + c;
+ if(o >= data_length) break;
+ if((mValue[o] < 0x20) || (mValue[o] >= 0x7F)) text.append(".");
+ else text.append(llformat("%c", mValue[o]));
+ }
+ mGLFont->renderUTF8(text, 0, text_x_ascii + (colstart0 * char_width), text_y, LLColor4::black);
+ text = "";
+ for(U32 c = colstart1; c < colend1; c++)
+ {
+ U32 o = line_char_offset + c;
+ if(o >= data_length) break;
+ if((mValue[o] < 0x20) || (mValue[o] >= 0x7F)) text.append(".");
+ else text.append(llformat("%c", mValue[o]));
+ }
+ mGLFont->renderUTF8(text, 0, text_x_ascii + (colstart1 * char_width), text_y, LLColor4::white);
+ text = "";
+ for(U32 c = colstart2; c < colend2; c++)
+ {
+ U32 o = line_char_offset + c;
+ if(o >= data_length) break;
+ if((mValue[o] < 0x20) || (mValue[o] >= 0x7F)) text.append(".");
+ else text.append(llformat("%c", mValue[o]));
+ }
+ mGLFont->renderUTF8(text, 0, text_x_ascii + (colstart2 * char_width), text_y, LLColor4::black);
+
+ text_y -= line_height;
+ }
+
+
+
+ // Cursor
+ if(has_focus && !mHasSelection && (U32(LLTimer::getElapsedSeconds() * 2.0f) & 0x1))
+ {
+ U32 cursor_line = mCursorPos / mColumns;
+ if((cursor_line >= first_line) && (cursor_line <= last_line))
+ {
+ F32 pixel_y = (F32)(mTextRect.mTop - line_height);
+ pixel_y -= line_height * (2 + (cursor_line - first_line));
+
+ U32 cursor_offset = mCursorPos % mColumns; // bytes
+ F32 pixel_x = mInData ? text_x_data : text_x_ascii;
+ if(mInData)
+ {
+ pixel_x += data_column_width * cursor_offset;
+ pixel_x += char_width;
+ if(mSecondNibble) pixel_x += char_width;
+ }
+ else
+ {
+ pixel_x += char_width * cursor_offset;
+ }
+ pixel_x -= 2.0f;
+ pixel_y -= 2.0f;
+ gl_rect_2d(pixel_x, pixel_y + line_height, pixel_x + 2, pixel_y, LLColor4::black);
+ }
+ }
+}
+
+void DOHexEditor::deselect()
+{
+ mSelectionStart = mCursorPos;
+ mSelectionEnd = mCursorPos;
+ mHasSelection = FALSE;
+ mSelecting = FALSE;
+}
+
+BOOL DOHexEditor::canUndo() const
+{
+ return mUndoBuffer->canUndo();
+}
+
+void DOHexEditor::undo()
+{
+ mUndoBuffer->undoAction();
+}
+
+BOOL DOHexEditor::canRedo() const
+{
+ return mUndoBuffer->canRedo();
+}
+
+void DOHexEditor::redo()
+{
+ mUndoBuffer->redoAction();
+}
+
+
+
+
+void DOHexEditor::moveCursor(U32 pos, BOOL second_nibble)
+{
+ mCursorPos = pos;
+
+ // Clamp and handle second nibble
+ if(mCursorPos >= mValue.size())
+ {
+ mCursorPos = mValue.size();
+ mSecondNibble = FALSE;
+ }
+ else
+ {
+ mSecondNibble = mInData ? second_nibble : FALSE;
+ }
+
+ // Change selection
+ mSelectionEnd = mCursorPos;
+ if(!mHasSelection) mSelectionStart = mCursorPos;
+
+ // Scroll
+ U32 line = mCursorPos / mColumns;
+ U32 first_line = mScrollbar->getDocPos();
+ U32 last_line = first_line + mScrollbar->getPageSize(); // don't -2 from scrollbar sizes
+ if(line < first_line) mScrollbar->setDocPos(line);
+ if(line > (last_line - 2)) mScrollbar->setDocPos(line - mScrollbar->getPageSize() + 1);
+}
+
+BOOL DOHexEditor::canCut() const
+{
+ return mHasSelection;
+}
+
+void DOHexEditor::cut()
+{
+ if(!canCut()) return;
+
+ copy();
+
+ U32 start = getProperSelectionStart();
+ del(start, getProperSelectionEnd() - 1, TRUE);
+
+ moveCursor(start, FALSE);
+}
+
+BOOL DOHexEditor::canCopy() const
+{
+ return mHasSelection;
+}
+
+void DOHexEditor::copy()
+{
+ if(!canCopy()) return;
+
+ std::string text;
+ if(mInData)
+ {
+ U32 start = getProperSelectionStart();
+ U32 end = getProperSelectionEnd();
+ for(U32 i = start; i < end; i++)
+ text.append(llformat("%02X", mValue[i]));
+ }
+ else
+ {
+ U32 start = getProperSelectionStart();
+ U32 end = getProperSelectionEnd();
+ for(U32 i = start; i < end; i++)
+ text.append(llformat("%c", mValue[i]));
+ }
+ LLWString wtext = utf8str_to_wstring(text);
+ gClipboard.copyFromSubstring(wtext, 0, wtext.length());
+}
+
+BOOL DOHexEditor::canPaste() const
+{
+ return TRUE;
+}
+
+void DOHexEditor::paste()
+{
+ if(!canPaste()) return;
+
+ std::string clipstr = wstring_to_utf8str(gClipboard.getPasteWString());
+ const char* clip = clipstr.c_str();
+
+ std::vector new_data;
+ if(mInData)
+ {
+ int len = strlen(clip);
+ for(int i = 0; (i + 1) < len; i += 2)
+ {
+ int c = 0;
+ if(sscanf(&(clip[i]), "%02X", &c) != 1) break;
+ new_data.push_back(U8(c));
+ }
+ }
+ else
+ {
+ int len = strlen(clip);
+ for(int i = 0; i < len; i++)
+ {
+ U8 c = 0;
+ if(sscanf(&(clip[i]), "%c", &c) != 1) break;
+ new_data.push_back(c);
+ }
+ }
+
+ U32 start = mCursorPos;
+ if(!mHasSelection)
+ insert(start, new_data, TRUE);
+ else
+ {
+ start = getProperSelectionStart();
+ overwrite(start, getProperSelectionEnd() - 1, new_data, TRUE);
+ }
+
+ moveCursor(start + new_data.size(), FALSE);
+}
+
+BOOL DOHexEditor::canDoDelete() const
+{
+ return mValue.size() > 0;
+}
+
+void DOHexEditor::doDelete()
+{
+ if(!canDoDelete()) return;
+
+ U32 start = getProperSelectionStart();
+ del(start, getProperSelectionEnd(), TRUE);
+
+ moveCursor(start, FALSE);
+}
+
+BOOL DOHexEditor::canSelectAll() const
+{
+ return mValue.size() > 0;
+}
+
+void DOHexEditor::selectAll()
+{
+ if(!canSelectAll()) return;
+
+ mSelectionStart = 0;
+ mSelectionEnd = mValue.size();
+ mHasSelection = mSelectionStart != mSelectionEnd;
+}
+
+BOOL DOHexEditor::canDeselect() const
+{
+ return mHasSelection;
+}
+
+void DOHexEditor::insert(U32 pos, std::vector new_data, BOOL undoable)
+{
+ if(pos > mValue.size())
+ {
+ llwarns << "pos outside data!" << llendl;
+ return;
+ }
+
+ deselect();
+
+ if(undoable)
+ {
+ DOUndoHex* action = (DOUndoHex*)(mUndoBuffer->getNextAction());
+ action->set(this, &(DOUndoHex::undoInsert), &(DOUndoHex::redoInsert), pos, pos, std::vector(), new_data);
+ }
+
+ std::vector::iterator wheres = mValue.begin() + pos;
+
+ mValue.insert(wheres, new_data.begin(), new_data.end());
+
+ changedLength();
+}
+
+void DOHexEditor::overwrite(U32 first_pos, U32 last_pos, std::vector new_data, BOOL undoable)
+{
+ if(first_pos > mValue.size() || last_pos > mValue.size())
+ {
+ llwarns << "pos outside data!" << llendl;
+ return;
+ }
+
+ deselect();
+
+ std::vector::iterator first = mValue.begin() + first_pos;
+ std::vector::iterator last = mValue.begin() + last_pos;
+
+ std::vector old_data;
+ if(last_pos > 0) old_data = std::vector(first, last + 1);
+
+ if(undoable)
+ {
+ DOUndoHex* action = (DOUndoHex*)(mUndoBuffer->getNextAction());
+ action->set(this, &(DOUndoHex::undoOverwrite), &(DOUndoHex::redoOverwrite), first_pos, last_pos, old_data, new_data);
+ }
+
+ mValue.erase(first, last + 1);
+ first = mValue.begin() + first_pos;
+ mValue.insert(first, new_data.begin(), new_data.end());
+
+ changedLength();
+}
+
+void DOHexEditor::del(U32 first_pos, U32 last_pos, BOOL undoable)
+{
+ if(first_pos > mValue.size() || last_pos > mValue.size())
+ {
+ llwarns << "pos outside data!" << llendl;
+ return;
+ }
+
+ deselect();
+
+ std::vector::iterator first = mValue.begin() + first_pos;
+ std::vector::iterator last = mValue.begin() + last_pos;
+
+ std::vector old_data;
+ if(last_pos > 0) old_data = std::vector(first, last + 1);
+
+ if(undoable)
+ {
+ DOUndoHex* action = (DOUndoHex*)(mUndoBuffer->getNextAction());
+ action->set(this, &(DOUndoHex::undoDel), &(DOUndoHex::redoDel), first_pos, last_pos, old_data, std::vector());
+ }
+
+ mValue.erase(first, last + 1);
+
+ changedLength();
+}
+
+void DOUndoHex::set(DOHexEditor* hex_editor,
+ void (*undo_action)(DOUndoHex*),
+ void (*redo_action)(DOUndoHex*),
+ U32 first_pos,
+ U32 last_pos,
+ std::vector old_data,
+ std::vector new_data)
+{
+ mHexEditor = hex_editor;
+ mUndoAction = undo_action;
+ mRedoAction = redo_action;
+ mFirstPos = first_pos;
+ mLastPos = last_pos;
+ mOldData = old_data;
+ mNewData = new_data;
+}
+
+void DOUndoHex::undo()
+{
+ mUndoAction(this);
+}
+
+void DOUndoHex::redo()
+{
+ mRedoAction(this);
+}
+
+void DOUndoHex::undoInsert(DOUndoHex* action)
+{
+ //action->mHexEditor->del(action->mFirstPos, action->mLastPos, FALSE);
+ action->mHexEditor->del(action->mFirstPos, action->mFirstPos + action->mNewData.size() - 1, FALSE);
+}
+
+void DOUndoHex::redoInsert(DOUndoHex* action)
+{
+ action->mHexEditor->insert(action->mFirstPos, action->mNewData, FALSE);
+}
+
+void DOUndoHex::undoOverwrite(DOUndoHex* action)
+{
+ //action->mHexEditor->overwrite(action->mFirstPos, action->mLastPos, action->mOldData, FALSE);
+ action->mHexEditor->overwrite(action->mFirstPos, action->mFirstPos + action->mNewData.size() - 1, action->mOldData, FALSE);
+}
+
+void DOUndoHex::redoOverwrite(DOUndoHex* action)
+{
+ action->mHexEditor->overwrite(action->mFirstPos, action->mLastPos, action->mNewData, FALSE);
+}
+
+void DOUndoHex::undoDel(DOUndoHex* action)
+{
+ action->mHexEditor->insert(action->mFirstPos, action->mOldData, FALSE);
+}
+
+void DOUndoHex::redoDel(DOUndoHex* action)
+{
+ action->mHexEditor->del(action->mFirstPos, action->mLastPos, FALSE);
+}
+
+
+//
diff --git a/indra/newview/dohexeditor.h b/indra/newview/dohexeditor.h
index 37f8ed35d..8790d7913 100644
--- a/indra/newview/dohexeditor.h
+++ b/indra/newview/dohexeditor.h
@@ -1,152 +1,159 @@
-/**
- * @file dohexeditor.h
- * @brief DOHexEditor Widget
- * @author Day Oh
- *
- * $LicenseInfo:firstyear=2009&license=WTFPLV2$
- *
- */
-
-//
-#ifndef DO_DOHEXEDITOR_H
-#define DO_DOHEXEDITOR_H
-
-#include "lluictrl.h"
-#include "llscrollbar.h"
-#include "llviewborder.h"
-#include "llundo.h"
-#include "lleditmenuhandler.h"
-
-class DOHexEditor : public LLUICtrl, public LLEditMenuHandler
-{
-public:
- DOHexEditor(const std::string& name, const LLRect& rect);
- ~DOHexEditor();
- static LLView* fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFactory *factory);
- void setValue(const LLSD& value);
- LLSD getValue() const;
- void setColumns(U8 columns);
- U8 getColumns(U8 columns) { return mColumns; };
- U32 getLineCount();
- F32 getSuggestedWidth();
- U32 getProperSelectionStart();
- U32 getProperSelectionEnd();
- void reshape(S32 width, S32 height, BOOL called_from_parent);
- void setFocus(BOOL b);
-
- BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
- BOOL handleMouseDown(S32 x, S32 y, MASK mask);
- BOOL handleHover(S32 x, S32 y, MASK mask);
- BOOL handleMouseUp(S32 x, S32 y, MASK mask);
-
- BOOL handleKeyHere(KEY key, MASK mask);
- BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent);
- BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent);
- BOOL handleUnicodeCharHere(llwchar uni_char);
-
- void draw();
-
- void moveCursor(U32 pos, BOOL second_nibble);
-
- void insert(U32 pos, std::vector new_data, BOOL undoable);
- void overwrite(U32 first_pos, U32 last_pos, std::vector new_data, BOOL undoable);
- void del(U32 first_pos, U32 last_pos, BOOL undoable);
-
- virtual void cut();
- virtual BOOL canCut() const;
-
- virtual void copy();
- virtual BOOL canCopy() const;
-
- virtual void paste();
- virtual BOOL canPaste() const;
-
- virtual void doDelete();
- virtual BOOL canDoDelete() const;
-
- virtual void selectAll();
- virtual BOOL canSelectAll() const;
-
- virtual void deselect();
- virtual BOOL canDeselect() const;
-
- virtual void undo();
- virtual BOOL canUndo() const;
-
- virtual void redo();
- virtual BOOL canRedo() const;
-
-private:
- std::vector mValue;
- U8 mColumns;
-
- U32 mCursorPos;
- BOOL mSecondNibble;
- BOOL mInData;
- BOOL mSelecting;
- BOOL mHasSelection;
- U32 mSelectionStart;
- U32 mSelectionEnd;
-
- LLFontGL* mGLFont;
- LLRect mTextRect;
- LLScrollbar* mScrollbar;
- LLViewBorder* mBorder;
-
- LLUndoBuffer* mUndoBuffer;
-
- void changedLength();
- void getPosAndContext(S32 x, S32 y, BOOL force_context, U32& pos, BOOL& in_data, BOOL& second_nibble);
-};
-
-class DOUndoHex : public LLUndoBuffer::LLUndoAction
-{
-protected:
- DOUndoHex() { }
- DOHexEditor* mHexEditor;
- U32 mFirstPos;
- U32 mLastPos;
- std::vector mOldData;
- std::vector mNewData;
-public:
- static LLUndoAction* create() { return new DOUndoHex(); }
- virtual void set(DOHexEditor* hex_editor,
- void (*undo_action)(DOUndoHex*),
- void (*redo_action)(DOUndoHex*),
- U32 first_pos,
- U32 last_pos,
- std::vector old_data,
- std::vector new_data);
- void (*mUndoAction)(DOUndoHex*);
- void (*mRedoAction)(DOUndoHex*);
- virtual void undo();
- virtual void redo();
-
- static void undoInsert(DOUndoHex* action);
- static void redoInsert(DOUndoHex* action);
- static void undoOverwrite(DOUndoHex* action);
- static void redoOverwrite(DOUndoHex* action);
- static void undoDel(DOUndoHex* action);
- static void redoDel(DOUndoHex* action);
-};
-
-class DOHexInsert : public DOUndoHex
-{
- virtual void undo();
- virtual void redo();
-};
-
-class DOHexOverwrite : public DOUndoHex
-{
- virtual void undo();
- virtual void redo();
-};
-
-class DOHexDel : public DOUndoHex
-{
- virtual void undo();
- virtual void redo();
-};
-
-#endif
-//
+/**
+ * @file dohexeditor.h
+ * @brief DOHexEditor Widget
+ * @author Day Oh
+ *
+ * $LicenseInfo:firstyear=2009&license=WTFPLV2$
+ *
+ */
+
+//
+#ifndef DO_DOHEXEDITOR_H
+#define DO_DOHEXEDITOR_H
+
+#define MIN_COLS 8
+#define MAX_COLS 48
+
+#ifndef COLUMN_SPAN
+#define COLUMN_SPAN
+#endif
+
+#include "lluictrl.h"
+#include "llscrollbar.h"
+#include "llviewborder.h"
+#include "llundo.h"
+#include "lleditmenuhandler.h"
+
+class DOHexEditor : public LLUICtrl, public LLEditMenuHandler
+{
+public:
+ DOHexEditor(const std::string& name, const LLRect& rect);
+ ~DOHexEditor();
+ static LLView* fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFactory *factory);
+ void setValue(const LLSD& value);
+ LLSD getValue() const;
+ void setColumns(U8 columns);
+ U8 getColumns() { return mColumns; };
+ U32 getLineCount();
+ F32 getSuggestedWidth(U8 cols = -1);
+ U32 getProperSelectionStart();
+ U32 getProperSelectionEnd();
+ void reshape(S32 width, S32 height, BOOL called_from_parent);
+ void setFocus(BOOL b);
+
+ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
+ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+ BOOL handleHover(S32 x, S32 y, MASK mask);
+ BOOL handleMouseUp(S32 x, S32 y, MASK mask);
+
+ BOOL handleKeyHere(KEY key, MASK mask);
+ BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent);
+ BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent);
+ BOOL handleUnicodeCharHere(llwchar uni_char);
+
+ void draw();
+
+ void moveCursor(U32 pos, BOOL second_nibble);
+
+ void insert(U32 pos, std::vector new_data, BOOL undoable);
+ void overwrite(U32 first_pos, U32 last_pos, std::vector new_data, BOOL undoable);
+ void del(U32 first_pos, U32 last_pos, BOOL undoable);
+
+ virtual void cut();
+ virtual BOOL canCut() const;
+
+ virtual void copy();
+ virtual BOOL canCopy() const;
+
+ virtual void paste();
+ virtual BOOL canPaste() const;
+
+ virtual void doDelete();
+ virtual BOOL canDoDelete() const;
+
+ virtual void selectAll();
+ virtual BOOL canSelectAll() const;
+
+ virtual void deselect();
+ virtual BOOL canDeselect() const;
+
+ virtual void undo();
+ virtual BOOL canUndo() const;
+
+ virtual void redo();
+ virtual BOOL canRedo() const;
+
+private:
+ std::vector mValue;
+ U8 mColumns;
+
+ U32 mCursorPos;
+ BOOL mSecondNibble;
+ BOOL mInData;
+ BOOL mSelecting;
+ BOOL mHasSelection;
+ U32 mSelectionStart;
+ U32 mSelectionEnd;
+
+ LLFontGL* mGLFont;
+ LLRect mTextRect;
+ LLScrollbar* mScrollbar;
+ LLViewBorder* mBorder;
+
+ LLUndoBuffer* mUndoBuffer;
+
+ void changedLength();
+ void getPosAndContext(S32 x, S32 y, BOOL force_context, U32& pos, BOOL& in_data, BOOL& second_nibble);
+};
+
+class DOUndoHex : public LLUndoBuffer::LLUndoAction
+{
+protected:
+ DOUndoHex() { }
+ DOHexEditor* mHexEditor;
+ U32 mFirstPos;
+ U32 mLastPos;
+ std::vector mOldData;
+ std::vector mNewData;
+public:
+ static LLUndoAction* create() { return new DOUndoHex(); }
+ virtual void set(DOHexEditor* hex_editor,
+ void (*undo_action)(DOUndoHex*),
+ void (*redo_action)(DOUndoHex*),
+ U32 first_pos,
+ U32 last_pos,
+ std::vector old_data,
+ std::vector new_data);
+ void (*mUndoAction)(DOUndoHex*);
+ void (*mRedoAction)(DOUndoHex*);
+ virtual void undo();
+ virtual void redo();
+
+ static void undoInsert(DOUndoHex* action);
+ static void redoInsert(DOUndoHex* action);
+ static void undoOverwrite(DOUndoHex* action);
+ static void redoOverwrite(DOUndoHex* action);
+ static void undoDel(DOUndoHex* action);
+ static void redoDel(DOUndoHex* action);
+};
+
+class DOHexInsert : public DOUndoHex
+{
+ virtual void undo();
+ virtual void redo();
+};
+
+class DOHexOverwrite : public DOUndoHex
+{
+ virtual void undo();
+ virtual void redo();
+};
+
+class DOHexDel : public DOUndoHex
+{
+ virtual void undo();
+ virtual void redo();
+};
+
+#endif
+//
diff --git a/indra/newview/hgfloatertexteditor.cpp b/indra/newview/hgfloatertexteditor.cpp
index e087f7e72..1001fed1b 100644
--- a/indra/newview/hgfloatertexteditor.cpp
+++ b/indra/newview/hgfloatertexteditor.cpp
@@ -1,398 +1,398 @@
-/**
- * @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 "llinventorybackup.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
-#include "lllocalinventory.h"
-
-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 OPENSIM_RULES!=1
- if(mItem->getCreatorUUID() == gAgentID)
- {
-#endif /* OPENSIM_RULES!=1 */
- // Load the asset
- editor->setVisible(FALSE);
- childSetText("status_text", std::string("Loading..."));
- LLInventoryBackup::download(mItem, this, imageCallback, assetCallback);
-#if OPENSIM_RULES!=1
- } else {
- this->close(false);
- }
-#endif /* OPENSIM_RULES!=1 */
-
- 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)
- {
- LLInventoryBackup::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::string new_data;
- for(S32 i = 0; i < size; i++)
- new_data += (char)src_data[i];
-
- delete[] src_data;
-
- 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)
-{
- LLInventoryBackup::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();
-
- std::string new_data("");
- if(size > 0)
- {
- char* buffer = new char[size + 1];
- if (buffer == NULL)
- {
- llerrs << "Memory Allocation Failed" << llendl;
- return;
- }
-
- file.read((U8*)buffer, size);
- buffer[size - 1] = 0;
-
- new_data = std::string(buffer);
- delete[] buffer;
- }
-
-
- floater->mEditor->setText(LLStringExplicit(new_data));
- floater->mEditor->setVisible(TRUE);
- floater->childSetText("status_text", llformat("File Size: %d", size));
-
- 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());
-
- const char* value = floater->mEditor->getText().c_str();
- int size = strlen(value);
- U8* buffer = new U8[size];
- for(int i = 0; i < size; i++)
- buffer[i] = (U8)value[i];
-
- delete[] value;
-
- 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;
- }
-
- 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)
- {
- 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());
-
- const char* value = floater->mEditor->getText().c_str();
- int size = strlen(value);
- U8* buffer = new U8[size];
- for(int i = 0; i < size; i++)
- buffer[i] = (U8)value[i];
-
- 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;
- }
-
- 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);
- }
-}
-
-//
+/**
+ * @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 "llinventorybackup.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
+#include "lllocalinventory.h"
+
+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 OPENSIM_RULES!=1
+ if(mItem->getCreatorUUID() == gAgentID)
+ {
+#endif /* OPENSIM_RULES!=1 */
+ // Load the asset
+ editor->setVisible(FALSE);
+ childSetText("status_text", std::string("Loading..."));
+ LLInventoryBackup::download(mItem, this, imageCallback, assetCallback);
+#if OPENSIM_RULES!=1
+ } else {
+ this->close(false);
+ }
+#endif /* OPENSIM_RULES!=1 */
+
+ 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)
+ {
+ LLInventoryBackup::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::string new_data;
+ for(S32 i = 0; i < size; i++)
+ new_data += (char)src_data[i];
+
+ delete[] src_data;
+
+ 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)
+{
+ LLInventoryBackup::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();
+
+ std::string new_data("");
+ if(size > 0)
+ {
+ char* buffer = new char[size + 1];
+ if (buffer == NULL)
+ {
+ llerrs << "Memory Allocation Failed" << llendl;
+ return;
+ }
+
+ file.read((U8*)buffer, size);
+ buffer[size - 1] = 0;
+
+ new_data = std::string(buffer);
+ delete[] buffer;
+ }
+
+
+ floater->mEditor->setText(LLStringExplicit(new_data));
+ floater->mEditor->setVisible(TRUE);
+ floater->childSetText("status_text", llformat("File Size: %d", size));
+
+ 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());
+
+ const char* value = floater->mEditor->getText().c_str();
+ int size = strlen(value);
+ U8* buffer = new U8[size];
+ for(int i = 0; i < size; i++)
+ buffer[i] = (U8)value[i];
+
+ delete[] value;
+
+ 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;
+ }
+
+ 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)
+ {
+ 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());
+
+ const char* value = floater->mEditor->getText().c_str();
+ int size = strlen(value);
+ U8* buffer = new U8[size];
+ for(int i = 0; i < size; i++)
+ buffer[i] = (U8)value[i];
+
+ 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;
+ }
+
+ 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
index 62fa68733..285821d52 100644
--- a/indra/newview/hgfloatertexteditor.h
+++ b/indra/newview/hgfloatertexteditor.h
@@ -1,50 +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_HGFLOATERTEXT_H
-#define HG_HGFLOATERTEXT_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
+/**
+ * @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_HGFLOATERTEXT_H
+#define HG_HGFLOATERTEXT_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/llfloatermessagelog.cpp b/indra/newview/llfloatermessagelog.cpp
index 6c3578c87..b8b3f9987 100644
--- a/indra/newview/llfloatermessagelog.cpp
+++ b/indra/newview/llfloatermessagelog.cpp
@@ -1,941 +1,941 @@
-//
-#include "llviewerprecompiledheaders.h"
-#include "llfloatermessagelog.h"
-#include "lluictrlfactory.h"
-#include "llworld.h"
-#include "llviewerregion.h"
-#include "llscrolllistctrl.h"
-#include "lltexteditor.h"
-#include "llviewerwindow.h" // alertXml
-#include "llmessagetemplate.h"
-#include
-#include "llmenugl.h"
-#include "llfloatermessagebuilder.h"
-#include "llagent.h"
-////////////////////////////////
-// LLNetListItem
-////////////////////////////////
-LLNetListItem::LLNetListItem(LLUUID id)
-: mID(id),
- mAutoName(TRUE),
- mName("No name"),
- mPreviousRegionName(""),
- mCircuitData(NULL)
-{
-}
-////////////////////////////////
-// LLFloaterMessageLogItem
-////////////////////////////////
-U8 LLFloaterMessageLogItem::sDecodeBuffer[8192];
-LLTemplateMessageReader* LLFloaterMessageLogItem::sTemplateMessageReader = NULL;
-LLFloaterMessageLogItem::LLFloaterMessageLogItem(LLMessageLogEntry entry)
-: LLMessageLogEntry(entry.mType, entry.mFromHost, entry.mToHost, entry.mData, entry.mDataSize)
-{
- if(!sTemplateMessageReader)
- {
- sTemplateMessageReader = new LLTemplateMessageReader(gMessageSystem->mMessageNumbers);
- }
- mID.generate();
- mSequenceID = 0;
- if(mType == TEMPLATE)
- {
- BOOL decode_invalid = FALSE;
- S32 decode_len = mDataSize;
- memcpy(sDecodeBuffer, mData, decode_len);
- mFlags = sDecodeBuffer[0];
- U8* decodep = &(sDecodeBuffer[0]);
- gMessageSystem->zeroCodeExpand(&decodep, &decode_len);
- if(decode_len < 7)
- decode_invalid = TRUE;
- else
- {
- mSequenceID = ntohl(*((U32*)(&decodep[1])));
- sTemplateMessageReader->clearMessage();
- if(!sTemplateMessageReader->validateMessage(decodep, decode_len, mFromHost, TRUE))
- decode_invalid = TRUE;
- else
- {
- if(!sTemplateMessageReader->decodeData(decodep, mFromHost, TRUE))
- decode_invalid = TRUE;
- else
- {
- LLMessageTemplate* temp = sTemplateMessageReader->getTemplate();
- mName = temp->mName;
- mSummary = "";
-
- if(mFlags)
- {
- mSummary.append(" [ ");
- if(mFlags & LL_ZERO_CODE_FLAG)
- mSummary.append(" Zer ");
- if(mFlags & LL_RELIABLE_FLAG)
- mSummary.append(" Rel ");
- if(mFlags & LL_RESENT_FLAG)
- mSummary.append(" Rsd ");
- if(mFlags & LL_ACK_FLAG)
- mSummary.append(" Ack ");
- mSummary.append(" ] ");
- }
-
- LLMessageTemplate::message_block_map_t::iterator blocks_end = temp->mMemberBlocks.end();
- for (LLMessageTemplate::message_block_map_t::iterator blocks_iter = temp->mMemberBlocks.begin();
- blocks_iter != blocks_end; ++blocks_iter)
- {
- LLMessageBlock* block = (*blocks_iter);
- const char* block_name = block->mName;
- S32 num_blocks = sTemplateMessageReader->getNumberOfBlocks(block_name);
- if(!num_blocks)
- mSummary.append(" { } ");
- else if(num_blocks > 1)
- mSummary.append(llformat(" %s [ %d ] { ... } ", block_name, num_blocks));
- else for(S32 i = 0; i < 1; i++)
- {
- mSummary.append(" { ");
- LLMessageBlock::message_variable_map_t::iterator var_end = block->mMemberVariables.end();
- for (LLMessageBlock::message_variable_map_t::iterator var_iter = block->mMemberVariables.begin();
- var_iter != var_end; ++var_iter)
- {
- LLMessageVariable* variable = (*var_iter);
- const char* var_name = variable->getName();
- BOOL returned_hex;
- std::string value = getString(sTemplateMessageReader, block_name, i, var_name, variable->getType(), returned_hex, TRUE);
- mSummary.append(llformat(" %s=%s ", var_name, value.c_str()));
- }
- mSummary.append(" } ");
- if(mSummary.length() > 255) break;
- }
- if(mSummary.length() > 255)
- {
- mSummary.append(" ... ");
- break;
- }
- } // blocks_iter
- } // decode_valid
- }
- }
- if(decode_invalid)
- {
- mName = "Invalid";
- mSummary = "";
- for(S32 i = 0; i < mDataSize; i++)
- mSummary.append(llformat("%02X ", mData[i]));
- }
- }
- else // not template
- {
- mName = "SOMETHING ELSE";
- mSummary = "TODO: SOMETHING ELSE";
- }
-}
-LLFloaterMessageLogItem::~LLFloaterMessageLogItem()
-{
-}
-BOOL LLFloaterMessageLogItem::isOutgoing()
-{
- return mFromHost == LLHost(16777343, gMessageSystem->getListenPort());
-}
-std::string LLFloaterMessageLogItem::getFull(BOOL show_header)
-{
- std::string full("");
- if(mType == TEMPLATE)
- {
- BOOL decode_invalid = FALSE;
- S32 decode_len = mDataSize;
- memcpy(sDecodeBuffer, mData, decode_len);
- U8* decodep = &(sDecodeBuffer[0]);
- gMessageSystem->zeroCodeExpand(&decodep, &decode_len);
- if(decode_len < 7)
- decode_invalid = TRUE;
- else
- {
- sTemplateMessageReader->clearMessage();
- if(!sTemplateMessageReader->validateMessage(decodep, decode_len, mFromHost, TRUE))
- decode_invalid = TRUE;
- else
- {
- if(!sTemplateMessageReader->decodeData(decodep, mFromHost, TRUE))
- decode_invalid = TRUE;
- else
- {
- LLMessageTemplate* temp = sTemplateMessageReader->getTemplate();
- full.append(isOutgoing() ? "out " : "in ");
- full.append(llformat("%s\n", temp->mName));
- if(show_header)
- {
- full.append("[Header]\n");
- full.append(llformat("SequenceID = %u\n", mSequenceID));
- full.append(llformat("LL_ZERO_CODE_FLAG = %s\n", (mFlags & LL_ZERO_CODE_FLAG) ? "True" : "False"));
- full.append(llformat("LL_RELIABLE_FLAG = %s\n", (mFlags & LL_RELIABLE_FLAG) ? "True" : "False"));
- full.append(llformat("LL_RESENT_FLAG = %s\n", (mFlags & LL_RESENT_FLAG) ? "True" : "False"));
- full.append(llformat("LL_ACK_FLAG = %s\n", (mFlags & LL_ACK_FLAG) ? "True" : "False"));
- }
- LLMessageTemplate::message_block_map_t::iterator blocks_end = temp->mMemberBlocks.end();
- for (LLMessageTemplate::message_block_map_t::iterator blocks_iter = temp->mMemberBlocks.begin();
- blocks_iter != blocks_end; ++blocks_iter)
- {
- LLMessageBlock* block = (*blocks_iter);
- const char* block_name = block->mName;
- S32 num_blocks = sTemplateMessageReader->getNumberOfBlocks(block_name);
- for(S32 i = 0; i < num_blocks; i++)
- {
- full.append(llformat("[%s]\n", block->mName));
- LLMessageBlock::message_variable_map_t::iterator var_end = block->mMemberVariables.end();
- for (LLMessageBlock::message_variable_map_t::iterator var_iter = block->mMemberVariables.begin();
- var_iter != var_end; ++var_iter)
- {
- LLMessageVariable* variable = (*var_iter);
- const char* var_name = variable->getName();
- BOOL returned_hex;
- std::string value = getString(sTemplateMessageReader, block_name, i, var_name, variable->getType(), returned_hex);
- if(returned_hex)
- full.append(llformat("%s =| ", var_name));
- else
- full.append(llformat("%s = ", var_name));
- // llformat has a 1024 char limit!?
- full.append(value);
- full.append("\n");
- }
- }
- } // blocks_iter
- } // decode_valid
- }
- }
- if(decode_invalid)
- {
- full = isOutgoing() ? "out" : "in";
- full.append("\n");
- for(S32 i = 0; i < mDataSize; i++)
- full.append(llformat("%02X ", mData[i]));
- }
- }
- else // not template
- {
- full = "FIXME";
- }
- return full;
-}
-// static
-std::string LLFloaterMessageLogItem::getString(LLTemplateMessageReader* readerp, const char* block_name, S32 block_num, const char* var_name, e_message_variable_type var_type, BOOL &returned_hex, BOOL summary_mode)
-{
- returned_hex = FALSE;
- std::stringstream stream;
- char* value;
- U32 valueU32;
- U16 valueU16;
- LLVector3 valueVector3;
- LLVector3d valueVector3d;
- LLVector4 valueVector4;
- LLQuaternion valueQuaternion;
- LLUUID valueLLUUID;
- switch(var_type)
- {
- case MVT_U8:
- U8 valueU8;
- readerp->getU8(block_name, var_name, valueU8, block_num);
- stream << U32(valueU8);
- break;
- case MVT_U16:
- readerp->getU16(block_name, var_name, valueU16, block_num);
- stream << valueU16;
- break;
- case MVT_U32:
- readerp->getU32(block_name, var_name, valueU32, block_num);
- stream << valueU32;
- break;
- case MVT_U64:
- U64 valueU64;
- readerp->getU64(block_name, var_name, valueU64, block_num);
- stream << valueU64;
- break;
- case MVT_S8:
- S8 valueS8;
- readerp->getS8(block_name, var_name, valueS8, block_num);
- stream << S32(valueS8);
- break;
- case MVT_S16:
- S16 valueS16;
- readerp->getS16(block_name, var_name, valueS16, block_num);
- stream << valueS16;
- break;
- case MVT_S32:
- S32 valueS32;
- readerp->getS32(block_name, var_name, valueS32, block_num);
- stream << valueS32;
- break;
- /*
- case MVT_S64:
- S64 valueS64;
- readerp->getS64(block_name, var_name, valueS64, block_num);
- stream << valueS64;
- break;
- */
- case MVT_F32:
- F32 valueF32;
- readerp->getF32(block_name, var_name, valueF32, block_num);
- stream << valueF32;
- break;
- case MVT_F64:
- F64 valueF64;
- readerp->getF64(block_name, var_name, valueF64, block_num);
- stream << valueF64;
- break;
- case MVT_LLVector3:
- readerp->getVector3(block_name, var_name, valueVector3, block_num);
- //stream << valueVector3;
- stream << "<" << valueVector3.mV[0] << ", " << valueVector3.mV[1] << ", " << valueVector3.mV[2] << ">";
- break;
- case MVT_LLVector3d:
- readerp->getVector3d(block_name, var_name, valueVector3d, block_num);
- //stream << valueVector3d;
- stream << "<" << valueVector3d.mdV[0] << ", " << valueVector3d.mdV[1] << ", " << valueVector3d.mdV[2] << ">";
- break;
- case MVT_LLVector4:
- readerp->getVector4(block_name, var_name, valueVector4, block_num);
- //stream << valueVector4;
- stream << "<" << valueVector4.mV[0] << ", " << valueVector4.mV[1] << ", " << valueVector4.mV[2] << ", " << valueVector4.mV[3] << ">";
- break;
- case MVT_LLQuaternion:
- readerp->getQuat(block_name, var_name, valueQuaternion, block_num);
- //stream << valueQuaternion;
- stream << "<" << valueQuaternion.mQ[0] << ", " << valueQuaternion.mQ[1] << ", " << valueQuaternion.mQ[2] << ", " << valueQuaternion.mQ[3] << ">";
- break;
- case MVT_LLUUID:
- readerp->getUUID(block_name, var_name, valueLLUUID, block_num);
- stream << valueLLUUID;
- break;
- case MVT_BOOL:
- BOOL valueBOOL;
- readerp->getBOOL(block_name, var_name, valueBOOL, block_num);
- stream << valueBOOL;
- break;
- case MVT_IP_ADDR:
- readerp->getIPAddr(block_name, var_name, valueU32, block_num);
- stream << LLHost(valueU32, 0).getIPString();
- break;
- case MVT_IP_PORT:
- readerp->getIPPort(block_name, var_name, valueU16, block_num);
- stream << valueU16;
- case MVT_VARIABLE:
- case MVT_FIXED:
- default:
- S32 size = readerp->getSize(block_name, block_num, var_name);
- if(size)
- {
- value = new char[size + 1];
- readerp->getBinaryData(block_name, var_name, value, size, block_num);
- value[size] = '\0';
- S32 readable = 0;
- S32 unreadable = 0;
- S32 end = (summary_mode && (size > 64)) ? 64 : size;
- for(S32 i = 0; i < end; i++)
- {
- if(!value[i])
- {
- if(i != (end - 1))
- { // don't want null terminator hiding data
- unreadable = S32_MAX;
- break;
- }
- }
- else if(value[i] < 0x20 || value[i] >= 0x7F)
- {
- if(summary_mode)
- unreadable++;
- else
- { // never want any wrong characters outside of summary mode
- unreadable = S32_MAX;
- break;
- }
- }
- else readable++;
- }
- if(readable >= unreadable)
- {
- if(summary_mode && (size > 64))
- {
- for(S32 i = 60; i < 63; i++)
- value[i] = '.';
- value[63] = '\0';
- }
- stream << value;
- }
- else
- {
- returned_hex = TRUE;
- S32 end = (summary_mode && (size > 8)) ? 8 : size;
- for(S32 i = 0; i < end; i++)
- //stream << std::uppercase << std::hex << U32(value[i]) << " ";
- stream << llformat("%02X ", (U8)value[i]);
- if(summary_mode && (size > 8))
- stream << " ... ";
- }
- }
- break;
- }
- return stream.str();
-}
-LLMessageLogFilter::LLMessageLogFilter()
-{
-}
-LLMessageLogFilter::~LLMessageLogFilter()
-{
-}
-BOOL LLMessageLogFilter::set(std::string filter)
-{
- mPositiveNames.clear();
- mNegativeNames.clear();
- typedef boost::tokenizer > tokenizer;
- boost::char_separator sep(" ","",boost::keep_empty_tokens);
- boost::tokenizer > tokens(filter, sep);
- boost::tokenizer >::iterator end = tokens.end();
- for(boost::tokenizer >::iterator iter = tokens.begin(); iter != end; ++iter)
- {
- std::string token = (*iter);
- LLStringUtil::trim(token);
- LLStringUtil::toLower(token);
- BOOL negative = token.find("!") == 0;
- if(negative)
- {
- token = token.substr(1);
- mNegativeNames.push_back(token);
- }
- else
- mPositiveNames.push_back(token);
- }
- return TRUE;
-}
-////////////////////////////////
-// LLMessageLogFilterApply
-////////////////////////////////
-LLMessageLogFilterApply::LLMessageLogFilterApply()
-: LLEventTimer(0.1f),
- mFinished(FALSE),
- mProgress(0)
-{
- mIter = LLFloaterMessageLog::sMessageLogEntries.begin();
-}
-void LLMessageLogFilterApply::cancel()
-{
- mFinished = TRUE;
-}
-BOOL LLMessageLogFilterApply::tick()
-{
- std::deque::iterator end = LLFloaterMessageLog::sMessageLogEntries.end();
- if(mIter == end || !LLFloaterMessageLog::sInstance)
- mFinished = TRUE;
- if(mFinished)
- {
- if(LLFloaterMessageLog::sInstance)
- if(LLFloaterMessageLog::sInstance->mMessageLogFilterApply == this)
- LLFloaterMessageLog::sInstance->stopApplyingFilter();
- return TRUE;
- }
- for(S32 i = 0; i < 256; i++)
- {
- if(mIter == end)
- {
- mFinished = TRUE;
- if(LLFloaterMessageLog::sInstance)
- if(LLFloaterMessageLog::sInstance->mMessageLogFilterApply == this)
- LLFloaterMessageLog::sInstance->stopApplyingFilter();
- return TRUE;
- }
-
- LLFloaterMessageLog::sInstance->conditionalLog(LLFloaterMessageLogItem((*mIter)));
-
- mIter++;
- mProgress++;
- }
- LLFloaterMessageLog::sInstance->updateFilterStatus();
- return FALSE;
-}
-////////////////////////////////
-// LLFloaterMessageLog
-////////////////////////////////
-LLFloaterMessageLog* LLFloaterMessageLog::sInstance;
-std::list LLFloaterMessageLog::sNetListItems;
-std::deque LLFloaterMessageLog::sMessageLogEntries;
-std::vector LLFloaterMessageLog::sFloaterMessageLogItems;
-LLMessageLogFilter LLFloaterMessageLog::sMessageLogFilter = LLMessageLogFilter();
-std::string LLFloaterMessageLog::sMessageLogFilterString("!StartPingCheck !CompletePingCheck !PacketAck !SimulatorViewerTimeMessage !SimStats !AgentUpdate !AgentAnimation !AvatarAnimation !ViewerEffect !CoarseLocationUpdate !LayerData !CameraConstraint !ObjectUpdateCached !RequestMultipleObjects !ObjectUpdate !ObjectUpdateCompressed !ImprovedTerseObjectUpdate !KillObject !ImagePacket !SendXferPacket !ConfirmXferPacket !TransferPacket");
-BOOL LLFloaterMessageLog::sBusyApplyingFilter = FALSE;
-LLFloaterMessageLog::LLFloaterMessageLog()
-: LLFloater(),
- LLEventTimer(1.0f),
- mNetInfoMode(NI_NET),
- mMessageLogFilterApply(NULL)
-{
- sInstance = this;
- LLMessageLog::setCallback(onLog);
- sMessageLogEntries = LLMessageLog::getDeque();
- LLUICtrlFactory::getInstance()->buildFloater(this, "floater_message_log.xml");
-}
-LLFloaterMessageLog::~LLFloaterMessageLog()
-{
- LLMessageLog::setCallback(NULL);
- stopApplyingFilter();
- sInstance = NULL;
- sNetListItems.clear();
- sMessageLogEntries.clear();
- sFloaterMessageLogItems.clear();
-}
-// static
-void LLFloaterMessageLog::show()
-{
- if(!sInstance) sInstance = new LLFloaterMessageLog();
- sInstance->open();
-}
-BOOL LLFloaterMessageLog::postBuild()
-{
- childSetCommitCallback("net_list", onCommitNetList, this);
- childSetCommitCallback("message_log", onCommitMessageLog, this);
- childSetAction("filter_choice_btn", onClickFilterChoice, this);
- childSetAction("filter_apply_btn", onClickFilterApply, this);
- childSetCommitCallback("filter_edit", onCommitFilter, this);
- childSetAction("clear_log_btn", onClickClearLog, this);
- childSetAction("send_to_message_builder_btn", onClickSendToMessageBuilder, this);
- childSetText("filter_edit", sMessageLogFilterString);
- refreshNetList();
- refreshNetInfo(TRUE);
- startApplyingFilter(sMessageLogFilterString, TRUE);
- return TRUE;
-}
-BOOL LLFloaterMessageLog::tick()
-{
- refreshNetList();
- refreshNetInfo(FALSE);
- return FALSE;
-}
-LLNetListItem* LLFloaterMessageLog::findNetListItem(LLHost host)
-{
- std::list::iterator end = sNetListItems.end();
- for(std::list::iterator iter = sNetListItems.begin(); iter != end; ++iter)
- if((*iter)->mCircuitData && (*iter)->mCircuitData->getHost() == host)
- return (*iter);
- return NULL;
-}
-LLNetListItem* LLFloaterMessageLog::findNetListItem(LLUUID id)
-{
- std::list::iterator end = sNetListItems.end();
- for(std::list::iterator iter = sNetListItems.begin(); iter != end; ++iter)
- if((*iter)->mID == id)
- return (*iter);
- return NULL;
-}
-void LLFloaterMessageLog::refreshNetList()
-{
- LLScrollListCtrl* scrollp = getChild("net_list");
- // Update circuit data of net list items
- std::vector circuits = gMessageSystem->getCircuit()->getCircuitDataList();
- std::vector::iterator circuits_end = circuits.end();
- for(std::vector::iterator iter = circuits.begin(); iter != circuits_end; ++iter)
- {
- LLNetListItem* itemp = findNetListItem((*iter)->getHost());
- if(!itemp)
- {
- LLUUID id; id.generate();
- itemp = new LLNetListItem(id);
- sNetListItems.push_back(itemp);
- }
- itemp->mCircuitData = (*iter);
- }
- // Clear circuit data of items whose circuits are gone
- std::list::iterator items_end = sNetListItems.end();
- for(std::list::iterator iter = sNetListItems.begin(); iter != items_end; ++iter)
- {
- if(std::find(circuits.begin(), circuits.end(), (*iter)->mCircuitData) == circuits.end())
- (*iter)->mCircuitData = NULL;
- }
- // Remove net list items that are totally useless now
- for(std::list::iterator iter = sNetListItems.begin(); iter != sNetListItems.end();)
- {
- if((*iter)->mCircuitData == NULL)
- iter = sNetListItems.erase(iter);
- else ++iter;
- }
- // Update names of net list items
- items_end = sNetListItems.end();
- for(std::list::iterator iter = sNetListItems.begin(); iter != items_end; ++iter)
- {
- LLNetListItem* itemp = (*iter);
- if(itemp->mAutoName)
- {
- if(itemp->mCircuitData)
- {
- LLViewerRegion* regionp = LLWorld::getInstance()->getRegion(itemp->mCircuitData->getHost());
- if(regionp)
- {
- std::string name = regionp->getName();
- if(name == "") name = llformat("%s (awaiting region name)", itemp->mCircuitData->getHost().getString().c_str());
- itemp->mName = name;
- itemp->mPreviousRegionName = name;
- }
- else
- {
- itemp->mName = itemp->mCircuitData->getHost().getString();
- if(itemp->mPreviousRegionName != "")
- itemp->mName.append(llformat(" (was %s)", itemp->mPreviousRegionName.c_str()));
- }
- }
- else
- {
- // an item just for an event queue, not handled yet
- itemp->mName = "Something else";
- }
- }
- }
- // Rebuild scroll list from scratch
- LLUUID selected_id = scrollp->getFirstSelected() ? scrollp->getFirstSelected()->getUUID() : LLUUID::null;
- S32 scroll_pos = scrollp->getScrollPos();
- scrollp->clearRows();
- for(std::list::iterator iter = sNetListItems.begin(); iter != items_end; ++iter)
- {
- LLNetListItem* itemp = (*iter);
- LLSD element;
- element["id"] = itemp->mID;
- LLSD& text_column = element["columns"][0];
- text_column["column"] = "text";
- text_column["value"] = itemp->mName + (itemp->mCircuitData->getHost() == gAgent.getRegionHost() ? " (main)" : "");
- for(int i = 0; i < 3; i++)
- {
- LLSD& icon_column = element["columns"][i + 1];
- icon_column["column"] = llformat("icon%d", i);
- icon_column["type"] = "icon";
- icon_column["value"] = "";
- }
- LLScrollListItem* scroll_itemp = scrollp->addElement(element);
- BOOL has_live_circuit = itemp->mCircuitData && itemp->mCircuitData->isAlive();
- if(has_live_circuit)
- {
- LLScrollListIcon* icon = (LLScrollListIcon*)scroll_itemp->getColumn(2);
- icon->setValue("icon_net_close_circuit.tga");
- icon->setClickCallback(onClickCloseCircuit, itemp);
- }
- else
- {
- LLScrollListIcon* icon = (LLScrollListIcon*)scroll_itemp->getColumn(2);
- icon->setValue("icon_net_close_circuit_gray.tga");
- icon->setClickCallback(NULL, NULL);
- }
- // Event queue isn't even supported yet... FIXME
- LLScrollListIcon* icon = (LLScrollListIcon*)scroll_itemp->getColumn(3);
- icon->setValue("icon_net_close_eventpoll_gray.tga");
- icon->setClickCallback(NULL, NULL);
- }
- if(selected_id.notNull()) scrollp->selectByID(selected_id);
- if(scroll_pos < scrollp->getItemCount()) scrollp->setScrollPos(scroll_pos);
-}
-void LLFloaterMessageLog::refreshNetInfo(BOOL force)
-{
- if(mNetInfoMode != NI_NET) return;
- LLScrollListCtrl* scrollp = getChild("net_list");
- LLScrollListItem* selected_itemp = scrollp->getFirstSelected();
- if(selected_itemp)
- {
- if(!force) if(getChild("net_info")->hasSelection()) return;
- LLNetListItem* itemp = findNetListItem(selected_itemp->getUUID());
- if(itemp)
- {
- std::string info(llformat("%s\n--------------------------------\n\n", itemp->mName.c_str()));
- if(itemp->mCircuitData)
- {
- LLCircuitData* cdp = itemp->mCircuitData;
- info.append("Circuit\n--------------------------------\n");
- info.append(llformat(" * Host: %s\n", cdp->getHost().getString().c_str()));
- S32 seconds = (S32)cdp->getAgeInSeconds();
- S32 minutes = seconds / 60;
- seconds = seconds % 60;
- S32 hours = minutes / 60;
- minutes = minutes % 60;
- info.append(llformat(" * Age: %dh %dm %ds\n", hours, minutes, seconds));
- info.append(llformat(" * Alive: %s\n", cdp->isAlive() ? "yes" : "no"));
- info.append(llformat(" * Blocked: %s\n", cdp->isBlocked() ? "yes" : "no"));
- info.append(llformat(" * Allow timeout: %s\n", cdp->getAllowTimeout() ? "yes" : "no"));
- info.append(llformat(" * Trusted: %s\n", cdp->getTrusted() ? "yes" : "no"));
- info.append(llformat(" * Ping delay: %d\n", cdp->getPingDelay()));
- info.append(llformat(" * Packets out: %d\n", cdp->getPacketsOut()));
- info.append(llformat(" * Bytes out: %d\n", cdp->getBytesOut()));
- info.append(llformat(" * Packets in: %d\n", cdp->getPacketsIn()));
- info.append(llformat(" * Bytes in: %d\n", cdp->getBytesIn()));
- info.append(llformat(" * Endpoint ID: %s\n", cdp->getLocalEndPointID().asString().c_str()));
- info.append(llformat(" * Remote ID: %s\n", cdp->getRemoteID().asString().c_str()));
- info.append(llformat(" * Remote session ID: %s\n", cdp->getRemoteSessionID().asString().c_str()));
- }
- childSetText("net_info", info);
- }
- else childSetText("net_info", std::string(""));
- }
- else childSetText("net_info", std::string(""));
-}
-void LLFloaterMessageLog::setNetInfoMode(ENetInfoMode mode)
-{
- mNetInfoMode = mode;
- if(mNetInfoMode == NI_NET)
- refreshNetInfo(TRUE);
- childSetEnabled("send_to_message_builder_btn", mNetInfoMode == NI_LOG);
-}
-// static
-void LLFloaterMessageLog::onLog(LLMessageLogEntry entry)
-{
- sMessageLogEntries.push_back(entry);
- if(!sBusyApplyingFilter)
- conditionalLog(LLFloaterMessageLogItem(entry));
-}
-// static
-void LLFloaterMessageLog::conditionalLog(LLFloaterMessageLogItem item)
-{
- if(!sBusyApplyingFilter)
- sInstance->childSetText("log_status_text", llformat("Showing %d messages from %d", sFloaterMessageLogItems.size(), sMessageLogEntries.size()));
- std::string find_name = item.mName;
- LLStringUtil::toLower(find_name);
- if(sMessageLogFilter.mPositiveNames.size())
- if(std::find(sMessageLogFilter.mPositiveNames.begin(), sMessageLogFilter.mPositiveNames.end(), find_name) == sMessageLogFilter.mPositiveNames.end())
- return;
- if(std::find(sMessageLogFilter.mNegativeNames.begin(), sMessageLogFilter.mNegativeNames.end(), find_name) != sMessageLogFilter.mNegativeNames.end())
- return;
- sFloaterMessageLogItems.push_back(item); // moved from beginning...
- BOOL outgoing = item.isOutgoing();
- std::string net_name("\?\?\?");
- if(item.mType == LLFloaterMessageLogItem::TEMPLATE)
- {
- LLHost find_host = outgoing ? item.mToHost : item.mFromHost;
- net_name = find_host.getIPandPort();
- std::list::iterator end = sNetListItems.end();
- for(std::list::iterator iter = sNetListItems.begin(); iter != end; ++iter)
- {
- if((*iter)->mCircuitData->getHost() == find_host)
- {
- net_name = (*iter)->mName;
- break;
- }
- }
- }
- LLSD element;
- element["id"] = item.mID;
- LLSD& sequence_column = element["columns"][0];
- sequence_column["column"] = "sequence";
- sequence_column["value"] = llformat("%u", item.mSequenceID);
- LLSD& type_column = element["columns"][1];
- type_column["column"] = "type";
- type_column["value"] = item.mType == LLFloaterMessageLogItem::TEMPLATE ? "UDP" : "\?\?\?";
- LLSD& direction_column = element["columns"][2];
- direction_column["column"] = "direction";
- direction_column["value"] = outgoing ? "to" : "from";
- LLSD& net_column = element["columns"][3];
- net_column["column"] = "net";
- net_column["value"] = net_name;
- LLSD& name_column = element["columns"][4];
- name_column["column"] = "name";
- name_column["value"] = item.mName;
- /*
- LLSD& zer_column = element["columns"][5];
- zer_column["column"] = "flag_zer";
- zer_column["type"] = "icon";
- zer_column["value"] = (item.mFlags & LL_ZERO_CODE_FLAG) ? "flag_zer.tga" : "";
- LLSD& rel_column = element["columns"][6];
- rel_column["column"] = "flag_rel";
- rel_column["type"] = "icon";
- rel_column["value"] = (item.mFlags & LL_RELIABLE_FLAG) ? "flag_rel.tga" : "";
- LLSD& rsd_column = element["columns"][7];
- rsd_column["column"] = "flag_rsd";
- rsd_column["type"] = "icon";
- rsd_column["value"] = (item.mFlags & LL_RESENT_FLAG) ? "flag_rsd.tga" : "";
- LLSD& ack_column = element["columns"][8];
- ack_column["column"] = "flag_ack";
- ack_column["type"] = "icon";
- ack_column["value"] = (item.mFlags & LL_ACK_FLAG) ? "flag_ack.tga" : "";
- */
- LLSD& summary_column = element["columns"][5];
- summary_column["column"] = "summary";
- summary_column["value"] = item.mSummary;
- LLScrollListCtrl* scrollp = sInstance->getChild("message_log");
- S32 scroll_pos = scrollp->getScrollPos();
- scrollp->addElement(element);
- if(scroll_pos > scrollp->getItemCount() - scrollp->getPageLines() - 4)
- scrollp->setScrollPos(scrollp->getItemCount());
-}
-// static
-void LLFloaterMessageLog::onCommitNetList(LLUICtrl* ctrl, void* user_data)
-{
- LLFloaterMessageLog* floaterp = (LLFloaterMessageLog*)user_data;
- floaterp->setNetInfoMode(NI_NET);
- floaterp->refreshNetInfo(TRUE);
-}
-// static
-void LLFloaterMessageLog::onCommitMessageLog(LLUICtrl* ctrl, void* user_data)
-{
- LLFloaterMessageLog* floaterp = (LLFloaterMessageLog*)user_data;
- LLScrollListCtrl* scrollp = floaterp->getChild("message_log");
- LLScrollListItem* selected_itemp = scrollp->getFirstSelected();
- if(!selected_itemp) return;
- LLUUID id = selected_itemp->getUUID();
- std::vector::iterator end = sFloaterMessageLogItems.end();
- for(std::vector::iterator iter = sFloaterMessageLogItems.begin(); iter != end; ++iter)
- {
- if(iter->mID == id)
- {
- floaterp->setNetInfoMode(NI_LOG);
- floaterp->childSetText("net_info", iter->getFull(FALSE));
- break;
- }
- }
-}
-// static
-BOOL LLFloaterMessageLog::onClickCloseCircuit(void* user_data)
-{
- LLNetListItem* itemp = (LLNetListItem*)user_data;
- LLCircuitData* cdp = (LLCircuitData*)itemp->mCircuitData;
- if(!cdp) return FALSE;
- LLHost myhost = cdp->getHost();
- LLSD args;
- args["MESSAGE"] = "This will delete local circuit data.\nDo you want to tell the remote host to close the circuit too?";
- LLSD payload;
- payload["circuittoclose"] = myhost.getString();
- LLNotifications::instance().add("GenericAlertYesCancel", args, payload, onConfirmCloseCircuit);
- return TRUE;
-}
-// static
-void LLFloaterMessageLog::onConfirmCloseCircuit(S32 option, LLSD payload)
-{
- LLCircuitData* cdp = gMessageSystem->mCircuitInfo.findCircuit(LLHost(payload["circuittoclose"].asString()));
- if(!cdp) return;
- LLViewerRegion* regionp = LLWorld::getInstance()->getRegion(cdp->getHost());
- switch(option)
- {
- case 0: // yes
- gMessageSystem->newMessageFast(_PREHASH_CloseCircuit);
- gMessageSystem->sendReliable(cdp->getHost());
- break;
- case 2: // cancel
- return;
- break;
- case 1: // no
- default:
- break;
- }
- if(gMessageSystem->findCircuitCode(cdp->getHost()))
- gMessageSystem->disableCircuit(cdp->getHost());
- else
- gMessageSystem->getCircuit()->removeCircuitData(cdp->getHost());
- if(regionp)
- {
- LLHost myhost = regionp->getHost();
- LLSD args;
- args["MESSAGE"] = "That host had a region associated with it.\nDo you want to clean that up?";
- LLSD payload;
- payload["regionhost"] = myhost.getString();
- LLNotifications::instance().add("GenericAlertYesCancel", args, payload, onConfirmRemoveRegion);
- }
-}
-// static
-void LLFloaterMessageLog::onConfirmRemoveRegion(S32 option, LLSD payload)
-{
- if(option == 0) // yes
- LLWorld::getInstance()->removeRegion(LLHost(payload["regionhost"].asString()));
-}
-// static
-void LLFloaterMessageLog::onClickFilterApply(void* user_data)
-{
- LLFloaterMessageLog* floaterp = (LLFloaterMessageLog*)user_data;
- floaterp->startApplyingFilter(floaterp->childGetValue("filter_edit"), FALSE);
-}
-void LLFloaterMessageLog::startApplyingFilter(std::string filter, BOOL force)
-{
- LLMessageLogFilter new_filter = LLMessageLogFilter();
- sMessageLogFilterString = filter;
- new_filter.set(sMessageLogFilterString);
- childSetText("filter_edit", filter + " ");
- if(force
- || (new_filter.mNegativeNames != sMessageLogFilter.mNegativeNames)
- || (new_filter.mPositiveNames != sMessageLogFilter.mPositiveNames))
- {
- stopApplyingFilter();
- sMessageLogFilter = new_filter;
- sFloaterMessageLogItems.clear();
- getChild("message_log")->clearRows();
- sBusyApplyingFilter = TRUE;
- childSetVisible("message_log", false);
- //childSetVisible("log_status_text", true);
- mMessageLogFilterApply = new LLMessageLogFilterApply();
- }
-}
-void LLFloaterMessageLog::stopApplyingFilter()
-{
- if(mMessageLogFilterApply)
- {
- if(!(mMessageLogFilterApply->mFinished))
- mMessageLogFilterApply->cancel();
- //delete mMessageLogFilterApply;
- sBusyApplyingFilter = FALSE;
- //childSetVisible("log_status_text", false);
- childSetVisible("message_log", true);
- childSetText("log_status_text", llformat("Showing %d messages from %d", sFloaterMessageLogItems.size(), sMessageLogEntries.size()));
- }
-}
-void LLFloaterMessageLog::updateFilterStatus()
-{
- if(!mMessageLogFilterApply || !sBusyApplyingFilter) return;
- S32 progress = mMessageLogFilterApply->mProgress;
- S32 packets = sMessageLogEntries.size();
- S32 matches = sFloaterMessageLogItems.size();
- std::string text = llformat("Applying filter ( %d / %d ), %d matches ...", progress, packets, matches);
- childSetText("log_status_text", text);
-}
-// static
-void LLFloaterMessageLog::onCommitFilter(LLUICtrl* ctrl, void* user_data)
-{
- LLFloaterMessageLog* floaterp = (LLFloaterMessageLog*)user_data;
- floaterp->startApplyingFilter(floaterp->childGetValue("filter_edit"), FALSE);
-}
-// static
-void LLFloaterMessageLog::onClickClearLog(void* user_data)
-{
- LLFloaterMessageLog* floaterp = (LLFloaterMessageLog*)user_data;
- floaterp->stopApplyingFilter();
- floaterp->getChild("message_log")->clearRows();
- floaterp->setNetInfoMode(NI_NET);
- sMessageLogEntries.clear();
- sFloaterMessageLogItems.clear();
-}
-// static
-void LLFloaterMessageLog::onClickFilterChoice(void* user_data)
-{
- LLMenuGL* menu = new LLMenuGL(LLStringUtil::null);
- menu->append(new LLMenuItemCallGL("No filter", onClickFilterMenu, NULL, (void*)""));
- menu->append(new LLMenuItemCallGL("Fewer spammy messages", onClickFilterMenu, NULL, (void*)"!StartPingCheck !CompletePingCheck !PacketAck !SimulatorViewerTimeMessage !SimStats !AgentUpdate !AgentAnimation !AvatarAnimation !ViewerEffect !CoarseLocationUpdate !LayerData !CameraConstraint !ObjectUpdateCached !RequestMultipleObjects !ObjectUpdate !ObjectUpdateCompressed !ImprovedTerseObjectUpdate !KillObject !ImagePacket !SendXferPacket !ConfirmXferPacket !TransferPacket"));
- menu->append(new LLMenuItemCallGL("Object updates", onClickFilterMenu, NULL, (void*)"ObjectUpdateCached ObjectUpdate ObjectUpdateCompressed ImprovedTerseObjectUpdate KillObject RequestMultipleObjects"));
- menu->append(new LLMenuItemCallGL("Abnormal", onClickFilterMenu, NULL, (void*)"Invalid TestMessage AddCircuitCode NeighborList AvatarTextureUpdate SimulatorMapUpdate SimulatorSetMap SubscribeLoad UnsubscribeLoad SimulatorReady SimulatorPresentAtLocation SimulatorLoad SimulatorShutdownRequest RegionPresenceRequestByRegionID RegionPresenceRequestByHandle RegionPresenceResponse UpdateSimulator LogDwellTime FeatureDisabled LogFailedMoneyTransaction UserReportInternal SetSimStatusInDatabase SetSimPresenceInDatabase OpenCircuit CloseCircuit DirFindQueryBackend DirPlacesQueryBackend DirClassifiedQueryBackend DirLandQueryBackend DirPopularQueryBackend GroupNoticeAdd DataHomeLocationRequest DataHomeLocationReply DerezContainer ObjectCategory ObjectExportSelected StateSave ReportAutosaveCrash AgentAlertMessage NearestLandingRegionRequest NearestLandingRegionReply NearestLandingRegionUpdated TeleportLandingStatusChanged ConfirmEnableSimulator KickUserAck SystemKickUser AvatarPropertiesRequestBackend UpdateParcel RemoveParcel MergeParcel LogParcelChanges CheckParcelSales ParcelSales StartAuction ConfirmAuctionStart CompleteAuction CancelAuction CheckParcelAuctions ParcelAuctions ChatPass EdgeDataPacket SimStatus ChildAgentUpdate ChildAgentAlive ChildAgentPositionUpdate ChildAgentDying ChildAgentUnknown AtomicPassObject KillChildAgents ScriptSensorRequest ScriptSensorReply DataServerLogout RequestInventoryAsset InventoryAssetResponse TransferInventory TransferInventoryAck EventLocationRequest EventLocationReply MoneyTransferBackend RoutedMoneyBalanceReply SetStartLocation NetTest SetCPURatio SimCrashed NameValuePair RemoveNameValuePair UpdateAttachment RemoveAttachment EmailMessageRequest EmailMessageReply InternalScriptMail ScriptDataRequest ScriptDataReply InviteGroupResponse TallyVotes LiveHelpGroupRequest LiveHelpGroupReply GroupDataUpdate LogTextMessage CreateTrustedCircuit ParcelRename SystemMessage RpcChannelRequest RpcChannelReply RpcScriptRequestInbound RpcScriptRequestInboundForward RpcScriptReplyInbound ScriptMailRegistration Error"));
- menu->updateParent(LLMenuGL::sMenuContainer);
- menu->setCanTearOff(FALSE);
- LLView* buttonp = sInstance->getChild("filter_choice_btn");
- S32 x = buttonp->getRect().mLeft;
- S32 y = buttonp->getRect().mBottom;
- LLMenuGL::showPopup(sInstance, menu, x, y);
-}
-// static
-void LLFloaterMessageLog::onClickFilterMenu(void* user_data)
-{
- std::string filter = std::string((char*)user_data);
- sInstance->childSetText("filter_edit", filter);
- sInstance->startApplyingFilter(filter, FALSE);
-}
-// static
-void LLFloaterMessageLog::onClickSendToMessageBuilder(void* user_data)
-{
- LLFloaterMessageLog* floaterp = (LLFloaterMessageLog*)user_data;
- LLScrollListCtrl* scrollp = floaterp->getChild("message_log");
- LLScrollListItem* selected_itemp = scrollp->getFirstSelected();
- if(!selected_itemp) return;
- LLUUID id = selected_itemp->getUUID();
- std::vector::iterator end = sFloaterMessageLogItems.end();
- for(std::vector::iterator iter = sFloaterMessageLogItems.begin(); iter != end; ++iter)
- {
- if(iter->mID == id)
- {
- std::string message_text = iter->getFull(FALSE);
- LLFloaterMessageBuilder::show(message_text);
- break;
- }
- }
-}
-//
+//
+#include "llviewerprecompiledheaders.h"
+#include "llfloatermessagelog.h"
+#include "lluictrlfactory.h"
+#include "llworld.h"
+#include "llviewerregion.h"
+#include "llscrolllistctrl.h"
+#include "lltexteditor.h"
+#include "llviewerwindow.h" // alertXml
+#include "llmessagetemplate.h"
+#include
+#include "llmenugl.h"
+#include "llfloatermessagebuilder.h"
+#include "llagent.h"
+////////////////////////////////
+// LLNetListItem
+////////////////////////////////
+LLNetListItem::LLNetListItem(LLUUID id)
+: mID(id),
+ mAutoName(TRUE),
+ mName("No name"),
+ mPreviousRegionName(""),
+ mCircuitData(NULL)
+{
+}
+////////////////////////////////
+// LLFloaterMessageLogItem
+////////////////////////////////
+U8 LLFloaterMessageLogItem::sDecodeBuffer[8192];
+LLTemplateMessageReader* LLFloaterMessageLogItem::sTemplateMessageReader = NULL;
+LLFloaterMessageLogItem::LLFloaterMessageLogItem(LLMessageLogEntry entry)
+: LLMessageLogEntry(entry.mType, entry.mFromHost, entry.mToHost, entry.mData, entry.mDataSize)
+{
+ if(!sTemplateMessageReader)
+ {
+ sTemplateMessageReader = new LLTemplateMessageReader(gMessageSystem->mMessageNumbers);
+ }
+ mID.generate();
+ mSequenceID = 0;
+ if(mType == TEMPLATE)
+ {
+ BOOL decode_invalid = FALSE;
+ S32 decode_len = mDataSize;
+ memcpy(sDecodeBuffer, mData, decode_len);
+ mFlags = sDecodeBuffer[0];
+ U8* decodep = &(sDecodeBuffer[0]);
+ gMessageSystem->zeroCodeExpand(&decodep, &decode_len);
+ if(decode_len < 7)
+ decode_invalid = TRUE;
+ else
+ {
+ mSequenceID = ntohl(*((U32*)(&decodep[1])));
+ sTemplateMessageReader->clearMessage();
+ if(!sTemplateMessageReader->validateMessage(decodep, decode_len, mFromHost, TRUE))
+ decode_invalid = TRUE;
+ else
+ {
+ if(!sTemplateMessageReader->decodeData(decodep, mFromHost, TRUE))
+ decode_invalid = TRUE;
+ else
+ {
+ LLMessageTemplate* temp = sTemplateMessageReader->getTemplate();
+ mName = temp->mName;
+ mSummary = "";
+
+ if(mFlags)
+ {
+ mSummary.append(" [ ");
+ if(mFlags & LL_ZERO_CODE_FLAG)
+ mSummary.append(" Zer ");
+ if(mFlags & LL_RELIABLE_FLAG)
+ mSummary.append(" Rel ");
+ if(mFlags & LL_RESENT_FLAG)
+ mSummary.append(" Rsd ");
+ if(mFlags & LL_ACK_FLAG)
+ mSummary.append(" Ack ");
+ mSummary.append(" ] ");
+ }
+
+ LLMessageTemplate::message_block_map_t::iterator blocks_end = temp->mMemberBlocks.end();
+ for (LLMessageTemplate::message_block_map_t::iterator blocks_iter = temp->mMemberBlocks.begin();
+ blocks_iter != blocks_end; ++blocks_iter)
+ {
+ LLMessageBlock* block = (*blocks_iter);
+ const char* block_name = block->mName;
+ S32 num_blocks = sTemplateMessageReader->getNumberOfBlocks(block_name);
+ if(!num_blocks)
+ mSummary.append(" { } ");
+ else if(num_blocks > 1)
+ mSummary.append(llformat(" %s [ %d ] { ... } ", block_name, num_blocks));
+ else for(S32 i = 0; i < 1; i++)
+ {
+ mSummary.append(" { ");
+ LLMessageBlock::message_variable_map_t::iterator var_end = block->mMemberVariables.end();
+ for (LLMessageBlock::message_variable_map_t::iterator var_iter = block->mMemberVariables.begin();
+ var_iter != var_end; ++var_iter)
+ {
+ LLMessageVariable* variable = (*var_iter);
+ const char* var_name = variable->getName();
+ BOOL returned_hex;
+ std::string value = getString(sTemplateMessageReader, block_name, i, var_name, variable->getType(), returned_hex, TRUE);
+ mSummary.append(llformat(" %s=%s ", var_name, value.c_str()));
+ }
+ mSummary.append(" } ");
+ if(mSummary.length() > 255) break;
+ }
+ if(mSummary.length() > 255)
+ {
+ mSummary.append(" ... ");
+ break;
+ }
+ } // blocks_iter
+ } // decode_valid
+ }
+ }
+ if(decode_invalid)
+ {
+ mName = "Invalid";
+ mSummary = "";
+ for(S32 i = 0; i < mDataSize; i++)
+ mSummary.append(llformat("%02X ", mData[i]));
+ }
+ }
+ else // not template
+ {
+ mName = "SOMETHING ELSE";
+ mSummary = "TODO: SOMETHING ELSE";
+ }
+}
+LLFloaterMessageLogItem::~LLFloaterMessageLogItem()
+{
+}
+BOOL LLFloaterMessageLogItem::isOutgoing()
+{
+ return mFromHost == LLHost(16777343, gMessageSystem->getListenPort());
+}
+std::string LLFloaterMessageLogItem::getFull(BOOL show_header)
+{
+ std::string full("");
+ if(mType == TEMPLATE)
+ {
+ BOOL decode_invalid = FALSE;
+ S32 decode_len = mDataSize;
+ memcpy(sDecodeBuffer, mData, decode_len);
+ U8* decodep = &(sDecodeBuffer[0]);
+ gMessageSystem->zeroCodeExpand(&decodep, &decode_len);
+ if(decode_len < 7)
+ decode_invalid = TRUE;
+ else
+ {
+ sTemplateMessageReader->clearMessage();
+ if(!sTemplateMessageReader->validateMessage(decodep, decode_len, mFromHost, TRUE))
+ decode_invalid = TRUE;
+ else
+ {
+ if(!sTemplateMessageReader->decodeData(decodep, mFromHost, TRUE))
+ decode_invalid = TRUE;
+ else
+ {
+ LLMessageTemplate* temp = sTemplateMessageReader->getTemplate();
+ full.append(isOutgoing() ? "out " : "in ");
+ full.append(llformat("%s\n", temp->mName));
+ if(show_header)
+ {
+ full.append("[Header]\n");
+ full.append(llformat("SequenceID = %u\n", mSequenceID));
+ full.append(llformat("LL_ZERO_CODE_FLAG = %s\n", (mFlags & LL_ZERO_CODE_FLAG) ? "True" : "False"));
+ full.append(llformat("LL_RELIABLE_FLAG = %s\n", (mFlags & LL_RELIABLE_FLAG) ? "True" : "False"));
+ full.append(llformat("LL_RESENT_FLAG = %s\n", (mFlags & LL_RESENT_FLAG) ? "True" : "False"));
+ full.append(llformat("LL_ACK_FLAG = %s\n", (mFlags & LL_ACK_FLAG) ? "True" : "False"));
+ }
+ LLMessageTemplate::message_block_map_t::iterator blocks_end = temp->mMemberBlocks.end();
+ for (LLMessageTemplate::message_block_map_t::iterator blocks_iter = temp->mMemberBlocks.begin();
+ blocks_iter != blocks_end; ++blocks_iter)
+ {
+ LLMessageBlock* block = (*blocks_iter);
+ const char* block_name = block->mName;
+ S32 num_blocks = sTemplateMessageReader->getNumberOfBlocks(block_name);
+ for(S32 i = 0; i < num_blocks; i++)
+ {
+ full.append(llformat("[%s]\n", block->mName));
+ LLMessageBlock::message_variable_map_t::iterator var_end = block->mMemberVariables.end();
+ for (LLMessageBlock::message_variable_map_t::iterator var_iter = block->mMemberVariables.begin();
+ var_iter != var_end; ++var_iter)
+ {
+ LLMessageVariable* variable = (*var_iter);
+ const char* var_name = variable->getName();
+ BOOL returned_hex;
+ std::string value = getString(sTemplateMessageReader, block_name, i, var_name, variable->getType(), returned_hex);
+ if(returned_hex)
+ full.append(llformat("%s =| ", var_name));
+ else
+ full.append(llformat("%s = ", var_name));
+ // llformat has a 1024 char limit!?
+ full.append(value);
+ full.append("\n");
+ }
+ }
+ } // blocks_iter
+ } // decode_valid
+ }
+ }
+ if(decode_invalid)
+ {
+ full = isOutgoing() ? "out" : "in";
+ full.append("\n");
+ for(S32 i = 0; i < mDataSize; i++)
+ full.append(llformat("%02X ", mData[i]));
+ }
+ }
+ else // not template
+ {
+ full = "FIXME";
+ }
+ return full;
+}
+// static
+std::string LLFloaterMessageLogItem::getString(LLTemplateMessageReader* readerp, const char* block_name, S32 block_num, const char* var_name, e_message_variable_type var_type, BOOL &returned_hex, BOOL summary_mode)
+{
+ returned_hex = FALSE;
+ std::stringstream stream;
+ char* value;
+ U32 valueU32;
+ U16 valueU16;
+ LLVector3 valueVector3;
+ LLVector3d valueVector3d;
+ LLVector4 valueVector4;
+ LLQuaternion valueQuaternion;
+ LLUUID valueLLUUID;
+ switch(var_type)
+ {
+ case MVT_U8:
+ U8 valueU8;
+ readerp->getU8(block_name, var_name, valueU8, block_num);
+ stream << U32(valueU8);
+ break;
+ case MVT_U16:
+ readerp->getU16(block_name, var_name, valueU16, block_num);
+ stream << valueU16;
+ break;
+ case MVT_U32:
+ readerp->getU32(block_name, var_name, valueU32, block_num);
+ stream << valueU32;
+ break;
+ case MVT_U64:
+ U64 valueU64;
+ readerp->getU64(block_name, var_name, valueU64, block_num);
+ stream << valueU64;
+ break;
+ case MVT_S8:
+ S8 valueS8;
+ readerp->getS8(block_name, var_name, valueS8, block_num);
+ stream << S32(valueS8);
+ break;
+ case MVT_S16:
+ S16 valueS16;
+ readerp->getS16(block_name, var_name, valueS16, block_num);
+ stream << valueS16;
+ break;
+ case MVT_S32:
+ S32 valueS32;
+ readerp->getS32(block_name, var_name, valueS32, block_num);
+ stream << valueS32;
+ break;
+ /*
+ case MVT_S64:
+ S64 valueS64;
+ readerp->getS64(block_name, var_name, valueS64, block_num);
+ stream << valueS64;
+ break;
+ */
+ case MVT_F32:
+ F32 valueF32;
+ readerp->getF32(block_name, var_name, valueF32, block_num);
+ stream << valueF32;
+ break;
+ case MVT_F64:
+ F64 valueF64;
+ readerp->getF64(block_name, var_name, valueF64, block_num);
+ stream << valueF64;
+ break;
+ case MVT_LLVector3:
+ readerp->getVector3(block_name, var_name, valueVector3, block_num);
+ //stream << valueVector3;
+ stream << "<" << valueVector3.mV[0] << ", " << valueVector3.mV[1] << ", " << valueVector3.mV[2] << ">";
+ break;
+ case MVT_LLVector3d:
+ readerp->getVector3d(block_name, var_name, valueVector3d, block_num);
+ //stream << valueVector3d;
+ stream << "<" << valueVector3d.mdV[0] << ", " << valueVector3d.mdV[1] << ", " << valueVector3d.mdV[2] << ">";
+ break;
+ case MVT_LLVector4:
+ readerp->getVector4(block_name, var_name, valueVector4, block_num);
+ //stream << valueVector4;
+ stream << "<" << valueVector4.mV[0] << ", " << valueVector4.mV[1] << ", " << valueVector4.mV[2] << ", " << valueVector4.mV[3] << ">";
+ break;
+ case MVT_LLQuaternion:
+ readerp->getQuat(block_name, var_name, valueQuaternion, block_num);
+ //stream << valueQuaternion;
+ stream << "<" << valueQuaternion.mQ[0] << ", " << valueQuaternion.mQ[1] << ", " << valueQuaternion.mQ[2] << ", " << valueQuaternion.mQ[3] << ">";
+ break;
+ case MVT_LLUUID:
+ readerp->getUUID(block_name, var_name, valueLLUUID, block_num);
+ stream << valueLLUUID;
+ break;
+ case MVT_BOOL:
+ BOOL valueBOOL;
+ readerp->getBOOL(block_name, var_name, valueBOOL, block_num);
+ stream << valueBOOL;
+ break;
+ case MVT_IP_ADDR:
+ readerp->getIPAddr(block_name, var_name, valueU32, block_num);
+ stream << LLHost(valueU32, 0).getIPString();
+ break;
+ case MVT_IP_PORT:
+ readerp->getIPPort(block_name, var_name, valueU16, block_num);
+ stream << valueU16;
+ case MVT_VARIABLE:
+ case MVT_FIXED:
+ default:
+ S32 size = readerp->getSize(block_name, block_num, var_name);
+ if(size)
+ {
+ value = new char[size + 1];
+ readerp->getBinaryData(block_name, var_name, value, size, block_num);
+ value[size] = '\0';
+ S32 readable = 0;
+ S32 unreadable = 0;
+ S32 end = (summary_mode && (size > 64)) ? 64 : size;
+ for(S32 i = 0; i < end; i++)
+ {
+ if(!value[i])
+ {
+ if(i != (end - 1))
+ { // don't want null terminator hiding data
+ unreadable = S32_MAX;
+ break;
+ }
+ }
+ else if(value[i] < 0x20 || value[i] >= 0x7F)
+ {
+ if(summary_mode)
+ unreadable++;
+ else
+ { // never want any wrong characters outside of summary mode
+ unreadable = S32_MAX;
+ break;
+ }
+ }
+ else readable++;
+ }
+ if(readable >= unreadable)
+ {
+ if(summary_mode && (size > 64))
+ {
+ for(S32 i = 60; i < 63; i++)
+ value[i] = '.';
+ value[63] = '\0';
+ }
+ stream << value;
+ }
+ else
+ {
+ returned_hex = TRUE;
+ S32 end = (summary_mode && (size > 8)) ? 8 : size;
+ for(S32 i = 0; i < end; i++)
+ //stream << std::uppercase << std::hex << U32(value[i]) << " ";
+ stream << llformat("%02X ", (U8)value[i]);
+ if(summary_mode && (size > 8))
+ stream << " ... ";
+ }
+ }
+ break;
+ }
+ return stream.str();
+}
+LLMessageLogFilter::LLMessageLogFilter()
+{
+}
+LLMessageLogFilter::~LLMessageLogFilter()
+{
+}
+BOOL LLMessageLogFilter::set(std::string filter)
+{
+ mPositiveNames.clear();
+ mNegativeNames.clear();
+ typedef boost::tokenizer > tokenizer;
+ boost::char_separator sep(" ","",boost::keep_empty_tokens);
+ boost::tokenizer > tokens(filter, sep);
+ boost::tokenizer >::iterator end = tokens.end();
+ for(boost::tokenizer >::iterator iter = tokens.begin(); iter != end; ++iter)
+ {
+ std::string token = (*iter);
+ LLStringUtil::trim(token);
+ LLStringUtil::toLower(token);
+ BOOL negative = token.find("!") == 0;
+ if(negative)
+ {
+ token = token.substr(1);
+ mNegativeNames.push_back(token);
+ }
+ else
+ mPositiveNames.push_back(token);
+ }
+ return TRUE;
+}
+////////////////////////////////
+// LLMessageLogFilterApply
+////////////////////////////////
+LLMessageLogFilterApply::LLMessageLogFilterApply()
+: LLEventTimer(0.1f),
+ mFinished(FALSE),
+ mProgress(0)
+{
+ mIter = LLFloaterMessageLog::sMessageLogEntries.begin();
+}
+void LLMessageLogFilterApply::cancel()
+{
+ mFinished = TRUE;
+}
+BOOL LLMessageLogFilterApply::tick()
+{
+ std::deque::iterator end = LLFloaterMessageLog::sMessageLogEntries.end();
+ if(mIter == end || !LLFloaterMessageLog::sInstance)
+ mFinished = TRUE;
+ if(mFinished)
+ {
+ if(LLFloaterMessageLog::sInstance)
+ if(LLFloaterMessageLog::sInstance->mMessageLogFilterApply == this)
+ LLFloaterMessageLog::sInstance->stopApplyingFilter();
+ return TRUE;
+ }
+ for(S32 i = 0; i < 256; i++)
+ {
+ if(mIter == end)
+ {
+ mFinished = TRUE;
+ if(LLFloaterMessageLog::sInstance)
+ if(LLFloaterMessageLog::sInstance->mMessageLogFilterApply == this)
+ LLFloaterMessageLog::sInstance->stopApplyingFilter();
+ return TRUE;
+ }
+
+ LLFloaterMessageLog::sInstance->conditionalLog(LLFloaterMessageLogItem((*mIter)));
+
+ mIter++;
+ mProgress++;
+ }
+ LLFloaterMessageLog::sInstance->updateFilterStatus();
+ return FALSE;
+}
+////////////////////////////////
+// LLFloaterMessageLog
+////////////////////////////////
+LLFloaterMessageLog* LLFloaterMessageLog::sInstance;
+std::list LLFloaterMessageLog::sNetListItems;
+std::deque LLFloaterMessageLog::sMessageLogEntries;
+std::vector LLFloaterMessageLog::sFloaterMessageLogItems;
+LLMessageLogFilter LLFloaterMessageLog::sMessageLogFilter = LLMessageLogFilter();
+std::string LLFloaterMessageLog::sMessageLogFilterString("!StartPingCheck !CompletePingCheck !PacketAck !SimulatorViewerTimeMessage !SimStats !AgentUpdate !AgentAnimation !AvatarAnimation !ViewerEffect !CoarseLocationUpdate !LayerData !CameraConstraint !ObjectUpdateCached !RequestMultipleObjects !ObjectUpdate !ObjectUpdateCompressed !ImprovedTerseObjectUpdate !KillObject !ImagePacket !SendXferPacket !ConfirmXferPacket !TransferPacket");
+BOOL LLFloaterMessageLog::sBusyApplyingFilter = FALSE;
+LLFloaterMessageLog::LLFloaterMessageLog()
+: LLFloater(),
+ LLEventTimer(1.0f),
+ mNetInfoMode(NI_NET),
+ mMessageLogFilterApply(NULL)
+{
+ sInstance = this;
+ LLMessageLog::setCallback(onLog);
+ sMessageLogEntries = LLMessageLog::getDeque();
+ LLUICtrlFactory::getInstance()->buildFloater(this, "floater_message_log.xml");
+}
+LLFloaterMessageLog::~LLFloaterMessageLog()
+{
+ LLMessageLog::setCallback(NULL);
+ stopApplyingFilter();
+ sInstance = NULL;
+ sNetListItems.clear();
+ sMessageLogEntries.clear();
+ sFloaterMessageLogItems.clear();
+}
+// static
+void LLFloaterMessageLog::show()
+{
+ if(!sInstance) sInstance = new LLFloaterMessageLog();
+ sInstance->open();
+}
+BOOL LLFloaterMessageLog::postBuild()
+{
+ childSetCommitCallback("net_list", onCommitNetList, this);
+ childSetCommitCallback("message_log", onCommitMessageLog, this);
+ childSetAction("filter_choice_btn", onClickFilterChoice, this);
+ childSetAction("filter_apply_btn", onClickFilterApply, this);
+ childSetCommitCallback("filter_edit", onCommitFilter, this);
+ childSetAction("clear_log_btn", onClickClearLog, this);
+ childSetAction("send_to_message_builder_btn", onClickSendToMessageBuilder, this);
+ childSetText("filter_edit", sMessageLogFilterString);
+ refreshNetList();
+ refreshNetInfo(TRUE);
+ startApplyingFilter(sMessageLogFilterString, TRUE);
+ return TRUE;
+}
+BOOL LLFloaterMessageLog::tick()
+{
+ refreshNetList();
+ refreshNetInfo(FALSE);
+ return FALSE;
+}
+LLNetListItem* LLFloaterMessageLog::findNetListItem(LLHost host)
+{
+ std::list::iterator end = sNetListItems.end();
+ for(std::list::iterator iter = sNetListItems.begin(); iter != end; ++iter)
+ if((*iter)->mCircuitData && (*iter)->mCircuitData->getHost() == host)
+ return (*iter);
+ return NULL;
+}
+LLNetListItem* LLFloaterMessageLog::findNetListItem(LLUUID id)
+{
+ std::list::iterator end = sNetListItems.end();
+ for(std::list::iterator iter = sNetListItems.begin(); iter != end; ++iter)
+ if((*iter)->mID == id)
+ return (*iter);
+ return NULL;
+}
+void LLFloaterMessageLog::refreshNetList()
+{
+ LLScrollListCtrl* scrollp = getChild("net_list");
+ // Update circuit data of net list items
+ std::vector circuits = gMessageSystem->getCircuit()->getCircuitDataList();
+ std::vector::iterator circuits_end = circuits.end();
+ for(std::vector::iterator iter = circuits.begin(); iter != circuits_end; ++iter)
+ {
+ LLNetListItem* itemp = findNetListItem((*iter)->getHost());
+ if(!itemp)
+ {
+ LLUUID id; id.generate();
+ itemp = new LLNetListItem(id);
+ sNetListItems.push_back(itemp);
+ }
+ itemp->mCircuitData = (*iter);
+ }
+ // Clear circuit data of items whose circuits are gone
+ std::list::iterator items_end = sNetListItems.end();
+ for(std::list::iterator iter = sNetListItems.begin(); iter != items_end; ++iter)
+ {
+ if(std::find(circuits.begin(), circuits.end(), (*iter)->mCircuitData) == circuits.end())
+ (*iter)->mCircuitData = NULL;
+ }
+ // Remove net list items that are totally useless now
+ for(std::list::iterator iter = sNetListItems.begin(); iter != sNetListItems.end();)
+ {
+ if((*iter)->mCircuitData == NULL)
+ iter = sNetListItems.erase(iter);
+ else ++iter;
+ }
+ // Update names of net list items
+ items_end = sNetListItems.end();
+ for(std::list::iterator iter = sNetListItems.begin(); iter != items_end; ++iter)
+ {
+ LLNetListItem* itemp = (*iter);
+ if(itemp->mAutoName)
+ {
+ if(itemp->mCircuitData)
+ {
+ LLViewerRegion* regionp = LLWorld::getInstance()->getRegion(itemp->mCircuitData->getHost());
+ if(regionp)
+ {
+ std::string name = regionp->getName();
+ if(name == "") name = llformat("%s (awaiting region name)", itemp->mCircuitData->getHost().getString().c_str());
+ itemp->mName = name;
+ itemp->mPreviousRegionName = name;
+ }
+ else
+ {
+ itemp->mName = itemp->mCircuitData->getHost().getString();
+ if(itemp->mPreviousRegionName != "")
+ itemp->mName.append(llformat(" (was %s)", itemp->mPreviousRegionName.c_str()));
+ }
+ }
+ else
+ {
+ // an item just for an event queue, not handled yet
+ itemp->mName = "Something else";
+ }
+ }
+ }
+ // Rebuild scroll list from scratch
+ LLUUID selected_id = scrollp->getFirstSelected() ? scrollp->getFirstSelected()->getUUID() : LLUUID::null;
+ S32 scroll_pos = scrollp->getScrollPos();
+ scrollp->clearRows();
+ for(std::list::iterator iter = sNetListItems.begin(); iter != items_end; ++iter)
+ {
+ LLNetListItem* itemp = (*iter);
+ LLSD element;
+ element["id"] = itemp->mID;
+ LLSD& text_column = element["columns"][0];
+ text_column["column"] = "text";
+ text_column["value"] = itemp->mName + (itemp->mCircuitData->getHost() == gAgent.getRegionHost() ? " (main)" : "");
+ for(int i = 0; i < 3; i++)
+ {
+ LLSD& icon_column = element["columns"][i + 1];
+ icon_column["column"] = llformat("icon%d", i);
+ icon_column["type"] = "icon";
+ icon_column["value"] = "";
+ }
+ LLScrollListItem* scroll_itemp = scrollp->addElement(element);
+ BOOL has_live_circuit = itemp->mCircuitData && itemp->mCircuitData->isAlive();
+ if(has_live_circuit)
+ {
+ LLScrollListIcon* icon = (LLScrollListIcon*)scroll_itemp->getColumn(2);
+ icon->setValue("icon_net_close_circuit.tga");
+ icon->setClickCallback(onClickCloseCircuit, itemp);
+ }
+ else
+ {
+ LLScrollListIcon* icon = (LLScrollListIcon*)scroll_itemp->getColumn(2);
+ icon->setValue("icon_net_close_circuit_gray.tga");
+ icon->setClickCallback(NULL, NULL);
+ }
+ // Event queue isn't even supported yet... FIXME
+ LLScrollListIcon* icon = (LLScrollListIcon*)scroll_itemp->getColumn(3);
+ icon->setValue("icon_net_close_eventpoll_gray.tga");
+ icon->setClickCallback(NULL, NULL);
+ }
+ if(selected_id.notNull()) scrollp->selectByID(selected_id);
+ if(scroll_pos < scrollp->getItemCount()) scrollp->setScrollPos(scroll_pos);
+}
+void LLFloaterMessageLog::refreshNetInfo(BOOL force)
+{
+ if(mNetInfoMode != NI_NET) return;
+ LLScrollListCtrl* scrollp = getChild("net_list");
+ LLScrollListItem* selected_itemp = scrollp->getFirstSelected();
+ if(selected_itemp)
+ {
+ if(!force) if(getChild("net_info")->hasSelection()) return;
+ LLNetListItem* itemp = findNetListItem(selected_itemp->getUUID());
+ if(itemp)
+ {
+ std::string info(llformat("%s\n--------------------------------\n\n", itemp->mName.c_str()));
+ if(itemp->mCircuitData)
+ {
+ LLCircuitData* cdp = itemp->mCircuitData;
+ info.append("Circuit\n--------------------------------\n");
+ info.append(llformat(" * Host: %s\n", cdp->getHost().getString().c_str()));
+ S32 seconds = (S32)cdp->getAgeInSeconds();
+ S32 minutes = seconds / 60;
+ seconds = seconds % 60;
+ S32 hours = minutes / 60;
+ minutes = minutes % 60;
+ info.append(llformat(" * Age: %dh %dm %ds\n", hours, minutes, seconds));
+ info.append(llformat(" * Alive: %s\n", cdp->isAlive() ? "yes" : "no"));
+ info.append(llformat(" * Blocked: %s\n", cdp->isBlocked() ? "yes" : "no"));
+ info.append(llformat(" * Allow timeout: %s\n", cdp->getAllowTimeout() ? "yes" : "no"));
+ info.append(llformat(" * Trusted: %s\n", cdp->getTrusted() ? "yes" : "no"));
+ info.append(llformat(" * Ping delay: %d\n", cdp->getPingDelay()));
+ info.append(llformat(" * Packets out: %d\n", cdp->getPacketsOut()));
+ info.append(llformat(" * Bytes out: %d\n", cdp->getBytesOut()));
+ info.append(llformat(" * Packets in: %d\n", cdp->getPacketsIn()));
+ info.append(llformat(" * Bytes in: %d\n", cdp->getBytesIn()));
+ info.append(llformat(" * Endpoint ID: %s\n", cdp->getLocalEndPointID().asString().c_str()));
+ info.append(llformat(" * Remote ID: %s\n", cdp->getRemoteID().asString().c_str()));
+ info.append(llformat(" * Remote session ID: %s\n", cdp->getRemoteSessionID().asString().c_str()));
+ }
+ childSetText("net_info", info);
+ }
+ else childSetText("net_info", std::string(""));
+ }
+ else childSetText("net_info", std::string(""));
+}
+void LLFloaterMessageLog::setNetInfoMode(ENetInfoMode mode)
+{
+ mNetInfoMode = mode;
+ if(mNetInfoMode == NI_NET)
+ refreshNetInfo(TRUE);
+ childSetEnabled("send_to_message_builder_btn", mNetInfoMode == NI_LOG);
+}
+// static
+void LLFloaterMessageLog::onLog(LLMessageLogEntry entry)
+{
+ sMessageLogEntries.push_back(entry);
+ if(!sBusyApplyingFilter)
+ conditionalLog(LLFloaterMessageLogItem(entry));
+}
+// static
+void LLFloaterMessageLog::conditionalLog(LLFloaterMessageLogItem item)
+{
+ if(!sBusyApplyingFilter)
+ sInstance->childSetText("log_status_text", llformat("Showing %d messages from %d", sFloaterMessageLogItems.size(), sMessageLogEntries.size()));
+ std::string find_name = item.mName;
+ LLStringUtil::toLower(find_name);
+ if(sMessageLogFilter.mPositiveNames.size())
+ if(std::find(sMessageLogFilter.mPositiveNames.begin(), sMessageLogFilter.mPositiveNames.end(), find_name) == sMessageLogFilter.mPositiveNames.end())
+ return;
+ if(std::find(sMessageLogFilter.mNegativeNames.begin(), sMessageLogFilter.mNegativeNames.end(), find_name) != sMessageLogFilter.mNegativeNames.end())
+ return;
+ sFloaterMessageLogItems.push_back(item); // moved from beginning...
+ BOOL outgoing = item.isOutgoing();
+ std::string net_name("\?\?\?");
+ if(item.mType == LLFloaterMessageLogItem::TEMPLATE)
+ {
+ LLHost find_host = outgoing ? item.mToHost : item.mFromHost;
+ net_name = find_host.getIPandPort();
+ std::list::iterator end = sNetListItems.end();
+ for(std::list::iterator iter = sNetListItems.begin(); iter != end; ++iter)
+ {
+ if((*iter)->mCircuitData->getHost() == find_host)
+ {
+ net_name = (*iter)->mName;
+ break;
+ }
+ }
+ }
+ LLSD element;
+ element["id"] = item.mID;
+ LLSD& sequence_column = element["columns"][0];
+ sequence_column["column"] = "sequence";
+ sequence_column["value"] = llformat("%u", item.mSequenceID);
+ LLSD& type_column = element["columns"][1];
+ type_column["column"] = "type";
+ type_column["value"] = item.mType == LLFloaterMessageLogItem::TEMPLATE ? "UDP" : "\?\?\?";
+ LLSD& direction_column = element["columns"][2];
+ direction_column["column"] = "direction";
+ direction_column["value"] = outgoing ? "to" : "from";
+ LLSD& net_column = element["columns"][3];
+ net_column["column"] = "net";
+ net_column["value"] = net_name;
+ LLSD& name_column = element["columns"][4];
+ name_column["column"] = "name";
+ name_column["value"] = item.mName;
+ /*
+ LLSD& zer_column = element["columns"][5];
+ zer_column["column"] = "flag_zer";
+ zer_column["type"] = "icon";
+ zer_column["value"] = (item.mFlags & LL_ZERO_CODE_FLAG) ? "flag_zer.tga" : "";
+ LLSD& rel_column = element["columns"][6];
+ rel_column["column"] = "flag_rel";
+ rel_column["type"] = "icon";
+ rel_column["value"] = (item.mFlags & LL_RELIABLE_FLAG) ? "flag_rel.tga" : "";
+ LLSD& rsd_column = element["columns"][7];
+ rsd_column["column"] = "flag_rsd";
+ rsd_column["type"] = "icon";
+ rsd_column["value"] = (item.mFlags & LL_RESENT_FLAG) ? "flag_rsd.tga" : "";
+ LLSD& ack_column = element["columns"][8];
+ ack_column["column"] = "flag_ack";
+ ack_column["type"] = "icon";
+ ack_column["value"] = (item.mFlags & LL_ACK_FLAG) ? "flag_ack.tga" : "";
+ */
+ LLSD& summary_column = element["columns"][5];
+ summary_column["column"] = "summary";
+ summary_column["value"] = item.mSummary;
+ LLScrollListCtrl* scrollp = sInstance->getChild("message_log");
+ S32 scroll_pos = scrollp->getScrollPos();
+ scrollp->addElement(element);
+ if(scroll_pos > scrollp->getItemCount() - scrollp->getPageLines() - 4)
+ scrollp->setScrollPos(scrollp->getItemCount());
+}
+// static
+void LLFloaterMessageLog::onCommitNetList(LLUICtrl* ctrl, void* user_data)
+{
+ LLFloaterMessageLog* floaterp = (LLFloaterMessageLog*)user_data;
+ floaterp->setNetInfoMode(NI_NET);
+ floaterp->refreshNetInfo(TRUE);
+}
+// static
+void LLFloaterMessageLog::onCommitMessageLog(LLUICtrl* ctrl, void* user_data)
+{
+ LLFloaterMessageLog* floaterp = (LLFloaterMessageLog*)user_data;
+ LLScrollListCtrl* scrollp = floaterp->getChild("message_log");
+ LLScrollListItem* selected_itemp = scrollp->getFirstSelected();
+ if(!selected_itemp) return;
+ LLUUID id = selected_itemp->getUUID();
+ std::vector::iterator end = sFloaterMessageLogItems.end();
+ for(std::vector::iterator iter = sFloaterMessageLogItems.begin(); iter != end; ++iter)
+ {
+ if(iter->mID == id)
+ {
+ floaterp->setNetInfoMode(NI_LOG);
+ floaterp->childSetText("net_info", iter->getFull(FALSE));
+ break;
+ }
+ }
+}
+// static
+BOOL LLFloaterMessageLog::onClickCloseCircuit(void* user_data)
+{
+ LLNetListItem* itemp = (LLNetListItem*)user_data;
+ LLCircuitData* cdp = (LLCircuitData*)itemp->mCircuitData;
+ if(!cdp) return FALSE;
+ LLHost myhost = cdp->getHost();
+ LLSD args;
+ args["MESSAGE"] = "This will delete local circuit data.\nDo you want to tell the remote host to close the circuit too?";
+ LLSD payload;
+ payload["circuittoclose"] = myhost.getString();
+ LLNotifications::instance().add("GenericAlertYesCancel", args, payload, onConfirmCloseCircuit);
+ return TRUE;
+}
+// static
+void LLFloaterMessageLog::onConfirmCloseCircuit(S32 option, LLSD payload)
+{
+ LLCircuitData* cdp = gMessageSystem->mCircuitInfo.findCircuit(LLHost(payload["circuittoclose"].asString()));
+ if(!cdp) return;
+ LLViewerRegion* regionp = LLWorld::getInstance()->getRegion(cdp->getHost());
+ switch(option)
+ {
+ case 0: // yes
+ gMessageSystem->newMessageFast(_PREHASH_CloseCircuit);
+ gMessageSystem->sendReliable(cdp->getHost());
+ break;
+ case 2: // cancel
+ return;
+ break;
+ case 1: // no
+ default:
+ break;
+ }
+ if(gMessageSystem->findCircuitCode(cdp->getHost()))
+ gMessageSystem->disableCircuit(cdp->getHost());
+ else
+ gMessageSystem->getCircuit()->removeCircuitData(cdp->getHost());
+ if(regionp)
+ {
+ LLHost myhost = regionp->getHost();
+ LLSD args;
+ args["MESSAGE"] = "That host had a region associated with it.\nDo you want to clean that up?";
+ LLSD payload;
+ payload["regionhost"] = myhost.getString();
+ LLNotifications::instance().add("GenericAlertYesCancel", args, payload, onConfirmRemoveRegion);
+ }
+}
+// static
+void LLFloaterMessageLog::onConfirmRemoveRegion(S32 option, LLSD payload)
+{
+ if(option == 0) // yes
+ LLWorld::getInstance()->removeRegion(LLHost(payload["regionhost"].asString()));
+}
+// static
+void LLFloaterMessageLog::onClickFilterApply(void* user_data)
+{
+ LLFloaterMessageLog* floaterp = (LLFloaterMessageLog*)user_data;
+ floaterp->startApplyingFilter(floaterp->childGetValue("filter_edit"), FALSE);
+}
+void LLFloaterMessageLog::startApplyingFilter(std::string filter, BOOL force)
+{
+ LLMessageLogFilter new_filter = LLMessageLogFilter();
+ sMessageLogFilterString = filter;
+ new_filter.set(sMessageLogFilterString);
+ childSetText("filter_edit", filter + " ");
+ if(force
+ || (new_filter.mNegativeNames != sMessageLogFilter.mNegativeNames)
+ || (new_filter.mPositiveNames != sMessageLogFilter.mPositiveNames))
+ {
+ stopApplyingFilter();
+ sMessageLogFilter = new_filter;
+ sFloaterMessageLogItems.clear();
+ getChild("message_log")->clearRows();
+ sBusyApplyingFilter = TRUE;
+ childSetVisible("message_log", false);
+ //childSetVisible("log_status_text", true);
+ mMessageLogFilterApply = new LLMessageLogFilterApply();
+ }
+}
+void LLFloaterMessageLog::stopApplyingFilter()
+{
+ if(mMessageLogFilterApply)
+ {
+ if(!(mMessageLogFilterApply->mFinished))
+ mMessageLogFilterApply->cancel();
+ //delete mMessageLogFilterApply;
+ sBusyApplyingFilter = FALSE;
+ //childSetVisible("log_status_text", false);
+ childSetVisible("message_log", true);
+ childSetText("log_status_text", llformat("Showing %d messages from %d", sFloaterMessageLogItems.size(), sMessageLogEntries.size()));
+ }
+}
+void LLFloaterMessageLog::updateFilterStatus()
+{
+ if(!mMessageLogFilterApply || !sBusyApplyingFilter) return;
+ S32 progress = mMessageLogFilterApply->mProgress;
+ S32 packets = sMessageLogEntries.size();
+ S32 matches = sFloaterMessageLogItems.size();
+ std::string text = llformat("Applying filter ( %d / %d ), %d matches ...", progress, packets, matches);
+ childSetText("log_status_text", text);
+}
+// static
+void LLFloaterMessageLog::onCommitFilter(LLUICtrl* ctrl, void* user_data)
+{
+ LLFloaterMessageLog* floaterp = (LLFloaterMessageLog*)user_data;
+ floaterp->startApplyingFilter(floaterp->childGetValue("filter_edit"), FALSE);
+}
+// static
+void LLFloaterMessageLog::onClickClearLog(void* user_data)
+{
+ LLFloaterMessageLog* floaterp = (LLFloaterMessageLog*)user_data;
+ floaterp->stopApplyingFilter();
+ floaterp->getChild("message_log")->clearRows();
+ floaterp->setNetInfoMode(NI_NET);
+ sMessageLogEntries.clear();
+ sFloaterMessageLogItems.clear();
+}
+// static
+void LLFloaterMessageLog::onClickFilterChoice(void* user_data)
+{
+ LLMenuGL* menu = new LLMenuGL(LLStringUtil::null);
+ menu->append(new LLMenuItemCallGL("No filter", onClickFilterMenu, NULL, (void*)""));
+ menu->append(new LLMenuItemCallGL("Fewer spammy messages", onClickFilterMenu, NULL, (void*)"!StartPingCheck !CompletePingCheck !PacketAck !SimulatorViewerTimeMessage !SimStats !AgentUpdate !AgentAnimation !AvatarAnimation !ViewerEffect !CoarseLocationUpdate !LayerData !CameraConstraint !ObjectUpdateCached !RequestMultipleObjects !ObjectUpdate !ObjectUpdateCompressed !ImprovedTerseObjectUpdate !KillObject !ImagePacket !SendXferPacket !ConfirmXferPacket !TransferPacket"));
+ menu->append(new LLMenuItemCallGL("Object updates", onClickFilterMenu, NULL, (void*)"ObjectUpdateCached ObjectUpdate ObjectUpdateCompressed ImprovedTerseObjectUpdate KillObject RequestMultipleObjects"));
+ menu->append(new LLMenuItemCallGL("Abnormal", onClickFilterMenu, NULL, (void*)"Invalid TestMessage AddCircuitCode NeighborList AvatarTextureUpdate SimulatorMapUpdate SimulatorSetMap SubscribeLoad UnsubscribeLoad SimulatorReady SimulatorPresentAtLocation SimulatorLoad SimulatorShutdownRequest RegionPresenceRequestByRegionID RegionPresenceRequestByHandle RegionPresenceResponse UpdateSimulator LogDwellTime FeatureDisabled LogFailedMoneyTransaction UserReportInternal SetSimStatusInDatabase SetSimPresenceInDatabase OpenCircuit CloseCircuit DirFindQueryBackend DirPlacesQueryBackend DirClassifiedQueryBackend DirLandQueryBackend DirPopularQueryBackend GroupNoticeAdd DataHomeLocationRequest DataHomeLocationReply DerezContainer ObjectCategory ObjectExportSelected StateSave ReportAutosaveCrash AgentAlertMessage NearestLandingRegionRequest NearestLandingRegionReply NearestLandingRegionUpdated TeleportLandingStatusChanged ConfirmEnableSimulator KickUserAck SystemKickUser AvatarPropertiesRequestBackend UpdateParcel RemoveParcel MergeParcel LogParcelChanges CheckParcelSales ParcelSales StartAuction ConfirmAuctionStart CompleteAuction CancelAuction CheckParcelAuctions ParcelAuctions ChatPass EdgeDataPacket SimStatus ChildAgentUpdate ChildAgentAlive ChildAgentPositionUpdate ChildAgentDying ChildAgentUnknown AtomicPassObject KillChildAgents ScriptSensorRequest ScriptSensorReply DataServerLogout RequestInventoryAsset InventoryAssetResponse TransferInventory TransferInventoryAck EventLocationRequest EventLocationReply MoneyTransferBackend RoutedMoneyBalanceReply SetStartLocation NetTest SetCPURatio SimCrashed NameValuePair RemoveNameValuePair UpdateAttachment RemoveAttachment EmailMessageRequest EmailMessageReply InternalScriptMail ScriptDataRequest ScriptDataReply InviteGroupResponse TallyVotes LiveHelpGroupRequest LiveHelpGroupReply GroupDataUpdate LogTextMessage CreateTrustedCircuit ParcelRename SystemMessage RpcChannelRequest RpcChannelReply RpcScriptRequestInbound RpcScriptRequestInboundForward RpcScriptReplyInbound ScriptMailRegistration Error"));
+ menu->updateParent(LLMenuGL::sMenuContainer);
+ menu->setCanTearOff(FALSE);
+ LLView* buttonp = sInstance->getChild("filter_choice_btn");
+ S32 x = buttonp->getRect().mLeft;
+ S32 y = buttonp->getRect().mBottom;
+ LLMenuGL::showPopup(sInstance, menu, x, y);
+}
+// static
+void LLFloaterMessageLog::onClickFilterMenu(void* user_data)
+{
+ std::string filter = std::string((char*)user_data);
+ sInstance->childSetText("filter_edit", filter);
+ sInstance->startApplyingFilter(filter, FALSE);
+}
+// static
+void LLFloaterMessageLog::onClickSendToMessageBuilder(void* user_data)
+{
+ LLFloaterMessageLog* floaterp = (LLFloaterMessageLog*)user_data;
+ LLScrollListCtrl* scrollp = floaterp->getChild("message_log");
+ LLScrollListItem* selected_itemp = scrollp->getFirstSelected();
+ if(!selected_itemp) return;
+ LLUUID id = selected_itemp->getUUID();
+ std::vector::iterator end = sFloaterMessageLogItems.end();
+ for(std::vector::iterator iter = sFloaterMessageLogItems.begin(); iter != end; ++iter)
+ {
+ if(iter->mID == id)
+ {
+ std::string message_text = iter->getFull(FALSE);
+ LLFloaterMessageBuilder::show(message_text);
+ break;
+ }
+ }
+}
+//
diff --git a/indra/newview/llinventoryactions.cpp b/indra/newview/llinventoryactions.cpp
index 4be9fc2f4..58b5e289f 100644
--- a/indra/newview/llinventoryactions.cpp
+++ b/indra/newview/llinventoryactions.cpp
@@ -86,12 +86,12 @@
#include "lluictrlfactory.h"
#include "llselectmgr.h"
-//
-#include "lllocalinventory.h"
-#include "llinventorybackup.h"
-//#include "llcheats.h"
-//#include "llnotecardmagic.h"
-//
+//
+#include "lllocalinventory.h"
+#include "llinventorybackup.h"
+//#include "llcheats.h"
+//#include "llnotecardmagic.h"
+//
const std::string NEW_LSL_NAME = "New Script"; // *TODO:Translate? (probably not)
const std::string NEW_NOTECARD_NAME = "New Note"; // *TODO:Translate? (probably not)
const std::string NEW_GESTURE_NAME = "New Gesture"; // *TODO:Translate? (probably not)
@@ -118,49 +118,49 @@ bool doToSelected(LLFolderView* folder, std::string action)
{
LLInventoryClipboard::instance().reset();
}
- //
- if("save_as" == action)
- {
- LLInventoryBackup::save(folder);
- return true;
- }
- else if("save_invcache" == action)
- {
- LLFilePicker& file_picker = LLFilePicker::instance();
- if(file_picker.getSaveFile( LLFilePicker::FFSAVE_INVGZ ))
- {
- std::string file_name = file_picker.getFirstFile();
- LLLocalInventory::saveInvCache(file_name, folder);
- }
- return true;
+ //
+ if("save_as" == action)
+ {
+ LLInventoryBackup::save(folder);
+ return true;
}
-/*
- else if("acquire_asset_id" == action)
- {
- if(LLCheats::cheatCodes["AcquireAssetID"].entered)
- {
- std::set selected_items_set;
- folder->getSelectionList(selected_items_set);
-
- if(selected_items_set.size() > 0)
- {
- LLAssetIDAcquirer::acquire(selected_items_set);
- }
- }
- return true;
- }
- else if("magic_get" == action)
- {
- std::set selected_items_set;
- folder->getSelectionList(selected_items_set);
-
- if(selected_items_set.size() > 0)
- {
- LLNotecardMagic::acquire(selected_items_set);
- }
+ else if("save_invcache" == action)
+ {
+ LLFilePicker& file_picker = LLFilePicker::instance();
+ if(file_picker.getSaveFile( LLFilePicker::FFSAVE_INVGZ ))
+ {
+ std::string file_name = file_picker.getFirstFile();
+ LLLocalInventory::saveInvCache(file_name, folder);
+ }
+ return true;
}
-*/
- //
+/*
+ else if("acquire_asset_id" == action)
+ {
+ if(LLCheats::cheatCodes["AcquireAssetID"].entered)
+ {
+ std::set selected_items_set;
+ folder->getSelectionList(selected_items_set);
+
+ if(selected_items_set.size() > 0)
+ {
+ LLAssetIDAcquirer::acquire(selected_items_set);
+ }
+ }
+ return true;
+ }
+ else if("magic_get" == action)
+ {
+ std::set selected_items_set;
+ folder->getSelectionList(selected_items_set);
+
+ if(selected_items_set.size() > 0)
+ {
+ LLNotecardMagic::acquire(selected_items_set);
+ }
+ }
+*/
+ //
std::set selected_items;
folder->getSelectionList(selected_items);
@@ -521,36 +521,36 @@ class LLDoCreateFloater : public inventory_listener_t
LLInventoryModel* model = mPtr->getPanel()->getModel();
if(!model) return false;
std::string type = userdata.asString();
- //
- if(type == "pretend")
- {
- LLFloaterNewLocalInventory* floater = new LLFloaterNewLocalInventory();
- floater->center();
- }
- else
- //
+ //
+ if(type == "pretend")
+ {
+ LLFloaterNewLocalInventory* floater = new LLFloaterNewLocalInventory();
+ floater->center();
+ }
+ else
+ //
do_create(model, mPtr->getPanel(), type);
return true;
}
};
-//
-class LLLoadInvCacheFloater : public inventory_listener_t
-{
- bool handleEvent(LLPointer event, const LLSD& userdata)
- {
- LLInventoryModel* model = mPtr->getPanel()->getModel();
- if(!model) return false;
- LLFilePicker& file_picker = LLFilePicker::instance();
- if(file_picker.getOpenFile( LLFilePicker::FFLOAD_INVGZ ))
- {
- std::string file_name = file_picker.getFirstFile();
- LLLocalInventory::loadInvCache(file_name);
- }
- return true;
- }
-};
-//
+//
+class LLLoadInvCacheFloater : public inventory_listener_t
+{
+ bool handleEvent(LLPointer event, const LLSD& userdata)
+ {
+ LLInventoryModel* model = mPtr->getPanel()->getModel();
+ if(!model) return false;
+ LLFilePicker& file_picker = LLFilePicker::instance();
+ if(file_picker.getOpenFile( LLFilePicker::FFLOAD_INVGZ ))
+ {
+ std::string file_name = file_picker.getFirstFile();
+ LLLocalInventory::loadInvCache(file_name);
+ }
+ return true;
+ }
+};
+//
class LLSetSortBy : public inventory_listener_t
{
bool handleEvent(LLPointer event, const LLSD& userdata)
@@ -789,9 +789,9 @@ void init_inventory_actions(LLInventoryView *floater)
(new LLCloseAllFoldersFloater())->registerListener(floater, "Inventory.CloseAllFolders");
(new LLEmptyTrashFloater())->registerListener(floater, "Inventory.EmptyTrash");
(new LLDoCreateFloater())->registerListener(floater, "Inventory.DoCreate");
- //
- (new LLLoadInvCacheFloater())->registerListener(floater, "Inventory.LoadInvCache");
- //
+ //
+ (new LLLoadInvCacheFloater())->registerListener(floater, "Inventory.LoadInvCache");
+ //
(new LLNewWindow())->registerListener(floater, "Inventory.NewWindow");
(new LLShowFilters())->registerListener(floater, "Inventory.ShowFilters");
diff --git a/indra/newview/llinventorybackup.cpp b/indra/newview/llinventorybackup.cpp
index d4bb07da7..7c54cc691 100644
--- a/indra/newview/llinventorybackup.cpp
+++ b/indra/newview/llinventorybackup.cpp
@@ -1,781 +1,781 @@
-//
-#include "llviewerprecompiledheaders.h"
-
-#include "llinventorybackup.h"
-#include "llinventorymodel.h"
-#include "llviewerinventory.h"
-#include "llfilepicker.h"
-#include "lldirpicker.h"
-#include "llviewerimage.h"
-#include "llviewerimagelist.h" // gImageList
-#include "llagent.h" // gAgent
-#include "llviewerwindow.h" // gViewerWindow
-#include "llfloater.h"
-#include "lluictrlfactory.h"
-#include "llscrolllistctrl.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/";
- LLNotifications::instance().add("ErrorMessage", args);
- return;
- }
-
- // Get dir name
- LLDirPicker& picker = LLDirPicker::instance();
- std::string filename = "New Folder";
- if (!picker.getDir(&filename))
- {
- floater->close();
- return;
- }
- filename = picker.getDirName();
-
- // Make local directory tree
- LLFile::mkdir(filename);
- 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 = filename + OS_SEP + LLInventoryBackup::getPath(*_cat_iter, order->mCats);
- LLFile::mkdir(path);
- }
-
- // Go go backup floater
- LLFloaterInventoryBackup* backup_floater = new LLFloaterInventoryBackup(filename, 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
-LLFilePicker::ESaveFilter LLInventoryBackup::getSaveFilter(LLInventoryItem* item)
-{
- LLAssetType::EType type = item->getType();
- EWearableType wear = (EWearableType)(item->getFlags() & 0xFF);
- switch(type)
- {
- case LLAssetType::AT_TEXTURE:
- return LLFilePicker::FFSAVE_TGA;
- case LLAssetType::AT_SOUND:
- return LLFilePicker::FFSAVE_OGG;
- case LLAssetType::AT_SCRIPT:
- case LLAssetType::AT_LSL_TEXT:
- return LLFilePicker::FFSAVE_LSL;
- case LLAssetType::AT_ANIMATION:
- return LLFilePicker::FFSAVE_ANIMATN;
- case LLAssetType::AT_GESTURE:
- return LLFilePicker::FFSAVE_GESTURE;
- case LLAssetType::AT_NOTECARD:
- return LLFilePicker::FFSAVE_NOTECARD;
- case LLAssetType::AT_LANDMARK:
- return LLFilePicker::FFSAVE_LANDMARK;
- case LLAssetType::AT_BODYPART:
- case LLAssetType::AT_CLOTHING:
- switch(wear)
- {
- case WT_EYES:
- return LLFilePicker::FFSAVE_EYES;
- case WT_GLOVES:
- return LLFilePicker::FFSAVE_GLOVES;
- case WT_HAIR:
- return LLFilePicker::FFSAVE_HAIR;
- case WT_JACKET:
- return LLFilePicker::FFSAVE_JACKET;
- case WT_PANTS:
- return LLFilePicker::FFSAVE_PANTS;
- case WT_SHAPE:
- return LLFilePicker::FFSAVE_SHAPE;
- case WT_SHIRT:
- return LLFilePicker::FFSAVE_SHIRT;
- case WT_SHOES:
- return LLFilePicker::FFSAVE_SHOES;
- case WT_SKIN:
- return LLFilePicker::FFSAVE_SKIN;
- case WT_SKIRT:
- return LLFilePicker::FFSAVE_SKIRT;
- case WT_SOCKS:
- return LLFilePicker::FFSAVE_SOCKS;
- case WT_UNDERPANTS:
- return LLFilePicker::FFSAVE_UNDERPANTS;
- case WT_UNDERSHIRT:
- return LLFilePicker::FFSAVE_UNDERSHIRT;
- default:
- return LLFilePicker::FFSAVE_ALL;
- }
- default:
- return LLFilePicker::FFSAVE_ALL;
- }
-}
-
-// static
-std::string LLInventoryBackup::getExtension(LLInventoryItem* item)
-{
- LLAssetType::EType type = item->getType();
- EWearableType wear = (EWearableType)(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 = LLWearable::typeToTypeName(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;
- LLViewerImage* imagep;
-
-#if OPENSIM_RULES!=1
- //don't be a jerk. (this check probably breaks stuff)
- if(item->getCreatorUUID() == gAgentID)
- {
-#endif /* OPENSIM_RULES!=1 */
- switch(item->getType())
- {
- case LLAssetType::AT_TEXTURE:
- imagep = gImageList.getImage(item->getAssetUUID(), MIPMAP_TRUE, TRUE);
- imagep->setLoadedCallbackNoAux( onImage, 0, TRUE, FALSE, userdata );
- 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;
- }
-#if OPENSIM_RULES!=1
- }
-#endif /* OPENSIM_RULES!=1 */
-}
-
-// static
-void LLInventoryBackup::imageCallback(BOOL success,
- LLViewerImage *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() + ".";
- LLNotifications::instance().add("ErrorMessage", args);
- return;
- }
-
- LLFilePicker& file_picker = LLFilePicker::instance();
- if( !file_picker.getSaveFile( getSaveFilter(item), LLDir::getScrubbedFileName(item->getName())) )
- {
- // User canceled or we failed to acquire save file.
- return;
- }
- // remember the user-approved/edited file name.
- std::string filename = file_picker.getFirstFile();
-
- LLPointer image_tga = new LLImageTGA;
- if( !image_tga->encode( src ) )
- {
- LLSD args;
- args["ERROR_MESSAGE"] = "Couldn't encode file.";
- LLNotifications::instance().add("ErrorMessage", args);
- }
- else if( !image_tga->save( filename ) )
- {
- LLSD args;
- args["ERROR_MESSAGE"] = "Couldn't write file.";
- LLNotifications::instance().add("ErrorMessage", args);
- }
- }
- else
- {
- src_vi->setBoostLevel(LLViewerImageBoostLevel::BOOST_UI);
- }
-}
-
-// 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() + ".";
- LLNotifications::instance().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];
- if (buffer == NULL)
- {
- llerrs << "Memory Allocation Failed" << llendl;
- return;
- }
-
- file.read((U8*)buffer, size);
-
- // Write it back out...
-
- LLFilePicker& file_picker = LLFilePicker::instance();
- if( !file_picker.getSaveFile( getSaveFilter(item), LLDir::getScrubbedFileName(item->getName())) )
- {
- // User canceled or we failed to acquire save file.
- return;
- }
- // remember the user-approved/edited file name.
- std::string filename = file_picker.getFirstFile();
-
- std::ofstream export_file(filename.c_str(), std::ofstream::binary);
- export_file.write(buffer, size);
- export_file.close();
-}
-
-// 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(selected_items);
-
- 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";
-
- list->addElement(element, ADD_BOTTOM);
- }
-
- // 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,
- LLViewerImage *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(LLViewerImageBoostLevel::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");
-}
-//
+//
+#include "llviewerprecompiledheaders.h"
+
+#include "llinventorybackup.h"
+#include "llinventorymodel.h"
+#include "llviewerinventory.h"
+#include "llfilepicker.h"
+#include "lldirpicker.h"
+#include "llviewerimage.h"
+#include "llviewerimagelist.h" // gImageList
+#include "llagent.h" // gAgent
+#include "llviewerwindow.h" // gViewerWindow
+#include "llfloater.h"
+#include "lluictrlfactory.h"
+#include "llscrolllistctrl.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/";
+ LLNotifications::instance().add("ErrorMessage", args);
+ return;
+ }
+
+ // Get dir name
+ LLDirPicker& picker = LLDirPicker::instance();
+ std::string filename = "New Folder";
+ if (!picker.getDir(&filename))
+ {
+ floater->close();
+ return;
+ }
+ filename = picker.getDirName();
+
+ // Make local directory tree
+ LLFile::mkdir(filename);
+ 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 = filename + OS_SEP + LLInventoryBackup::getPath(*_cat_iter, order->mCats);
+ LLFile::mkdir(path);
+ }
+
+ // Go go backup floater
+ LLFloaterInventoryBackup* backup_floater = new LLFloaterInventoryBackup(filename, 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
+LLFilePicker::ESaveFilter LLInventoryBackup::getSaveFilter(LLInventoryItem* item)
+{
+ LLAssetType::EType type = item->getType();
+ EWearableType wear = (EWearableType)(item->getFlags() & 0xFF);
+ switch(type)
+ {
+ case LLAssetType::AT_TEXTURE:
+ return LLFilePicker::FFSAVE_TGA;
+ case LLAssetType::AT_SOUND:
+ return LLFilePicker::FFSAVE_OGG;
+ case LLAssetType::AT_SCRIPT:
+ case LLAssetType::AT_LSL_TEXT:
+ return LLFilePicker::FFSAVE_LSL;
+ case LLAssetType::AT_ANIMATION:
+ return LLFilePicker::FFSAVE_ANIMATN;
+ case LLAssetType::AT_GESTURE:
+ return LLFilePicker::FFSAVE_GESTURE;
+ case LLAssetType::AT_NOTECARD:
+ return LLFilePicker::FFSAVE_NOTECARD;
+ case LLAssetType::AT_LANDMARK:
+ return LLFilePicker::FFSAVE_LANDMARK;
+ case LLAssetType::AT_BODYPART:
+ case LLAssetType::AT_CLOTHING:
+ switch(wear)
+ {
+ case WT_EYES:
+ return LLFilePicker::FFSAVE_EYES;
+ case WT_GLOVES:
+ return LLFilePicker::FFSAVE_GLOVES;
+ case WT_HAIR:
+ return LLFilePicker::FFSAVE_HAIR;
+ case WT_JACKET:
+ return LLFilePicker::FFSAVE_JACKET;
+ case WT_PANTS:
+ return LLFilePicker::FFSAVE_PANTS;
+ case WT_SHAPE:
+ return LLFilePicker::FFSAVE_SHAPE;
+ case WT_SHIRT:
+ return LLFilePicker::FFSAVE_SHIRT;
+ case WT_SHOES:
+ return LLFilePicker::FFSAVE_SHOES;
+ case WT_SKIN:
+ return LLFilePicker::FFSAVE_SKIN;
+ case WT_SKIRT:
+ return LLFilePicker::FFSAVE_SKIRT;
+ case WT_SOCKS:
+ return LLFilePicker::FFSAVE_SOCKS;
+ case WT_UNDERPANTS:
+ return LLFilePicker::FFSAVE_UNDERPANTS;
+ case WT_UNDERSHIRT:
+ return LLFilePicker::FFSAVE_UNDERSHIRT;
+ default:
+ return LLFilePicker::FFSAVE_ALL;
+ }
+ default:
+ return LLFilePicker::FFSAVE_ALL;
+ }
+}
+
+// static
+std::string LLInventoryBackup::getExtension(LLInventoryItem* item)
+{
+ LLAssetType::EType type = item->getType();
+ EWearableType wear = (EWearableType)(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 = LLWearable::typeToTypeName(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;
+ LLViewerImage* imagep;
+
+#if OPENSIM_RULES!=1
+ //don't be a jerk. (this check probably breaks stuff)
+ if(item->getCreatorUUID() == gAgentID)
+ {
+#endif /* OPENSIM_RULES!=1 */
+ switch(item->getType())
+ {
+ case LLAssetType::AT_TEXTURE:
+ imagep = gImageList.getImage(item->getAssetUUID(), MIPMAP_TRUE, TRUE);
+ imagep->setLoadedCallbackNoAux( onImage, 0, TRUE, FALSE, userdata );
+ 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;
+ }
+#if OPENSIM_RULES!=1
+ }
+#endif /* OPENSIM_RULES!=1 */
+}
+
+// static
+void LLInventoryBackup::imageCallback(BOOL success,
+ LLViewerImage *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() + ".";
+ LLNotifications::instance().add("ErrorMessage", args);
+ return;
+ }
+
+ LLFilePicker& file_picker = LLFilePicker::instance();
+ if( !file_picker.getSaveFile( getSaveFilter(item), LLDir::getScrubbedFileName(item->getName())) )
+ {
+ // User canceled or we failed to acquire save file.
+ return;
+ }
+ // remember the user-approved/edited file name.
+ std::string filename = file_picker.getFirstFile();
+
+ LLPointer image_tga = new LLImageTGA;
+ if( !image_tga->encode( src ) )
+ {
+ LLSD args;
+ args["ERROR_MESSAGE"] = "Couldn't encode file.";
+ LLNotifications::instance().add("ErrorMessage", args);
+ }
+ else if( !image_tga->save( filename ) )
+ {
+ LLSD args;
+ args["ERROR_MESSAGE"] = "Couldn't write file.";
+ LLNotifications::instance().add("ErrorMessage", args);
+ }
+ }
+ else
+ {
+ src_vi->setBoostLevel(LLViewerImageBoostLevel::BOOST_UI);
+ }
+}
+
+// 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() + ".";
+ LLNotifications::instance().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];
+ if (buffer == NULL)
+ {
+ llerrs << "Memory Allocation Failed" << llendl;
+ return;
+ }
+
+ file.read((U8*)buffer, size);
+
+ // Write it back out...
+
+ LLFilePicker& file_picker = LLFilePicker::instance();
+ if( !file_picker.getSaveFile( getSaveFilter(item), LLDir::getScrubbedFileName(item->getName())) )
+ {
+ // User canceled or we failed to acquire save file.
+ return;
+ }
+ // remember the user-approved/edited file name.
+ std::string filename = file_picker.getFirstFile();
+
+ std::ofstream export_file(filename.c_str(), std::ofstream::binary);
+ export_file.write(buffer, size);
+ export_file.close();
+}
+
+// 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(selected_items);
+
+ 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";
+
+ list->addElement(element, ADD_BOTTOM);
+ }
+
+ // 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,
+ LLViewerImage *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(LLViewerImageBoostLevel::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");
+}
+//
diff --git a/indra/newview/llinventorybackup.h b/indra/newview/llinventorybackup.h
index 42b671b62..70a7c076f 100644
--- a/indra/newview/llinventorybackup.h
+++ b/indra/newview/llinventorybackup.h
@@ -1,135 +1,135 @@
-//
-#ifndef LL_LLINVENTORYBACKUP_H
-#define LL_LLINVENTORYBACKUP_H
-
-#if LL_WINDOWS
-#define OS_SEP "\\"
-#else
-#define OS_SEP "/"
-#endif
-
-
-#include "llviewerinventory.h"
-#include "llfolderview.h"
-#include "llfilepicker.h"
-#include "llviewerimage.h"
-#include "llfloater.h"
-
-
-class LLInventoryBackupOrder
-{
-public:
- LLInventoryBackupOrder();
-
- std::string mPath;
- std::vector mCats;
- std::vector mItems;
-
- bool mDownloadTextures;
- bool mDownloadSounds;
- bool mDownloadCallingCards;
- bool mDownloadLandmarks;
- bool mDownloadScripts;
- bool mDownloadWearables;
- bool mDownloadObjects;
- bool mDownloadNotecards;
- bool mDownloadAnimations;
- bool mDownloadGestures;
- //bool mDownloadOthers;
-};
-
-class LLFloaterInventoryBackupSettings
-: public LLFloater
-{
-public:
- LLFloaterInventoryBackupSettings(LLInventoryBackupOrder* order);
- BOOL postBuild(void);
- static void onClickNext(void* userdata);
-
- LLInventoryBackupOrder* mOrder;
- virtual ~LLFloaterInventoryBackupSettings();
-};
-
-class LLFloaterInventoryBackup
-: public LLFloater
-{
-public:
- LLFloaterInventoryBackup(std::string path, std::vector cats, std::vector items);
- BOOL postBuild(void);
-
- std::string mPath;
- std::vector mCats;
- std::vector mItems;
- std::vector::iterator mItemIter;
- int mBusy;
-
- static std::list sInstances;
-
-private:
- virtual ~LLFloaterInventoryBackup();
- void setStatus(LLUUID itemid, std::string status);
- void finishItem(LLUUID itemid, std::string status);
- void advance();
- 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);
-
- int mItemsTotal;
- int mItemsCompleted;
-
- enum LIST_COLUMN_ORDER
- {
- LIST_TYPE,
- LIST_NAME,
- LIST_STATUS
- };
-
-};
-
-class LLInventoryBackup
-{
-public:
- static LLFilePicker::ESaveFilter getSaveFilter(LLInventoryItem* item);
- static std::string getExtension(LLInventoryItem* item);
- static std::string getUniqueFilename(std::string filename, std::string extension);
- static std::string getUniqueDirname(std::string dirname);
- static bool itemIsFolder(LLInventoryItem* item);
- static void save(LLFolderView* folder);
- static void download(LLInventoryItem* item, LLFloater* floater, loaded_callback_func onImage, LLGetAssetCallback onAsset);
- static std::string getPath(LLInventoryCategory* cat, std::vector cats);
-
- struct callbackdata
- {
- LLFloater* floater;
- LLInventoryItem* item;
- };
-
-private:
- 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 climb(LLInventoryCategory* cat,
- std::vector& cats,
- std::vector& items);
-};
-
-
-
-#endif
-//
+//
+#ifndef LL_LLINVENTORYBACKUP_H
+#define LL_LLINVENTORYBACKUP_H
+
+#if LL_WINDOWS
+#define OS_SEP "\\"
+#else
+#define OS_SEP "/"
+#endif
+
+
+#include "llviewerinventory.h"
+#include "llfolderview.h"
+#include "llfilepicker.h"
+#include "llviewerimage.h"
+#include "llfloater.h"
+
+
+class LLInventoryBackupOrder
+{
+public:
+ LLInventoryBackupOrder();
+
+ std::string mPath;
+ std::vector mCats;
+ std::vector mItems;
+
+ bool mDownloadTextures;
+ bool mDownloadSounds;
+ bool mDownloadCallingCards;
+ bool mDownloadLandmarks;
+ bool mDownloadScripts;
+ bool mDownloadWearables;
+ bool mDownloadObjects;
+ bool mDownloadNotecards;
+ bool mDownloadAnimations;
+ bool mDownloadGestures;
+ //bool mDownloadOthers;
+};
+
+class LLFloaterInventoryBackupSettings
+: public LLFloater
+{
+public:
+ LLFloaterInventoryBackupSettings(LLInventoryBackupOrder* order);
+ BOOL postBuild(void);
+ static void onClickNext(void* userdata);
+
+ LLInventoryBackupOrder* mOrder;
+ virtual ~LLFloaterInventoryBackupSettings();
+};
+
+class LLFloaterInventoryBackup
+: public LLFloater
+{
+public:
+ LLFloaterInventoryBackup(std::string path, std::vector cats, std::vector items);
+ BOOL postBuild(void);
+
+ std::string mPath;
+ std::vector mCats;
+ std::vector mItems;
+ std::vector::iterator mItemIter;
+ int mBusy;
+
+ static std::list sInstances;
+
+private:
+ virtual ~LLFloaterInventoryBackup();
+ void setStatus(LLUUID itemid, std::string status);
+ void finishItem(LLUUID itemid, std::string status);
+ void advance();
+ 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);
+
+ int mItemsTotal;
+ int mItemsCompleted;
+
+ enum LIST_COLUMN_ORDER
+ {
+ LIST_TYPE,
+ LIST_NAME,
+ LIST_STATUS
+ };
+
+};
+
+class LLInventoryBackup
+{
+public:
+ static LLFilePicker::ESaveFilter getSaveFilter(LLInventoryItem* item);
+ static std::string getExtension(LLInventoryItem* item);
+ static std::string getUniqueFilename(std::string filename, std::string extension);
+ static std::string getUniqueDirname(std::string dirname);
+ static bool itemIsFolder(LLInventoryItem* item);
+ static void save(LLFolderView* folder);
+ static void download(LLInventoryItem* item, LLFloater* floater, loaded_callback_func onImage, LLGetAssetCallback onAsset);
+ static std::string getPath(LLInventoryCategory* cat, std::vector cats);
+
+ struct callbackdata
+ {
+ LLFloater* floater;
+ LLInventoryItem* item;
+ };
+
+private:
+ 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 climb(LLInventoryCategory* cat,
+ std::vector& cats,
+ std::vector& items);
+};
+
+
+
+#endif
+//
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 690a10dc0..5a2a8ccfc 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -569,14 +569,14 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, std::vector
+ // for now, disable reupload
+ //if(getInventoryType() == LLInventoryType::IT_ANIMATION)
+ //{
+ // items.push_back(std::string("Reupload..."));
+ //}
+ items.push_back(std::string("Save As..."));
+ items.push_back(std::string("Save InvCache..."));
+ //
items.push_back(std::string("Copy Separator"));
@@ -955,98 +955,98 @@ void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model,
return;
}
//
- else if("open hex" == action)
- {
- LLInventoryItem* item = model->getItem(mUUID);
- if(!item) return;
- DOFloaterHex::show(mUUID);
- }
+ else if("open hex" == action)
+ {
+ LLInventoryItem* item = model->getItem(mUUID);
+ if(!item) return;
+ DOFloaterHex::show(mUUID);
+ }
else if("open text" == action)
{
LLInventoryItem* item = model->getItem(mUUID);
if(!item) return;
HGFloaterTextEditor::show(mUUID);
- }
- else if ("rez" == action)
- {
- LLInventoryItem* item = model->getItem(mUUID);
- if(!item) return;
- LLViewerRegion* regionp = gAgent.getRegion();
- if (!regionp)
- {
- llwarns << "Couldn't find region to rez object" << llendl;
- return;
- }
-
- //llinfos << "Rezzing object" << llendl;
- make_ui_sound("UISndObjectRezIn");
-
- if (regionp
- && (regionp->getRegionFlags() & REGION_FLAGS_SANDBOX))
- {
- LLFirstUse::useSandbox();
- }
-
- BOOL remove_from_inventory = !item->getPermissions().allowCopyBy(gAgent.getID());
-
- LLVector3 rezpos = gAgent.getPositionAgent() + (gAgent.getAtAxis() * 5.0f);
-
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_RezObject);
-
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID());
-
- msg->nextBlock("RezData");
- // if it's being rezzed from task inventory, we need to enable
- // saving it back into the task inventory.
- // *FIX: We can probably compress this to a single byte, since I
- // think folderid == mSourceID. This will be a later
- // optimization.
- msg->addUUIDFast(_PREHASH_FromTaskID, LLUUID::null);
- msg->addU8Fast(_PREHASH_BypassRaycast, (U8)TRUE);
- msg->addVector3Fast(_PREHASH_RayStart, rezpos);
- msg->addVector3Fast(_PREHASH_RayEnd, rezpos);
- msg->addUUIDFast(_PREHASH_RayTargetID, LLUUID::null);
- msg->addBOOLFast(_PREHASH_RayEndIsIntersection, FALSE);
- msg->addBOOLFast(_PREHASH_RezSelected, true);
- msg->addBOOLFast(_PREHASH_RemoveItem, remove_from_inventory);
-
- // deal with permissions slam logic
- pack_permissions_slam(msg, item->getFlags(), item->getPermissions());
-
- LLUUID folder_id = item->getParentUUID();
- msg->nextBlockFast(_PREHASH_InventoryData);
- item->packMessage(msg);
-
- msg->sendReliable(regionp->getHost());
- }
- else if("reupload" == action)
- {
- LLInventoryItem* item = model->getItem(mUUID);
- if(!item) return;
-
- LLFilePicker& picker = LLFilePicker::instance();
- std::string filename;
-
- switch(item->getType())
- {
- case LLAssetType::AT_TEXTURE:
- if(!picker.getOpenFile(LLFilePicker::FFLOAD_IMAGE))
- return;
- filename = picker.getFirstFile();
- if(!filename.empty())
- {
- LLFloaterImagePreview* floaterp = new LLFloaterImagePreview(filename, item);
- LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_image_preview.xml");
- }
- break;
- default:
- break;
- }
- }
+ }
+ else if ("rez" == action)
+ {
+ LLInventoryItem* item = model->getItem(mUUID);
+ if(!item) return;
+ LLViewerRegion* regionp = gAgent.getRegion();
+ if (!regionp)
+ {
+ llwarns << "Couldn't find region to rez object" << llendl;
+ return;
+ }
+
+ //llinfos << "Rezzing object" << llendl;
+ make_ui_sound("UISndObjectRezIn");
+
+ if (regionp
+ && (regionp->getRegionFlags() & REGION_FLAGS_SANDBOX))
+ {
+ LLFirstUse::useSandbox();
+ }
+
+ BOOL remove_from_inventory = !item->getPermissions().allowCopyBy(gAgent.getID());
+
+ LLVector3 rezpos = gAgent.getPositionAgent() + (gAgent.getAtAxis() * 5.0f);
+
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_RezObject);
+
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID());
+
+ msg->nextBlock("RezData");
+ // if it's being rezzed from task inventory, we need to enable
+ // saving it back into the task inventory.
+ // *FIX: We can probably compress this to a single byte, since I
+ // think folderid == mSourceID. This will be a later
+ // optimization.
+ msg->addUUIDFast(_PREHASH_FromTaskID, LLUUID::null);
+ msg->addU8Fast(_PREHASH_BypassRaycast, (U8)TRUE);
+ msg->addVector3Fast(_PREHASH_RayStart, rezpos);
+ msg->addVector3Fast(_PREHASH_RayEnd, rezpos);
+ msg->addUUIDFast(_PREHASH_RayTargetID, LLUUID::null);
+ msg->addBOOLFast(_PREHASH_RayEndIsIntersection, FALSE);
+ msg->addBOOLFast(_PREHASH_RezSelected, true);
+ msg->addBOOLFast(_PREHASH_RemoveItem, remove_from_inventory);
+
+ // deal with permissions slam logic
+ pack_permissions_slam(msg, item->getFlags(), item->getPermissions());
+
+ LLUUID folder_id = item->getParentUUID();
+ msg->nextBlockFast(_PREHASH_InventoryData);
+ item->packMessage(msg);
+
+ msg->sendReliable(regionp->getHost());
+ }
+ else if("reupload" == action)
+ {
+ LLInventoryItem* item = model->getItem(mUUID);
+ if(!item) return;
+
+ LLFilePicker& picker = LLFilePicker::instance();
+ std::string filename;
+
+ switch(item->getType())
+ {
+ case LLAssetType::AT_TEXTURE:
+ if(!picker.getOpenFile(LLFilePicker::FFLOAD_IMAGE))
+ return;
+ filename = picker.getFirstFile();
+ if(!filename.empty())
+ {
+ LLFloaterImagePreview* floaterp = new LLFloaterImagePreview(filename, item);
+ LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_image_preview.xml");
+ }
+ break;
+ default:
+ break;
+ }
+ }
//
}
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 8722ec8e3..70e45b943 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -59,12 +59,12 @@
#include "message.h"
#include "raytrace.h"
#include "llsdserialize.h"
-//
-#include "lllocalinventory.h"
-#include "llfloaterimport.h"
-#include "llfloaterexport.h"
-#include "llfloaterexploreanimations.h"
-//
+//
+#include "lllocalinventory.h"
+#include "llfloaterimport.h"
+#include "llfloaterexport.h"
+#include "llfloaterexploreanimations.h"
+//
#include "lltimer.h"
#include "llvfile.h"
#include "llvolumemgr.h"
@@ -228,11 +228,11 @@
#include "lltexlayer.h"
-//
+//
#include "dofloaterhex.h"
#include "hgfloatertexteditor.h"
#include "llfloatermessagelog.h"
-#include "llfloatermessagebuilder.h"
+#include "llfloatermessagebuilder.h"
//
using namespace LLVOAvatarDefines;
@@ -394,12 +394,12 @@ void handle_god_mode(void*);
// God menu
void handle_leave_god_mode(void*);
-//
+//
void handle_close_all_notifications(void*);
void handle_reopen_with_hex_editor(void*);
void handle_open_message_log(void*);
-void handle_open_message_builder(void*);
-//
+void handle_open_message_builder(void*);
+//
BOOL is_inventory_visible( void* user_data );
void handle_reset_view();
@@ -862,9 +862,9 @@ void init_client_menu(LLMenuGL* menu)
#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
- //
- //if (!LLViewerLogin::getInstance()->isInProductionGrid())
- //
+ //
+ //if (!LLViewerLogin::getInstance()->isInProductionGrid())
+ //
{
menu->append(new LLMenuItemCheckGL("Hacked Godmode",
&handle_toggle_hacked_godmode,
@@ -1034,12 +1034,12 @@ void init_client_menu(LLMenuGL* menu)
menu->append(new LLMenuItemCallGL("Leave Admin Status",
&handle_leave_god_mode, NULL, NULL, 'G', MASK_ALT | MASK_SHIFT | MASK_CONTROL));
- //
+ //
menu->appendSeparator();
- menu->append(new LLMenuItemCallGL( "Close All Dialogs",
- &handle_close_all_notifications, NULL, NULL, 'D', MASK_CONTROL | MASK_ALT | MASK_SHIFT));
+ menu->append(new LLMenuItemCallGL( "Close All Dialogs",
+ &handle_close_all_notifications, NULL, NULL, 'D', MASK_CONTROL | MASK_ALT | MASK_SHIFT));
- menu->append(new LLMenuItemCallGL( "Reopen with Hex Editor",
+ menu->append(new LLMenuItemCallGL( "Reopen with Hex Editor",
&handle_reopen_with_hex_editor, NULL));
menu->append(new LLMenuItemCallGL( "Message Log", &handle_open_message_log, NULL));
@@ -1149,10 +1149,10 @@ void init_debug_xui_menu(LLMenuGL* menu)
menu->append(new LLMenuItemCallGL("Export Menus to XML...", handle_export_menus_to_xml));
menu->append(new LLMenuItemCallGL("Edit UI...", LLFloaterEditUI::show));
menu->append(new LLMenuItemCallGL("Load from XML...", handle_load_from_xml));
- //
- //menu->append(new LLMenuItemCallGL("Save to XML...", handle_save_to_xml));
- menu->append(new LLMenuItemCallGL("Save to XML...", handle_save_to_xml, NULL, NULL, 'X', MASK_CONTROL | MASK_ALT | MASK_SHIFT));
- //
+ //
+ //menu->append(new LLMenuItemCallGL("Save to XML...", handle_save_to_xml));
+ menu->append(new LLMenuItemCallGL("Save to XML...", handle_save_to_xml, NULL, NULL, 'X', MASK_CONTROL | MASK_ALT | MASK_SHIFT));
+ //
menu->append(new LLMenuItemCheckGL("Show XUI Names", toggle_show_xui_names, NULL, check_show_xui_names, NULL));
//menu->append(new LLMenuItemCallGL("Buy Currency...", handle_buy_currency));
@@ -1462,14 +1462,14 @@ void init_debug_avatar_menu(LLMenuGL* menu)
menu->append(new LLMenuItemToggleGL( "Debug Rotation", &LLVOAvatar::sDebugAvatarRotation));
menu->append(new LLMenuItemCallGL("Dump Attachments", handle_dump_attachments));
menu->append(new LLMenuItemCallGL("Rebake Textures", handle_rebake_textures, NULL, NULL, 'R', MASK_ALT | MASK_CONTROL ));
-//
-//#ifndef LL_RELEASE_FOR_DOWNLOAD
-//
+//
+//#ifndef LL_RELEASE_FOR_DOWNLOAD
+//
menu->append(new LLMenuItemCallGL("Debug Avatar Textures", handle_debug_avatar_textures, NULL, NULL, 'A', MASK_SHIFT|MASK_CONTROL|MASK_ALT));
menu->append(new LLMenuItemCallGL("Dump Local Textures", handle_dump_avatar_local_textures, NULL, NULL, 'M', MASK_SHIFT|MASK_ALT ));
-//
-//#endif
-//
+//
+//#endif
+//
menu->createJumpKeys();
}
@@ -2194,125 +2194,125 @@ class LLObjectMute : public view_listener_t
}
};
-//
-class LLObjectEnableCopyUUID : public view_listener_t
-{
- bool handleEvent(LLPointer event, const LLSD& userdata)
- {
- LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
- bool new_value = (object != NULL);
- gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
- return true;
- }
-};
-
-class LLObjectCopyUUID : public view_listener_t
-{
- bool handleEvent(LLPointer event, const LLSD& userdata)
- {
- LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
- if(object)
- {
- gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(object->getID().asString()));
- }
- return true;
- }
-};
-
-class LLObjectEnableSaveAs : public view_listener_t
-{
- bool handleEvent(LLPointer event, const LLSD& userdata)
- {
- LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
- bool new_value = (object != NULL);
- gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
- return true;
- }
-};
-
-class LLObjectSaveAs : public view_listener_t
-{
- bool handleEvent(LLPointer event, const LLSD& userdata)
- {
- LLFloaterExport* floater = new LLFloaterExport();
- floater->center();
- return true;
- }
-};
-
-class LLObjectEnableImport : public view_listener_t
-{
- bool handleEvent(LLPointer event, const LLSD& userdata)
- {
- LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
- bool new_value = (object != NULL);
- if(object)
- {
- if(!object->permCopy())
- new_value = false;
- else if(!object->permModify())
- new_value = false;
- else if(!object->permMove())
- new_value = false;
- else if(object->numChildren() != 0)
- new_value = false;
- else if(object->getParent())
- new_value = false;
- }
- gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
- return true;
- }
-};
-
-class LLObjectImport : public view_listener_t
-{
- bool handleEvent(LLPointer event, const LLSD& userdata)
- {
- LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
- bool new_value = (object != NULL);
- if(object)
- {
- if(!object->permCopy())
- new_value = false;
- else if(!object->permModify())
- new_value = false;
- else if(!object->permMove())
- new_value = false;
- else if(object->numChildren() != 0)
- new_value = false;
- else if(object->getParent())
- new_value = false;
- }
- if(new_value == false) return true;
-
- LLFilePicker& picker = LLFilePicker::instance();
- if (!picker.getOpenFile(LLFilePicker::FFLOAD_XML))
- {
- return true;
- }
- std::string file_name = picker.getFirstFile();
- LLXmlImportOptions* options = new LLXmlImportOptions(file_name);
- options->mSupplier = object;
- new LLFloaterXmlImportOptions(options);
- return true;
- }
-};
-
-class LLAvatarAnims : public view_listener_t
-{
- bool handleEvent(LLPointer event, const LLSD& userdata)
- {
- LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
- if(avatar)
- {
- new LLFloaterExploreAnimations(avatar->getID()); //temporary
- }
- return true;
- }
-};
-
+//
+class LLObjectEnableCopyUUID : public view_listener_t
+{
+ bool handleEvent(LLPointer event, const LLSD& userdata)
+ {
+ LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ bool new_value = (object != NULL);
+ gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
+ return true;
+ }
+};
+
+class LLObjectCopyUUID : public view_listener_t
+{
+ bool handleEvent(LLPointer event, const LLSD& userdata)
+ {
+ LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if(object)
+ {
+ gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(object->getID().asString()));
+ }
+ return true;
+ }
+};
+
+class LLObjectEnableSaveAs : public view_listener_t
+{
+ bool handleEvent(LLPointer event, const LLSD& userdata)
+ {
+ LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ bool new_value = (object != NULL);
+ gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
+ return true;
+ }
+};
+
+class LLObjectSaveAs : public view_listener_t
+{
+ bool handleEvent(LLPointer event, const LLSD& userdata)
+ {
+ LLFloaterExport* floater = new LLFloaterExport();
+ floater->center();
+ return true;
+ }
+};
+
+class LLObjectEnableImport : public view_listener_t
+{
+ bool handleEvent(LLPointer event, const LLSD& userdata)
+ {
+ LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ bool new_value = (object != NULL);
+ if(object)
+ {
+ if(!object->permCopy())
+ new_value = false;
+ else if(!object->permModify())
+ new_value = false;
+ else if(!object->permMove())
+ new_value = false;
+ else if(object->numChildren() != 0)
+ new_value = false;
+ else if(object->getParent())
+ new_value = false;
+ }
+ gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
+ return true;
+ }
+};
+
+class LLObjectImport : public view_listener_t
+{
+ bool handleEvent(LLPointer event, const LLSD& userdata)
+ {
+ LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ bool new_value = (object != NULL);
+ if(object)
+ {
+ if(!object->permCopy())
+ new_value = false;
+ else if(!object->permModify())
+ new_value = false;
+ else if(!object->permMove())
+ new_value = false;
+ else if(object->numChildren() != 0)
+ new_value = false;
+ else if(object->getParent())
+ new_value = false;
+ }
+ if(new_value == false) return true;
+
+ LLFilePicker& picker = LLFilePicker::instance();
+ if (!picker.getOpenFile(LLFilePicker::FFLOAD_XML))
+ {
+ return true;
+ }
+ std::string file_name = picker.getFirstFile();
+ LLXmlImportOptions* options = new LLXmlImportOptions(file_name);
+ options->mSupplier = object;
+ new LLFloaterXmlImportOptions(options);
+ return true;
+ }
+};
+
+class LLAvatarAnims : public view_listener_t
+{
+ bool handleEvent(LLPointer event, const LLSD& userdata)
+ {
+ LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
+ if(avatar)
+ {
+ new LLFloaterExploreAnimations(avatar->getID()); //temporary
+ }
+ return true;
+ }
+};
+
//
-
+
bool handle_go_to()
{
LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal;
@@ -3191,10 +3191,10 @@ bool handle_sit_or_stand()
{
LLPickInfo pick = LLToolPie::getInstance()->getPick();
LLViewerObject *object = pick.getObject();;
- //
- //if (!object || pick.mPickType == LLPickInfo::PICK_FLORA)
- if (!object)
- //
+ //
+ //if (!object || pick.mPickType == LLPickInfo::PICK_FLORA)
+ if (!object)
+ //
{
return true;
}
@@ -3799,12 +3799,12 @@ void derez_objects(EDeRezDestination dest, const LLUUID& dest_id)
break;
default:
- //
- //if((node->mPermissions->allowTransferTo(gAgent.getID())
- // && object->permCopy())
- // || gAgent.isGodlike())
- if(1)
- //
+ //
+ //if((node->mPermissions->allowTransferTo(gAgent.getID())
+ // && object->permCopy())
+ // || gAgent.isGodlike())
+ if(1)
+ //
{
can_derez_current = TRUE;
}
@@ -3861,17 +3861,17 @@ void derez_objects(EDeRezDestination dest, const LLUUID& dest_id)
LLViewerObject* object = derez_objects.get(object_index++);
msg->nextBlockFast(_PREHASH_ObjectData);
msg->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID());
- //
- if(!gSavedSettings.getBOOL("DisablePointAtAndBeam"))
- {
- //
+ //
+ if(!gSavedSettings.getBOOL("DisablePointAtAndBeam"))
+ {
+ //
// VEFFECT: DerezObject
LLHUDEffectSpiral* effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
effectp->setPositionGlobal(object->getPositionGlobal());
effectp->setColor(LLColor4U(gAgent.getEffectColor()));
- //
- }
- //
+ //
+ }
+ //
}
msg->sendReliable(first_region->getHost());
}
@@ -4359,20 +4359,20 @@ BOOL sitting_on_selection()
return (avatar->mIsSitting && avatar->getRoot() == root_object);
}
-class LLToolsSaveToInventory : public view_listener_t
-{
- bool handleEvent(LLPointer event, const LLSD& userdata)
- {
- //
- //if(enable_save_into_inventory(NULL))
- if(1)
- //
- {
- derez_objects(DRD_SAVE_INTO_AGENT_INVENTORY, LLUUID::null);
- }
- return true;
- }
-};
+class LLToolsSaveToInventory : public view_listener_t
+{
+ bool handleEvent(LLPointer event, const LLSD& userdata)
+ {
+ //
+ //if(enable_save_into_inventory(NULL))
+ if(1)
+ //
+ {
+ derez_objects(DRD_SAVE_INTO_AGENT_INVENTORY, LLUUID::null);
+ }
+ return true;
+ }
+};
class LLToolsSaveToObjectInventory : public view_listener_t
{
bool handleEvent(LLPointer event, const LLSD& userdata)
@@ -6368,10 +6368,10 @@ class LLObjectEnableWear : public view_listener_t
bool handleEvent(LLPointer event, const LLSD& userdata)
{
bool is_wearable = object_selected_and_point_valid(NULL);
- // Don't allow attaching objects while importing attachments
- if(LLXmlImport::sImportInProgress && LLXmlImport::sImportHasAttachments)
- is_wearable = false;
- //
+ // Don't allow attaching objects while importing attachments
+ if(LLXmlImport::sImportInProgress && LLXmlImport::sImportHasAttachments)
+ is_wearable = false;
+ //
gMenuHolder->findControl(userdata["control"].asString())->setValue(is_wearable);
return TRUE;
}
@@ -6542,10 +6542,10 @@ class LLToolsSelectedScriptAction : public view_listener_t
void handle_selected_texture_info(void*)
{
- //
- std::map unique_textures;
- S32 total_memory = 0;
- //
+ //
+ std::map unique_textures;
+ S32 total_memory = 0;
+ //
for (LLObjectSelection::valid_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_begin();
iter != LLSelectMgr::getInstance()->getSelection()->valid_end(); iter++)
{
@@ -6568,33 +6568,33 @@ void handle_selected_texture_info(void*)
LLViewerImage* img = node->getObject()->getTEImage(i);
LLUUID image_id = img->getID();
faces_per_texture[image_id].push_back(i);
- //
- if(!unique_textures[image_id])
- {
- unique_textures[image_id] = true;
- total_memory += (img->getWidth() * img->getHeight() * img->getComponents());
- }
- //
+ //
+ if(!unique_textures[image_id])
+ {
+ unique_textures[image_id] = true;
+ total_memory += (img->getWidth() * img->getHeight() * img->getComponents());
+ }
+ //
}
// Per-texture, dump which faces are using it.
map_t::iterator it;
for (it = faces_per_texture.begin(); it != faces_per_texture.end(); ++it)
{
LLUUID image_id = it->first;
- //
- std::string uuid_str;
- image_id.toString(uuid_str);
- //
+ //
+ std::string uuid_str;
+ image_id.toString(uuid_str);
+ //
U8 te = it->second[0];
LLViewerImage* img = node->getObject()->getTEImage(te);
S32 height = img->getHeight();
S32 width = img->getWidth();
S32 components = img->getComponents();
- //
- //msg = llformat("%dx%d %s on face ",
- msg = llformat("%s, %dx%d %s on face ",
- uuid_str.c_str(),
- //
+ //
+ //msg = llformat("%dx%d %s on face ",
+ msg = llformat("%s, %dx%d %s on face ",
+ uuid_str.c_str(),
+ //
width,
height,
(components == 4 ? "alpha" : "opaque"));
@@ -6605,41 +6605,41 @@ void handle_selected_texture_info(void*)
LLChat chat(msg);
LLFloaterChat::addChat(chat);
}
- //
- if(node->getObject()->isSculpted())
- {
- LLSculptParams *sculpt_params = (LLSculptParams *)(node->getObject()->getParameterEntry(LLNetworkData::PARAMS_SCULPT));
- LLUUID sculpt_id = sculpt_params->getSculptTexture();
- std::string uuid_str;
- sculpt_id.toString(uuid_str);
- msg.assign("Sculpt texture: ");
- msg.append(uuid_str.c_str());
- LLChat chat(msg);
- LLFloaterChat::addChat(chat);
-
- unique_textures[sculpt_id] = true;
+ //
+ if(node->getObject()->isSculpted())
+ {
+ LLSculptParams *sculpt_params = (LLSculptParams *)(node->getObject()->getParameterEntry(LLNetworkData::PARAMS_SCULPT));
+ LLUUID sculpt_id = sculpt_params->getSculptTexture();
+ std::string uuid_str;
+ sculpt_id.toString(uuid_str);
+ msg.assign("Sculpt texture: ");
+ msg.append(uuid_str.c_str());
+ LLChat chat(msg);
+ LLFloaterChat::addChat(chat);
+
+ unique_textures[sculpt_id] = true;
}
- if(node->getObject()->isParticleSource())
- {
- //LLUUID particle_id = node->getObject()->mPartSourcep->getImage()->getID();
- }
- //
- }
- //
- typedef std::map::iterator map_iter;
- for(map_iter i = unique_textures.begin(); i != unique_textures.end(); ++i)
- {
- LLUUID asset_id = (*i).first;
- LLLocalInventory::addItem(asset_id.asString(), (int)LLAssetType::AT_TEXTURE, asset_id, true);
- }
-
- // Show total widthxheight
- F32 memoriez = (F32)total_memory;
- memoriez = memoriez / 1000000;
- std::string msg = llformat("Total uncompressed: %f MB", memoriez);
- LLChat chat(msg);
- LLFloaterChat::addChat(chat);
- //
+ if(node->getObject()->isParticleSource())
+ {
+ //LLUUID particle_id = node->getObject()->mPartSourcep->getImage()->getID();
+ }
+ //
+ }
+ //
+ typedef std::map::iterator map_iter;
+ for(map_iter i = unique_textures.begin(); i != unique_textures.end(); ++i)
+ {
+ LLUUID asset_id = (*i).first;
+ LLLocalInventory::addItem(asset_id.asString(), (int)LLAssetType::AT_TEXTURE, asset_id, true);
+ }
+
+ // Show total widthxheight
+ F32 memoriez = (F32)total_memory;
+ memoriez = memoriez / 1000000;
+ std::string msg = llformat("Total uncompressed: %f MB", memoriez);
+ LLChat chat(msg);
+ LLFloaterChat::addChat(chat);
+ //
}
void handle_dump_image_list(void*)
@@ -6872,25 +6872,25 @@ class LLToolsEnableTakeCopy : public view_listener_t
}
};
-//
-class LLToolsEnableAdminDelete : public view_listener_t
-{
- bool handleEvent(LLPointer event, const LLSD& userdata)
- {
- LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
- return (object != NULL);
- }
-};
-class LLToolsAdminDelete : public view_listener_t
-{
- bool handleEvent(LLPointer event, const LLSD& userdata)
- {
- LLSelectMgr::getInstance()->selectForceDelete();
- return true;
- }
-};
+//
+class LLToolsEnableAdminDelete : public view_listener_t
+{
+ bool handleEvent(LLPointer event, const LLSD& userdata)
+ {
+ LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ return (object != NULL);
+ }
+};
+class LLToolsAdminDelete : public view_listener_t
+{
+ bool handleEvent(LLPointer event, const LLSD& userdata)
+ {
+ LLSelectMgr::getInstance()->selectForceDelete();
+ return true;
+ }
+};
//
-
+
BOOL enable_selection_you_own_all(void*)
{
if (LLSelectMgr::getInstance())
@@ -8132,11 +8132,11 @@ void initialize_menus()
addMenu(new LLToolsLookAtSelection(), "Tools.LookAtSelection");
addMenu(new LLToolsBuyOrTake(), "Tools.BuyOrTake");
addMenu(new LLToolsTakeCopy(), "Tools.TakeCopy");
- addMenu(new LLToolsTakeCopy(), "Tools.TakeCopy");
- //
- addMenu(new LLToolsEnableAdminDelete(), "Tools.EnableAdminDelete");
- addMenu(new LLToolsAdminDelete(), "Tools.AdminDelete");
- //
+ addMenu(new LLToolsTakeCopy(), "Tools.TakeCopy");
+ //
+ addMenu(new LLToolsEnableAdminDelete(), "Tools.EnableAdminDelete");
+ addMenu(new LLToolsAdminDelete(), "Tools.AdminDelete");
+ //
addMenu(new LLToolsSaveToObjectInventory(), "Tools.SaveToObjectInventory");
addMenu(new LLToolsSelectedScriptAction(), "Tools.SelectedScriptAction");
@@ -8187,11 +8187,11 @@ void initialize_menus()
addMenu(new LLObjectAttachToAvatar(), "Object.AttachToAvatar");
addMenu(new LLObjectReturn(), "Object.Return");
addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse");
- addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse");
- //
- addMenu(new LLObjectSaveAs(), "Object.SaveAs");
- addMenu(new LLObjectImport(), "Object.Import");
- //
+ addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse");
+ //
+ addMenu(new LLObjectSaveAs(), "Object.SaveAs");
+ addMenu(new LLObjectImport(), "Object.Import");
+ //
addMenu(new LLObjectMute(), "Object.Mute");
addMenu(new LLObjectBuy(), "Object.Buy");
addMenu(new LLObjectEdit(), "Object.Edit");
@@ -8204,10 +8204,10 @@ void initialize_menus()
addMenu(new LLObjectEnableWear(), "Object.EnableWear");
addMenu(new LLObjectEnableReturn(), "Object.EnableReturn");
addMenu(new LLObjectEnableReportAbuse(), "Object.EnableReportAbuse");
- //
- addMenu(new LLObjectEnableSaveAs(), "Object.EnableSaveAs");
- addMenu(new LLObjectEnableImport(), "Object.EnableImport");
- //
+ //
+ addMenu(new LLObjectEnableSaveAs(), "Object.EnableSaveAs");
+ addMenu(new LLObjectEnableImport(), "Object.EnableImport");
+ //
addMenu(new LLObjectEnableMute(), "Object.EnableMute");
addMenu(new LLObjectEnableBuy(), "Object.EnableBuy");
diff --git a/indra/newview/skins/default/xui/en-us/floater_hex.xml b/indra/newview/skins/default/xui/en-us/floater_hex.xml
index b8377193e..36f02f068 100644
--- a/indra/newview/skins/default/xui/en-us/floater_hex.xml
+++ b/indra/newview/skins/default/xui/en-us/floater_hex.xml
@@ -2,7 +2,12 @@
- Loading...
+ Loading...
+
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 abc2f6e7c..70cd4f2a5 100644
--- a/indra/newview/skins/default/xui/en-us/floater_inventory.xml
+++ b/indra/newview/skins/default/xui/en-us/floater_inventory.xml
@@ -146,10 +146,10 @@
-
-
-
+
+
+
[FIRST] [LAST]
+
+
>sys.stderr, "This script is not inside a valid installation."
- sys.exit(1)
-
-base_dir = add_indra_lib_path()
-defaultUserAgent = 'Lynx/2.8.6rel.5 libwww-FM/2.14' #pretend to be lynx because github sucks a fat dick
-
-import copy
-import optparse
-import os
-import platform
-import pprint
-import shutil
-import tarfile
-import tempfile
-import urllib2
-import urlparse
-
-from indra.base import llsd
-from indra.util import helpformatter
-
-# *HACK: Necessary for python 2.4. Consider replacing this code wart
-# after python >=2.5 has deployed everywhere. 2009-10-05
-try:
- from hashlib import md5
-except ImportError:
- from md5 import md5
-
-class InstallFile(object):
- "This is just a handy way to throw around details on a file in memory."
- def __init__(self, pkgname, url, md5sum, cache_dir, platform_path):
- self.pkgname = pkgname
- self.url = url
- self.md5sum = md5sum
- filename = urlparse.urlparse(url)[2].split('/')[-1]
- self.filename = os.path.join(cache_dir, filename)
- self.platform_path = platform_path
-
- def __str__(self):
- return "ifile{%s:%s}" % (self.pkgname, self.url)
-
- def _is_md5sum_match(self):
- hasher = md5(file(self.filename, 'rb').read())
- if hasher.hexdigest() == self.md5sum:
- return True
- return False
-
- def is_match(self, platform):
- """@brief Test to see if this ifile is part of platform
- @param platform The target platform. Eg, windows or linux/i686/gcc/3.3
- @return Returns True if the ifile is in the platform.
- """
- if self.platform_path[0] == 'common':
- return True
- req_platform_path = platform.split('/')
- #print "platform:",req_platform_path
- #print "path:",self.platform_path
- # to match, every path part much match
- match_count = min(len(req_platform_path), len(self.platform_path))
- for ii in range(0, match_count):
- if req_platform_path[ii] != self.platform_path[ii]:
- return False
- #print "match!"
- return True
-
- def fetch_local(self):
- #print "Looking for:",self.filename
- if not os.path.exists(self.filename):
- pass
- elif self.md5sum and not self._is_md5sum_match():
- print "md5 mismatch:", self.filename
- os.remove(self.filename)
- else:
- print "Found matching package:", self.filename
- return
- print "Downloading",self.url,"to local file",self.filename
-
- request = urllib2.Request(self.url)
-
- if re.match("/^http:\/\/github.com/", self.url):
- request.add_header('User-agent', defaultUserAgent)
-
- file(self.filename, 'wb').write(urllib2.urlopen(request).read())
- if self.md5sum and not self._is_md5sum_match():
- raise RuntimeError("Error matching md5 for %s" % self.url)
-
-class LicenseDefinition(object):
- def __init__(self, definition):
- #probably looks like:
- # { text : ...,
- # url : ...
- # blessed : ...
- # }
- self._definition = definition
-
-
-class InstallableDefinition(object):
- def __init__(self, definition):
- #probably looks like:
- # { packages : {platform...},
- # copyright : ...
- # license : ...
- # description: ...
- # }
- self._definition = definition
-
- def _ifiles_from(self, tree, pkgname, cache_dir):
- return self._ifiles_from_path(tree, pkgname, cache_dir, [])
-
- def _ifiles_from_path(self, tree, pkgname, cache_dir, path):
- ifiles = []
- if 'url' in tree:
- ifiles.append(InstallFile(
- pkgname,
- tree['url'],
- tree.get('md5sum', None),
- cache_dir,
- path))
- else:
- for key in tree:
- platform_path = copy.copy(path)
- platform_path.append(key)
- ifiles.extend(
- self._ifiles_from_path(
- tree[key],
- pkgname,
- cache_dir,
- platform_path))
- return ifiles
-
- def ifiles(self, pkgname, platform, cache_dir):
- """@brief return a list of appropriate InstallFile instances to install
- @param pkgname The name of the package to be installed, eg 'tut'
- @param platform The target platform. Eg, windows or linux/i686/gcc/3.3
- @param cache_dir The directory to cache downloads.
- @return Returns a list of InstallFiles which are part of this install
- """
- if 'packages' not in self._definition:
- return []
- all_ifiles = self._ifiles_from(
- self._definition['packages'],
- pkgname,
- cache_dir)
- if platform == 'all':
- return all_ifiles
- #print "Considering", len(all_ifiles), "packages for", pkgname
- # split into 2 lines because pychecker thinks it might return none.
- files = [ifile for ifile in all_ifiles if ifile.is_match(platform)]
- return files
-
-class InstalledPackage(object):
- def __init__(self, definition):
- # looks like:
- # { url1 : { files: [file1,file2,...], md5sum:... },
- # url2 : { files: [file1,file2,...], md5sum:... },...
- # }
- self._installed = {}
- for url in definition:
- self._installed[url] = definition[url]
-
- def urls(self):
- return self._installed.keys()
-
- def files_in(self, url):
- return self._installed[url].get('files', [])
-
- def get_md5sum(self, url):
- return self._installed[url].get('md5sum', None)
-
- def remove(self, url):
- self._installed.pop(url)
-
- def add_files(self, url, files):
- if url not in self._installed:
- self._installed[url] = {}
- self._installed[url]['files'] = files
-
- def set_md5sum(self, url, md5sum):
- if url not in self._installed:
- self._installed[url] = {}
- self._installed[url]['md5sum'] = md5sum
-
-class Installer(object):
- def __init__(self, install_filename, installed_filename, dryrun):
- self._install_filename = install_filename
- self._install_changed = False
- self._installed_filename = installed_filename
- self._installed_changed = False
- self._dryrun = dryrun
- self._installables = {}
- self._licenses = {}
- self._installed = {}
- self.load()
-
- def load(self):
- if os.path.exists(self._install_filename):
- install = llsd.parse(file(self._install_filename, 'rb').read())
- try:
- for name in install['installables']:
- self._installables[name] = InstallableDefinition(
- install['installables'][name])
- except KeyError:
- pass
- try:
- for name in install['licenses']:
- self._licenses[name] = LicenseDefinition(install['licenses'][name])
- except KeyError:
- pass
- if os.path.exists(self._installed_filename):
- installed = llsd.parse(file(self._installed_filename, 'rb').read())
- try:
- bins = installed['installables']
- for name in bins:
- self._installed[name] = InstalledPackage(bins[name])
- except KeyError:
- pass
-
- def _write(self, filename, state):
- print "Writing state to",filename
- if not self._dryrun:
- file(filename, 'wb').write(llsd.format_pretty_xml(state))
-
- def save(self):
- if self._install_changed:
- state = {}
- state['licenses'] = {}
- for name in self._licenses:
- state['licenses'][name] = self._licenses[name]._definition
- #print "self._installables:",self._installables
- state['installables'] = {}
- for name in self._installables:
- state['installables'][name] = \
- self._installables[name]._definition
- self._write(self._install_filename, state)
- if self._installed_changed:
- state = {}
- state['installables'] = {}
- bin = state['installables']
- for name in self._installed:
- #print "installed:",name,self._installed[name]._installed
- bin[name] = self._installed[name]._installed
- self._write(self._installed_filename, state)
-
- def is_valid_license(self, bin):
- "@brief retrun true if we have valid license info for installable."
- installable = self._installables[bin]._definition
- if 'license' not in installable:
- print >>sys.stderr, "No license info found for", bin
- print >>sys.stderr, 'Please add the license with the',
- print >>sys.stderr, '--add-installable option. See', \
- sys.argv[0], '--help'
- return False
- if installable['license'] not in self._licenses:
- lic = installable['license']
- print >>sys.stderr, "Missing license info for '" + lic + "'.",
- print >>sys.stderr, 'Please add the license with the',
- print >>sys.stderr, '--add-license option. See', sys.argv[0],
- print >>sys.stderr, '--help'
- return False
- return True
-
- def list_installables(self):
- "Return a list of all known installables."
- return sorted(self._installables.keys())
-
- def detail_installable(self, name):
- "Return a installable definition detail"
- return self._installables[name]._definition
-
- def list_licenses(self):
- "Return a list of all known licenses."
- return sorted(self._licenses.keys())
-
- def detail_license(self, name):
- "Return a license definition detail"
- return self._licenses[name]._definition
-
- def list_installed(self):
- "Return a list of installed packages."
- return sorted(self._installed.keys())
-
- def detail_installed(self, name):
- "Return file list for specific installed package."
- filelist = []
- for url in self._installed[name]._installed.keys():
- filelist.extend(self._installed[name].files_in(url))
- return filelist
-
- def _update_field(self, description, field, value, multiline=False):
- """Given a block and a field name, add or update it.
- @param description a dict containing all the details of a description.
- @param field the name of the field to update.
- @param value the value of the field to update; if omitted, interview
- will ask for value.
- @param multiline boolean specifying whether field is multiline or not.
- """
- if value:
- description[field] = value
- else:
- if field in description:
- print "Update value for '" + field + "'"
- print "(Leave blank to keep current value)"
- print "Current Value: '" + description[field] + "'"
- else:
- print "Specify value for '" + field + "'"
- if not multiline:
- new_value = raw_input("Enter New Value: ")
- else:
- print "Please enter " + field + ". End input with EOF (^D)."
- new_value = sys.stdin.read()
-
- if field in description and not new_value:
- pass
- elif new_value:
- description[field] = new_value
-
- self._install_changed = True
- return True
-
- def _update_installable(self, name, platform, url, md5sum):
- """Update installable entry with specific package information.
- @param installable[in,out] a dict containing installable details.
- @param platform Platform info, i.e. linux/i686, windows/i686 etc.
- @param url URL of tar file
- @param md5sum md5sum of tar file
- """
- installable = self._installables[name]._definition
- path = platform.split('/')
- if 'packages' not in installable:
- installable['packages'] = {}
- update = installable['packages']
- for child in path:
- if child not in update:
- update[child] = {}
- parent = update
- update = update[child]
- parent[child]['url'] = llsd.uri(url)
- parent[child]['md5sum'] = md5sum
-
- self._install_changed = True
- return True
-
-
- def add_installable_package(self, name, **kwargs):
- """Add an url for a platform path to the installable.
- @param installable[in,out] a dict containing installable details.
- """
- platform_help_str = """\
-Please enter a new package location and url. Some examples:
-common -- specify a package for all platforms
-linux -- specify a package for all arch and compilers on linux
-darwin/universal -- specify a mac os x universal
-windows/i686/vs/2003 -- specify a windows visual studio 2003 package"""
- if name not in self._installables:
- print "Error: must add library with --add-installable or " \
- +"--add-installable-metadata before using " \
- +"--add-installable-package option"
- return False
- else:
- print "Updating installable '" + name + "'."
- for arg in ('platform', 'url', 'md5sum'):
- if not kwargs[arg]:
- if arg == 'platform':
- print platform_help_str
- kwargs[arg] = raw_input("Package "+arg+":")
- #path = kwargs['platform'].split('/')
-
- return self._update_installable(name, kwargs['platform'],
- kwargs['url'], kwargs['md5sum'])
-
- def add_installable_metadata(self, name, **kwargs):
- """Interactively add (only) library metadata into install,
- w/o adding installable"""
- if name not in self._installables:
- print "Adding installable '" + name + "'."
- self._installables[name] = InstallableDefinition({})
- else:
- print "Updating installable '" + name + "'."
- installable = self._installables[name]._definition
- for field in ('copyright', 'license', 'description'):
- self._update_field(installable, field, kwargs[field])
- print "Added installable '" + name + "':"
- pprint.pprint(self._installables[name])
-
- return True
-
- def add_installable(self, name, **kwargs):
- "Interactively pull a new installable into the install"
- ret_a = self.add_installable_metadata(name, **kwargs)
- ret_b = self.add_installable_package(name, **kwargs)
- return (ret_a and ret_b)
-
- def remove_installable(self, name):
- self._installables.pop(name)
- self._install_changed = True
-
- def add_license(self, name, **kwargs):
- if name not in self._licenses:
- print "Adding license '" + name + "'."
- self._licenses[name] = LicenseDefinition({})
- else:
- print "Updating license '" + name + "'."
- the_license = self._licenses[name]._definition
- for field in ('url', 'text'):
- multiline = False
- if field == 'text':
- multiline = True
- self._update_field(the_license, field, kwargs[field], multiline)
- self._install_changed = True
- return True
-
- def remove_license(self, name):
- self._licenses.pop(name)
- self._install_changed = True
-
- def _uninstall(self, installables):
- """@brief Do the actual removal of files work.
- *NOTE: This method is not transactionally safe -- ie, if it
- raises an exception, internal state may be inconsistent. How
- should we address this?
- @param installables The package names to remove
- """
- remove_file_list = []
- for pkgname in installables:
- for url in self._installed[pkgname].urls():
- remove_file_list.extend(
- self._installed[pkgname].files_in(url))
- self._installed[pkgname].remove(url)
- if not self._dryrun:
- self._installed_changed = True
- if not self._dryrun:
- self._installed.pop(pkgname)
- remove_dir_set = set()
- for filename in remove_file_list:
- print "rm",filename
- if not self._dryrun:
- if os.path.exists(filename):
- remove_dir_set.add(os.path.dirname(filename))
- try:
- os.remove(filename)
- except OSError:
- # This is just for cleanup, so we don't care
- # about normal failures.
- pass
- for dirname in remove_dir_set:
- try:
- os.removedirs(dirname)
- except OSError:
- # This is just for cleanup, so we don't care about
- # normal failures.
- pass
-
- def uninstall(self, installables, install_dir):
- """@brief Remove the packages specified.
- @param installables The package names to remove
- @param install_dir The directory to work from
- """
- print "uninstall",installables,"from",install_dir
- cwd = os.getcwdu()
- os.chdir(install_dir)
- try:
- self._uninstall(installables)
- finally:
- os.chdir(cwd)
-
- def _build_ifiles(self, platform, cache_dir):
- """@brief determine what files to install
- @param platform The target platform. Eg, windows or linux/i686/gcc/3.3
- @param cache_dir The directory to cache downloads.
- @return Returns the ifiles to install
- """
- ifiles = []
- for bin in self._installables:
- ifiles.extend(self._installables[bin].ifiles(bin,
- platform,
- cache_dir))
- to_install = []
- #print "self._installed",self._installed
- for ifile in ifiles:
- if ifile.pkgname not in self._installed:
- to_install.append(ifile)
- elif ifile.url not in self._installed[ifile.pkgname].urls():
- to_install.append(ifile)
- elif ifile.md5sum != \
- self._installed[ifile.pkgname].get_md5sum(ifile.url):
- # *TODO: We may want to uninstall the old version too
- # when we detect it is installed, but the md5 sum is
- # different.
- to_install.append(ifile)
- else:
- #print "Installation up to date:",
- # ifile.pkgname,ifile.platform_path
- pass
- #print "to_install",to_install
- return to_install
-
- def _install(self, to_install, install_dir):
- for ifile in to_install:
- tar = tarfile.open(ifile.filename, 'r')
- print "Extracting",ifile.filename,"to",install_dir
- if not self._dryrun:
- # *NOTE: try to call extractall, which first appears
- # in python 2.5. Phoenix 2008-01-28
- try:
- tar.extractall(path=install_dir)
- except AttributeError:
- _extractall(tar, path=install_dir)
- if ifile.pkgname in self._installed:
- self._installed[ifile.pkgname].add_files(
- ifile.url,
- tar.getnames())
- self._installed[ifile.pkgname].set_md5sum(
- ifile.url,
- ifile.md5sum)
- else:
- # *HACK: this understands the installed package syntax.
- definition = { ifile.url :
- {'files': tar.getnames(),
- 'md5sum' : ifile.md5sum } }
- self._installed[ifile.pkgname] = InstalledPackage(definition)
- self._installed_changed = True
-
- def install(self, installables, platform, install_dir, cache_dir):
- """@brief Do the installation for for the platform.
- @param installables The requested installables to install.
- @param platform The target platform. Eg, windows or linux/i686/gcc/3.3
- @param install_dir The root directory to install into. Created
- if missing.
- @param cache_dir The directory to cache downloads. Created if
- missing.
- """
- # The ordering of steps in the method is to help reduce the
- # likelihood that we break something.
- install_dir = os.path.realpath(install_dir)
- cache_dir = os.path.realpath(cache_dir)
- _mkdir(install_dir)
- _mkdir(cache_dir)
- to_install = self._build_ifiles(platform, cache_dir)
-
- # Filter for files which we actually requested to install.
- to_install = [ifl for ifl in to_install if ifl.pkgname in installables]
- for ifile in to_install:
- ifile.fetch_local()
- self._install(to_install, install_dir)
-
- def do_install(self, installables, platform, install_dir, cache_dir=None,
- check_license=True, scp=None):
- """Determine what installables should be installed. If they were
- passed in on the command line, use them, otherwise install
- all known installables.
- """
- if not cache_dir:
- cache_dir = _default_installable_cache()
- all_installables = self.list_installables()
- if not len(installables):
- install_installables = all_installables
- else:
- # passed in on the command line. We'll need to verify we
- # know about them here.
- install_installables = installables
- for installable in install_installables:
- if installable not in all_installables:
- raise RuntimeError('Unknown installable: %s' %
- (installable,))
- if check_license:
- # *TODO: check against a list of 'known good' licenses.
- # *TODO: check for urls which conflict -- will lead to
- # problems.
- for installable in install_installables:
- if not self.is_valid_license(installable):
- return 1
-
- # Set up the 'scp' handler
- opener = urllib2.build_opener()
- scp_or_http = SCPOrHTTPHandler(scp)
- opener.add_handler(scp_or_http)
- urllib2.install_opener(opener)
-
- # Do the work of installing the requested installables.
- self.install(
- install_installables,
- platform,
- install_dir,
- cache_dir)
- scp_or_http.cleanup()
-
- # Verify that requested packages are installed
- for pkg in installables:
- if pkg not in self._installed:
- raise RuntimeError("No '%s' available for '%s'." %
- (pkg, platform))
-
- def do_uninstall(self, installables, install_dir):
- # Do not bother to check license if we're uninstalling.
- all_installed = self.list_installed()
- if not len(installables):
- uninstall_installables = all_installed
- else:
- # passed in on the command line. We'll need to verify we
- # know about them here.
- uninstall_installables = installables
- for installable in uninstall_installables:
- if installable not in all_installed:
- raise RuntimeError('Installable not installed: %s' %
- (installable,))
- self.uninstall(uninstall_installables, install_dir)
-
-class SCPOrHTTPHandler(urllib2.BaseHandler):
- """Evil hack to allow both the build system and developers consume
- proprietary binaries.
- To use http, export the environment variable:
- INSTALL_USE_HTTP_FOR_SCP=true
- """
- def __init__(self, scp_binary):
- self._scp = scp_binary
- self._dir = None
-
- def scp_open(self, request):
- #scp:codex.lindenlab.com:/local/share/install_pkgs/package.tar.bz2
- remote = request.get_full_url()[4:]
- if os.getenv('INSTALL_USE_HTTP_FOR_SCP', None) == 'true':
- return self.do_http(remote)
- try:
- return self.do_scp(remote)
- except:
- self.cleanup()
- raise
-
- def do_http(self, remote):
- url = remote.split(':',1)
- if not url[1].startswith('/'):
- # in case it's in a homedir or something
- url.insert(1, '/')
- url.insert(0, "http://")
- url = ''.join(url)
- print "Using HTTP:",url
- request = urllib2.Request(url)
-
- if re.match("/^http:\/\/github.com/", self.url):
- request.add_header('User-agent', defaultUserAgent)
-
- return urllib2.urlopen(request)
-
- def do_scp(self, remote):
- if not self._dir:
- self._dir = tempfile.mkdtemp()
- local = os.path.join(self._dir, remote.split('/')[-1:][0])
- command = []
- for part in (self._scp, remote, local):
- if ' ' in part:
- # I hate shell escaping.
- part.replace('\\', '\\\\')
- part.replace('"', '\\"')
- command.append('"%s"' % part)
- else:
- command.append(part)
- #print "forking:", command
- rv = os.system(' '.join(command))
- if rv != 0:
- raise RuntimeError("Cannot fetch: %s" % remote)
- return file(local, 'rb')
-
- def cleanup(self):
- if self._dir:
- shutil.rmtree(self._dir)
-
-
-#
-# *NOTE: PULLED FROM PYTHON 2.5 tarfile.py Phoenix 2008-01-28
-#
-def _extractall(tar, path=".", members=None):
- """Extract all members from the archive to the current working
- directory and set owner, modification time and permissions on
- directories afterwards. `path' specifies a different directory
- to extract to. `members' is optional and must be a subset of the
- list returned by getmembers().
- """
- directories = []
-
- if members is None:
- members = tar
-
- for tarinfo in members:
- if tarinfo.isdir():
- # Extract directory with a safe mode, so that
- # all files below can be extracted as well.
- try:
- os.makedirs(os.path.join(path, tarinfo.name), 0777)
- except EnvironmentError:
- pass
- directories.append(tarinfo)
- else:
- tar.extract(tarinfo, path)
-
- # Reverse sort directories.
- directories.sort(lambda a, b: cmp(a.name, b.name))
- directories.reverse()
-
- # Set correct owner, mtime and filemode on directories.
- for tarinfo in directories:
- path = os.path.join(path, tarinfo.name)
- try:
- tar.chown(tarinfo, path)
- tar.utime(tarinfo, path)
- tar.chmod(tarinfo, path)
- except tarfile.ExtractError, e:
- if tar.errorlevel > 1:
- raise
- else:
- tar._dbg(1, "tarfile: %s" % e)
-
-
-def _mkdir(directory):
- "Safe, repeatable way to make a directory."
- if not os.path.exists(directory):
- os.makedirs(directory)
-
-def _get_platform():
- "Return appropriate platform packages for the environment."
- platform_map = {
- 'darwin': 'darwin',
- 'linux2': 'linux',
- 'win32' : 'windows',
- 'cygwin' : 'windows',
- 'solaris' : 'solaris'
- }
- this_platform = platform_map[sys.platform]
- if this_platform == 'linux':
- if platform.architecture()[0] == '64bit':
- # TODO -- someday when install.py accepts a platform of the form
- # os/arch/compiler/compiler_version then we can replace the
- # 'linux64' platform with 'linux/x86_64/gcc/4.1'
- this_platform = 'linux'
- return this_platform
-
-def _getuser():
- "Get the user"
- try:
- # Unix-only.
- import getpass
- return getpass.getuser()
- except ImportError:
- import win32api
- return win32api.GetUserName()
-
-def _default_installable_cache():
- """In general, the installable files do not change much, so find a
- host/user specific location to cache files."""
- user = _getuser()
- cache_dir = "/var/tmp/%s/install.cache" % user
- if _get_platform() == 'windows':
- cache_dir = os.path.join(tempfile.gettempdir(), \
- 'install.cache.%s' % user)
- return cache_dir
-
-def parse_args():
- parser = optparse.OptionParser(
- usage="usage: %prog [options] [installable1 [installable2...]]",
- formatter = helpformatter.Formatter(),
- description="""This script fetches and installs installable packages.
-It also handles uninstalling those packages and manages the mapping between
-packages and their license.
-
-The process is to open and read an install manifest file which specifies
-what files should be installed. For each installable to be installed.
- * make sure it has a license
- * check the installed version
- ** if not installed and needs to be, download and install
- ** if installed version differs, download & install
-
-If no installables are specified on the command line, then the defaut
-behavior is to install all known installables appropriate for the platform
-specified or uninstall all installables if --uninstall is set. You can specify
-more than one installable on the command line.
-
-When specifying a platform, you can specify 'all' to install all
-packages, or any platform of the form:
-
-OS[/arch[/compiler[/compiler_version]]]
-
-Where the supported values for each are:
-OS: darwin, linux, windows, solaris
-arch: i686, x86_64, ppc, universal
-compiler: vs, gcc
-compiler_version: 2003, 2005, 2008, 3.3, 3.4, 4.0, etc.
-
-No checks are made to ensure a valid combination of platform
-parts. Some exmples of valid platforms:
-
-windows
-windows/i686/vs/2005
-linux/x86_64/gcc/3.3
-linux/x86_64/gcc/4.0
-darwin/universal/gcc/4.0
-""")
- parser.add_option(
- '--dry-run',
- action='store_true',
- default=False,
- dest='dryrun',
- help='Do not actually install files. Downloads will still happen.')
- parser.add_option(
- '--install-manifest',
- type='string',
- default=os.path.join(base_dir, 'install.xml'),
- dest='install_filename',
- help='The file used to describe what should be installed.')
- parser.add_option(
- '--installed-manifest',
- type='string',
- default=os.path.join(base_dir, 'installed.xml'),
- dest='installed_filename',
- help='The file used to record what is installed.')
- parser.add_option(
- '--export-manifest',
- action='store_true',
- default=False,
- dest='export_manifest',
- help="Print the install manifest to stdout and exit.")
- parser.add_option(
- '-p', '--platform',
- type='string',
- default=_get_platform(),
- dest='platform',
- help="""Override the automatically determined platform. \
-You can specify 'all' to do a installation of installables for all platforms.""")
- parser.add_option(
- '--cache-dir',
- type='string',
- default=_default_installable_cache(),
- dest='cache_dir',
- help='Where to download files. Default: %s'% \
- (_default_installable_cache()))
- parser.add_option(
- '--install-dir',
- type='string',
- default=base_dir,
- dest='install_dir',
- help='Where to unpack the installed files.')
- parser.add_option(
- '--list-installed',
- action='store_true',
- default=False,
- dest='list_installed',
- help="List the installed package names and exit.")
- parser.add_option(
- '--skip-license-check',
- action='store_false',
- default=True,
- dest='check_license',
- help="Do not perform the license check.")
- parser.add_option(
- '--list-licenses',
- action='store_true',
- default=False,
- dest='list_licenses',
- help="List known licenses and exit.")
- parser.add_option(
- '--detail-license',
- type='string',
- default=None,
- dest='detail_license',
- help="Get detailed information on specified license and exit.")
- parser.add_option(
- '--add-license',
- type='string',
- default=None,
- dest='new_license',
- help="""Add a license to the install file. Argument is the name of \
-license. Specify --license-url if the license is remote or specify \
---license-text, otherwse the license text will be read from standard \
-input.""")
- parser.add_option(
- '--license-url',
- type='string',
- default=None,
- dest='license_url',
- help="""Put the specified url into an added license. \
-Ignored if --add-license is not specified.""")
- parser.add_option(
- '--license-text',
- type='string',
- default=None,
- dest='license_text',
- help="""Put the text into an added license. \
-Ignored if --add-license is not specified.""")
- parser.add_option(
- '--remove-license',
- type='string',
- default=None,
- dest='remove_license',
- help="Remove a named license.")
- parser.add_option(
- '--remove-installable',
- type='string',
- default=None,
- dest='remove_installable',
- help="Remove a installable from the install file.")
- parser.add_option(
- '--add-installable',
- type='string',
- default=None,
- dest='add_installable',
- help="""Add a installable into the install file. Argument is \
-the name of the installable to add.""")
- parser.add_option(
- '--add-installable-metadata',
- type='string',
- default=None,
- dest='add_installable_metadata',
- help="""Add package for library into the install file. Argument is \
-the name of the library to add.""")
- parser.add_option(
- '--installable-copyright',
- type='string',
- default=None,
- dest='installable_copyright',
- help="""Copyright for specified new package. Ignored if \
---add-installable is not specified.""")
- parser.add_option(
- '--installable-license',
- type='string',
- default=None,
- dest='installable_license',
- help="""Name of license for specified new package. Ignored if \
---add-installable is not specified.""")
- parser.add_option(
- '--installable-description',
- type='string',
- default=None,
- dest='installable_description',
- help="""Description for specified new package. Ignored if \
---add-installable is not specified.""")
- parser.add_option(
- '--add-installable-package',
- type='string',
- default=None,
- dest='add_installable_package',
- help="""Add package for library into the install file. Argument is \
-the name of the library to add.""")
- parser.add_option(
- '--package-platform',
- type='string',
- default=None,
- dest='package_platform',
- help="""Platform for specified new package. \
-Ignored if --add-installable or --add-installable-package is not specified.""")
- parser.add_option(
- '--package-url',
- type='string',
- default=None,
- dest='package_url',
- help="""URL for specified package. \
-Ignored if --add-installable or --add-installable-package is not specified.""")
- parser.add_option(
- '--package-md5',
- type='string',
- default=None,
- dest='package_md5',
- help="""md5sum for new package. \
-Ignored if --add-installable or --add-installable-package is not specified.""")
- parser.add_option(
- '--list',
- action='store_true',
- default=False,
- dest='list_installables',
- help="List the installables in the install manifest and exit.")
- parser.add_option(
- '--detail',
- type='string',
- default=None,
- dest='detail_installable',
- help="Get detailed information on specified installable and exit.")
- parser.add_option(
- '--detail-installed',
- type='string',
- default=None,
- dest='detail_installed',
- help="Get list of files for specified installed installable and exit.")
- parser.add_option(
- '--uninstall',
- action='store_true',
- default=False,
- dest='uninstall',
- help="""Remove the installables specified in the arguments. Just like \
-during installation, if no installables are listed then all installed \
-installables are removed.""")
- parser.add_option(
- '--scp',
- type='string',
- default='scp',
- dest='scp',
- help="Specify the path to your scp program.")
-
- return parser.parse_args()
-
-def main():
- options, args = parse_args()
- installer = Installer(
- options.install_filename,
- options.installed_filename,
- options.dryrun)
-
- #
- # Handle the queries for information
- #
- if options.list_installed:
- print "installed list:", installer.list_installed()
- return 0
- if options.list_installables:
- print "installable list:", installer.list_installables()
- return 0
- if options.detail_installable:
- try:
- detail = installer.detail_installable(options.detail_installable)
- print "Detail on installable",options.detail_installable+":"
- pprint.pprint(detail)
- except KeyError:
- print "Installable '"+options.detail_installable+"' not found in",
- print "install file."
- return 0
- if options.detail_installed:
- try:
- detail = installer.detail_installed(options.detail_installed)
- #print "Detail on installed",options.detail_installed+":"
- for line in detail:
- print line
- except:
- raise
- print "Installable '"+options.detail_installed+"' not found in ",
- print "install file."
- return 0
- if options.list_licenses:
- print "license list:", installer.list_licenses()
- return 0
- if options.detail_license:
- try:
- detail = installer.detail_license(options.detail_license)
- print "Detail on license",options.detail_license+":"
- pprint.pprint(detail)
- except KeyError:
- print "License '"+options.detail_license+"' not defined in",
- print "install file."
- return 0
- if options.export_manifest:
- # *HACK: just re-parse the install manifest and pretty print
- # it. easier than looking at the datastructure designed for
- # actually determining what to install
- install = llsd.parse(file(options.install_filename, 'rb').read())
- pprint.pprint(install)
- return 0
-
- #
- # Handle updates -- can only do one of these
- # *TODO: should this change the command line syntax?
- #
- if options.new_license:
- if not installer.add_license(
- options.new_license,
- text=options.license_text,
- url=options.license_url):
- return 1
- elif options.remove_license:
- installer.remove_license(options.remove_license)
- elif options.remove_installable:
- installer.remove_installable(options.remove_installable)
- elif options.add_installable:
- if not installer.add_installable(
- options.add_installable,
- copyright=options.installable_copyright,
- license=options.installable_license,
- description=options.installable_description,
- platform=options.package_platform,
- url=options.package_url,
- md5sum=options.package_md5):
- return 1
- elif options.add_installable_metadata:
- if not installer.add_installable_metadata(
- options.add_installable_metadata,
- copyright=options.installable_copyright,
- license=options.installable_license,
- description=options.installable_description):
- return 1
- elif options.add_installable_package:
- if not installer.add_installable_package(
- options.add_installable_package,
- platform=options.package_platform,
- url=options.package_url,
- md5sum=options.package_md5):
- return 1
- elif options.uninstall:
- installer.do_uninstall(args, options.install_dir)
- else:
- installer.do_install(args, options.platform, options.install_dir,
- options.cache_dir, options.check_license,
- options.scp)
-
- # save out any changes
- installer.save()
- return 0
-
-if __name__ == '__main__':
- #print sys.argv
- sys.exit(main())
+#!/usr/bin/env python
+"""\
+@file install.py
+@author Phoenix
+@date 2008-01-27
+@brief Install files into an indra checkout.
+
+Install files as specified by:
+https://wiki.lindenlab.com/wiki/User:Phoenix/Library_Installation
+
+
+$LicenseInfo:firstyear=2007&license=mit$
+
+Copyright (c) 2007-2009, Linden Research, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+$/LicenseInfo$
+"""
+
+import sys
+import os.path
+import re
+
+# Look for indra/lib/python in all possible parent directories ...
+# This is an improvement over the setup-path.py method used previously:
+# * the script may blocated anywhere inside the source tree
+# * it doesn't depend on the current directory
+# * it doesn't depend on another file being present.
+
+def add_indra_lib_path():
+ root = os.path.realpath(__file__)
+ # always insert the directory of the script in the search path
+ dir = os.path.dirname(root)
+ if dir not in sys.path:
+ sys.path.insert(0, dir)
+
+ # Now go look for indra/lib/python in the parent dies
+ while root != os.path.sep:
+ root = os.path.dirname(root)
+ dir = os.path.join(root, 'indra', 'lib', 'python')
+ if os.path.isdir(dir):
+ if dir not in sys.path:
+ sys.path.insert(0, dir)
+ return root
+ else:
+ print >>sys.stderr, "This script is not inside a valid installation."
+ sys.exit(1)
+
+base_dir = add_indra_lib_path()
+defaultUserAgent = 'Lynx/2.8.6rel.5 libwww-FM/2.14' #pretend to be lynx because github sucks a fat dick
+
+import copy
+import optparse
+import os
+import platform
+import pprint
+import shutil
+import tarfile
+import tempfile
+import urllib2
+import urlparse
+
+from indra.base import llsd
+from indra.util import helpformatter
+
+# *HACK: Necessary for python 2.4. Consider replacing this code wart
+# after python >=2.5 has deployed everywhere. 2009-10-05
+try:
+ from hashlib import md5
+except ImportError:
+ from md5 import md5
+
+class InstallFile(object):
+ "This is just a handy way to throw around details on a file in memory."
+ def __init__(self, pkgname, url, md5sum, cache_dir, platform_path):
+ self.pkgname = pkgname
+ self.url = url
+ self.md5sum = md5sum
+ filename = urlparse.urlparse(url)[2].split('/')[-1]
+ self.filename = os.path.join(cache_dir, filename)
+ self.platform_path = platform_path
+
+ def __str__(self):
+ return "ifile{%s:%s}" % (self.pkgname, self.url)
+
+ def _is_md5sum_match(self):
+ hasher = md5(file(self.filename, 'rb').read())
+ if hasher.hexdigest() == self.md5sum:
+ return True
+ return False
+
+ def is_match(self, platform):
+ """@brief Test to see if this ifile is part of platform
+ @param platform The target platform. Eg, windows or linux/i686/gcc/3.3
+ @return Returns True if the ifile is in the platform.
+ """
+ if self.platform_path[0] == 'common':
+ return True
+ req_platform_path = platform.split('/')
+ #print "platform:",req_platform_path
+ #print "path:",self.platform_path
+ # to match, every path part much match
+ match_count = min(len(req_platform_path), len(self.platform_path))
+ for ii in range(0, match_count):
+ if req_platform_path[ii] != self.platform_path[ii]:
+ return False
+ #print "match!"
+ return True
+
+ def fetch_local(self):
+ #print "Looking for:",self.filename
+ if not os.path.exists(self.filename):
+ pass
+ elif self.md5sum and not self._is_md5sum_match():
+ print "md5 mismatch:", self.filename
+ os.remove(self.filename)
+ else:
+ print "Found matching package:", self.filename
+ return
+ print "Downloading",self.url,"to local file",self.filename
+
+ request = urllib2.Request(self.url)
+
+ if re.match("/^http:\/\/github.com/", self.url):
+ request.add_header('User-agent', defaultUserAgent)
+
+ file(self.filename, 'wb').write(urllib2.urlopen(request).read())
+ if self.md5sum and not self._is_md5sum_match():
+ raise RuntimeError("Error matching md5 for %s" % self.url)
+
+class LicenseDefinition(object):
+ def __init__(self, definition):
+ #probably looks like:
+ # { text : ...,
+ # url : ...
+ # blessed : ...
+ # }
+ self._definition = definition
+
+
+class InstallableDefinition(object):
+ def __init__(self, definition):
+ #probably looks like:
+ # { packages : {platform...},
+ # copyright : ...
+ # license : ...
+ # description: ...
+ # }
+ self._definition = definition
+
+ def _ifiles_from(self, tree, pkgname, cache_dir):
+ return self._ifiles_from_path(tree, pkgname, cache_dir, [])
+
+ def _ifiles_from_path(self, tree, pkgname, cache_dir, path):
+ ifiles = []
+ if 'url' in tree:
+ ifiles.append(InstallFile(
+ pkgname,
+ tree['url'],
+ tree.get('md5sum', None),
+ cache_dir,
+ path))
+ else:
+ for key in tree:
+ platform_path = copy.copy(path)
+ platform_path.append(key)
+ ifiles.extend(
+ self._ifiles_from_path(
+ tree[key],
+ pkgname,
+ cache_dir,
+ platform_path))
+ return ifiles
+
+ def ifiles(self, pkgname, platform, cache_dir):
+ """@brief return a list of appropriate InstallFile instances to install
+ @param pkgname The name of the package to be installed, eg 'tut'
+ @param platform The target platform. Eg, windows or linux/i686/gcc/3.3
+ @param cache_dir The directory to cache downloads.
+ @return Returns a list of InstallFiles which are part of this install
+ """
+ if 'packages' not in self._definition:
+ return []
+ all_ifiles = self._ifiles_from(
+ self._definition['packages'],
+ pkgname,
+ cache_dir)
+ if platform == 'all':
+ return all_ifiles
+ #print "Considering", len(all_ifiles), "packages for", pkgname
+ # split into 2 lines because pychecker thinks it might return none.
+ files = [ifile for ifile in all_ifiles if ifile.is_match(platform)]
+ return files
+
+class InstalledPackage(object):
+ def __init__(self, definition):
+ # looks like:
+ # { url1 : { files: [file1,file2,...], md5sum:... },
+ # url2 : { files: [file1,file2,...], md5sum:... },...
+ # }
+ self._installed = {}
+ for url in definition:
+ self._installed[url] = definition[url]
+
+ def urls(self):
+ return self._installed.keys()
+
+ def files_in(self, url):
+ return self._installed[url].get('files', [])
+
+ def get_md5sum(self, url):
+ return self._installed[url].get('md5sum', None)
+
+ def remove(self, url):
+ self._installed.pop(url)
+
+ def add_files(self, url, files):
+ if url not in self._installed:
+ self._installed[url] = {}
+ self._installed[url]['files'] = files
+
+ def set_md5sum(self, url, md5sum):
+ if url not in self._installed:
+ self._installed[url] = {}
+ self._installed[url]['md5sum'] = md5sum
+
+class Installer(object):
+ def __init__(self, install_filename, installed_filename, dryrun):
+ self._install_filename = install_filename
+ self._install_changed = False
+ self._installed_filename = installed_filename
+ self._installed_changed = False
+ self._dryrun = dryrun
+ self._installables = {}
+ self._licenses = {}
+ self._installed = {}
+ self.load()
+
+ def load(self):
+ if os.path.exists(self._install_filename):
+ install = llsd.parse(file(self._install_filename, 'rb').read())
+ try:
+ for name in install['installables']:
+ self._installables[name] = InstallableDefinition(
+ install['installables'][name])
+ except KeyError:
+ pass
+ try:
+ for name in install['licenses']:
+ self._licenses[name] = LicenseDefinition(install['licenses'][name])
+ except KeyError:
+ pass
+ if os.path.exists(self._installed_filename):
+ installed = llsd.parse(file(self._installed_filename, 'rb').read())
+ try:
+ bins = installed['installables']
+ for name in bins:
+ self._installed[name] = InstalledPackage(bins[name])
+ except KeyError:
+ pass
+
+ def _write(self, filename, state):
+ print "Writing state to",filename
+ if not self._dryrun:
+ file(filename, 'wb').write(llsd.format_pretty_xml(state))
+
+ def save(self):
+ if self._install_changed:
+ state = {}
+ state['licenses'] = {}
+ for name in self._licenses:
+ state['licenses'][name] = self._licenses[name]._definition
+ #print "self._installables:",self._installables
+ state['installables'] = {}
+ for name in self._installables:
+ state['installables'][name] = \
+ self._installables[name]._definition
+ self._write(self._install_filename, state)
+ if self._installed_changed:
+ state = {}
+ state['installables'] = {}
+ bin = state['installables']
+ for name in self._installed:
+ #print "installed:",name,self._installed[name]._installed
+ bin[name] = self._installed[name]._installed
+ self._write(self._installed_filename, state)
+
+ def is_valid_license(self, bin):
+ "@brief retrun true if we have valid license info for installable."
+ installable = self._installables[bin]._definition
+ if 'license' not in installable:
+ print >>sys.stderr, "No license info found for", bin
+ print >>sys.stderr, 'Please add the license with the',
+ print >>sys.stderr, '--add-installable option. See', \
+ sys.argv[0], '--help'
+ return False
+ if installable['license'] not in self._licenses:
+ lic = installable['license']
+ print >>sys.stderr, "Missing license info for '" + lic + "'.",
+ print >>sys.stderr, 'Please add the license with the',
+ print >>sys.stderr, '--add-license option. See', sys.argv[0],
+ print >>sys.stderr, '--help'
+ return False
+ return True
+
+ def list_installables(self):
+ "Return a list of all known installables."
+ return sorted(self._installables.keys())
+
+ def detail_installable(self, name):
+ "Return a installable definition detail"
+ return self._installables[name]._definition
+
+ def list_licenses(self):
+ "Return a list of all known licenses."
+ return sorted(self._licenses.keys())
+
+ def detail_license(self, name):
+ "Return a license definition detail"
+ return self._licenses[name]._definition
+
+ def list_installed(self):
+ "Return a list of installed packages."
+ return sorted(self._installed.keys())
+
+ def detail_installed(self, name):
+ "Return file list for specific installed package."
+ filelist = []
+ for url in self._installed[name]._installed.keys():
+ filelist.extend(self._installed[name].files_in(url))
+ return filelist
+
+ def _update_field(self, description, field, value, multiline=False):
+ """Given a block and a field name, add or update it.
+ @param description a dict containing all the details of a description.
+ @param field the name of the field to update.
+ @param value the value of the field to update; if omitted, interview
+ will ask for value.
+ @param multiline boolean specifying whether field is multiline or not.
+ """
+ if value:
+ description[field] = value
+ else:
+ if field in description:
+ print "Update value for '" + field + "'"
+ print "(Leave blank to keep current value)"
+ print "Current Value: '" + description[field] + "'"
+ else:
+ print "Specify value for '" + field + "'"
+ if not multiline:
+ new_value = raw_input("Enter New Value: ")
+ else:
+ print "Please enter " + field + ". End input with EOF (^D)."
+ new_value = sys.stdin.read()
+
+ if field in description and not new_value:
+ pass
+ elif new_value:
+ description[field] = new_value
+
+ self._install_changed = True
+ return True
+
+ def _update_installable(self, name, platform, url, md5sum):
+ """Update installable entry with specific package information.
+ @param installable[in,out] a dict containing installable details.
+ @param platform Platform info, i.e. linux/i686, windows/i686 etc.
+ @param url URL of tar file
+ @param md5sum md5sum of tar file
+ """
+ installable = self._installables[name]._definition
+ path = platform.split('/')
+ if 'packages' not in installable:
+ installable['packages'] = {}
+ update = installable['packages']
+ for child in path:
+ if child not in update:
+ update[child] = {}
+ parent = update
+ update = update[child]
+ parent[child]['url'] = llsd.uri(url)
+ parent[child]['md5sum'] = md5sum
+
+ self._install_changed = True
+ return True
+
+
+ def add_installable_package(self, name, **kwargs):
+ """Add an url for a platform path to the installable.
+ @param installable[in,out] a dict containing installable details.
+ """
+ platform_help_str = """\
+Please enter a new package location and url. Some examples:
+common -- specify a package for all platforms
+linux -- specify a package for all arch and compilers on linux
+darwin/universal -- specify a mac os x universal
+windows/i686/vs/2003 -- specify a windows visual studio 2003 package"""
+ if name not in self._installables:
+ print "Error: must add library with --add-installable or " \
+ +"--add-installable-metadata before using " \
+ +"--add-installable-package option"
+ return False
+ else:
+ print "Updating installable '" + name + "'."
+ for arg in ('platform', 'url', 'md5sum'):
+ if not kwargs[arg]:
+ if arg == 'platform':
+ print platform_help_str
+ kwargs[arg] = raw_input("Package "+arg+":")
+ #path = kwargs['platform'].split('/')
+
+ return self._update_installable(name, kwargs['platform'],
+ kwargs['url'], kwargs['md5sum'])
+
+ def add_installable_metadata(self, name, **kwargs):
+ """Interactively add (only) library metadata into install,
+ w/o adding installable"""
+ if name not in self._installables:
+ print "Adding installable '" + name + "'."
+ self._installables[name] = InstallableDefinition({})
+ else:
+ print "Updating installable '" + name + "'."
+ installable = self._installables[name]._definition
+ for field in ('copyright', 'license', 'description'):
+ self._update_field(installable, field, kwargs[field])
+ print "Added installable '" + name + "':"
+ pprint.pprint(self._installables[name])
+
+ return True
+
+ def add_installable(self, name, **kwargs):
+ "Interactively pull a new installable into the install"
+ ret_a = self.add_installable_metadata(name, **kwargs)
+ ret_b = self.add_installable_package(name, **kwargs)
+ return (ret_a and ret_b)
+
+ def remove_installable(self, name):
+ self._installables.pop(name)
+ self._install_changed = True
+
+ def add_license(self, name, **kwargs):
+ if name not in self._licenses:
+ print "Adding license '" + name + "'."
+ self._licenses[name] = LicenseDefinition({})
+ else:
+ print "Updating license '" + name + "'."
+ the_license = self._licenses[name]._definition
+ for field in ('url', 'text'):
+ multiline = False
+ if field == 'text':
+ multiline = True
+ self._update_field(the_license, field, kwargs[field], multiline)
+ self._install_changed = True
+ return True
+
+ def remove_license(self, name):
+ self._licenses.pop(name)
+ self._install_changed = True
+
+ def _uninstall(self, installables):
+ """@brief Do the actual removal of files work.
+ *NOTE: This method is not transactionally safe -- ie, if it
+ raises an exception, internal state may be inconsistent. How
+ should we address this?
+ @param installables The package names to remove
+ """
+ remove_file_list = []
+ for pkgname in installables:
+ for url in self._installed[pkgname].urls():
+ remove_file_list.extend(
+ self._installed[pkgname].files_in(url))
+ self._installed[pkgname].remove(url)
+ if not self._dryrun:
+ self._installed_changed = True
+ if not self._dryrun:
+ self._installed.pop(pkgname)
+ remove_dir_set = set()
+ for filename in remove_file_list:
+ print "rm",filename
+ if not self._dryrun:
+ if os.path.exists(filename):
+ remove_dir_set.add(os.path.dirname(filename))
+ try:
+ os.remove(filename)
+ except OSError:
+ # This is just for cleanup, so we don't care
+ # about normal failures.
+ pass
+ for dirname in remove_dir_set:
+ try:
+ os.removedirs(dirname)
+ except OSError:
+ # This is just for cleanup, so we don't care about
+ # normal failures.
+ pass
+
+ def uninstall(self, installables, install_dir):
+ """@brief Remove the packages specified.
+ @param installables The package names to remove
+ @param install_dir The directory to work from
+ """
+ print "uninstall",installables,"from",install_dir
+ cwd = os.getcwdu()
+ os.chdir(install_dir)
+ try:
+ self._uninstall(installables)
+ finally:
+ os.chdir(cwd)
+
+ def _build_ifiles(self, platform, cache_dir):
+ """@brief determine what files to install
+ @param platform The target platform. Eg, windows or linux/i686/gcc/3.3
+ @param cache_dir The directory to cache downloads.
+ @return Returns the ifiles to install
+ """
+ ifiles = []
+ for bin in self._installables:
+ ifiles.extend(self._installables[bin].ifiles(bin,
+ platform,
+ cache_dir))
+ to_install = []
+ #print "self._installed",self._installed
+ for ifile in ifiles:
+ if ifile.pkgname not in self._installed:
+ to_install.append(ifile)
+ elif ifile.url not in self._installed[ifile.pkgname].urls():
+ to_install.append(ifile)
+ elif ifile.md5sum != \
+ self._installed[ifile.pkgname].get_md5sum(ifile.url):
+ # *TODO: We may want to uninstall the old version too
+ # when we detect it is installed, but the md5 sum is
+ # different.
+ to_install.append(ifile)
+ else:
+ #print "Installation up to date:",
+ # ifile.pkgname,ifile.platform_path
+ pass
+ #print "to_install",to_install
+ return to_install
+
+ def _install(self, to_install, install_dir):
+ for ifile in to_install:
+ tar = tarfile.open(ifile.filename, 'r')
+ print "Extracting",ifile.filename,"to",install_dir
+ if not self._dryrun:
+ # *NOTE: try to call extractall, which first appears
+ # in python 2.5. Phoenix 2008-01-28
+ try:
+ tar.extractall(path=install_dir)
+ except AttributeError:
+ _extractall(tar, path=install_dir)
+ if ifile.pkgname in self._installed:
+ self._installed[ifile.pkgname].add_files(
+ ifile.url,
+ tar.getnames())
+ self._installed[ifile.pkgname].set_md5sum(
+ ifile.url,
+ ifile.md5sum)
+ else:
+ # *HACK: this understands the installed package syntax.
+ definition = { ifile.url :
+ {'files': tar.getnames(),
+ 'md5sum' : ifile.md5sum } }
+ self._installed[ifile.pkgname] = InstalledPackage(definition)
+ self._installed_changed = True
+
+ def install(self, installables, platform, install_dir, cache_dir):
+ """@brief Do the installation for for the platform.
+ @param installables The requested installables to install.
+ @param platform The target platform. Eg, windows or linux/i686/gcc/3.3
+ @param install_dir The root directory to install into. Created
+ if missing.
+ @param cache_dir The directory to cache downloads. Created if
+ missing.
+ """
+ # The ordering of steps in the method is to help reduce the
+ # likelihood that we break something.
+ install_dir = os.path.realpath(install_dir)
+ cache_dir = os.path.realpath(cache_dir)
+ _mkdir(install_dir)
+ _mkdir(cache_dir)
+ to_install = self._build_ifiles(platform, cache_dir)
+
+ # Filter for files which we actually requested to install.
+ to_install = [ifl for ifl in to_install if ifl.pkgname in installables]
+ for ifile in to_install:
+ ifile.fetch_local()
+ self._install(to_install, install_dir)
+
+ def do_install(self, installables, platform, install_dir, cache_dir=None,
+ check_license=True, scp=None):
+ """Determine what installables should be installed. If they were
+ passed in on the command line, use them, otherwise install
+ all known installables.
+ """
+ if not cache_dir:
+ cache_dir = _default_installable_cache()
+ all_installables = self.list_installables()
+ if not len(installables):
+ install_installables = all_installables
+ else:
+ # passed in on the command line. We'll need to verify we
+ # know about them here.
+ install_installables = installables
+ for installable in install_installables:
+ if installable not in all_installables:
+ raise RuntimeError('Unknown installable: %s' %
+ (installable,))
+ if check_license:
+ # *TODO: check against a list of 'known good' licenses.
+ # *TODO: check for urls which conflict -- will lead to
+ # problems.
+ for installable in install_installables:
+ if not self.is_valid_license(installable):
+ return 1
+
+ # Set up the 'scp' handler
+ opener = urllib2.build_opener()
+ scp_or_http = SCPOrHTTPHandler(scp)
+ opener.add_handler(scp_or_http)
+ urllib2.install_opener(opener)
+
+ # Do the work of installing the requested installables.
+ self.install(
+ install_installables,
+ platform,
+ install_dir,
+ cache_dir)
+ scp_or_http.cleanup()
+
+ # Verify that requested packages are installed
+ for pkg in installables:
+ if pkg not in self._installed:
+ raise RuntimeError("No '%s' available for '%s'." %
+ (pkg, platform))
+
+ def do_uninstall(self, installables, install_dir):
+ # Do not bother to check license if we're uninstalling.
+ all_installed = self.list_installed()
+ if not len(installables):
+ uninstall_installables = all_installed
+ else:
+ # passed in on the command line. We'll need to verify we
+ # know about them here.
+ uninstall_installables = installables
+ for installable in uninstall_installables:
+ if installable not in all_installed:
+ raise RuntimeError('Installable not installed: %s' %
+ (installable,))
+ self.uninstall(uninstall_installables, install_dir)
+
+class SCPOrHTTPHandler(urllib2.BaseHandler):
+ """Evil hack to allow both the build system and developers consume
+ proprietary binaries.
+ To use http, export the environment variable:
+ INSTALL_USE_HTTP_FOR_SCP=true
+ """
+ def __init__(self, scp_binary):
+ self._scp = scp_binary
+ self._dir = None
+
+ def scp_open(self, request):
+ #scp:codex.lindenlab.com:/local/share/install_pkgs/package.tar.bz2
+ remote = request.get_full_url()[4:]
+ if os.getenv('INSTALL_USE_HTTP_FOR_SCP', None) == 'true':
+ return self.do_http(remote)
+ try:
+ return self.do_scp(remote)
+ except:
+ self.cleanup()
+ raise
+
+ def do_http(self, remote):
+ url = remote.split(':',1)
+ if not url[1].startswith('/'):
+ # in case it's in a homedir or something
+ url.insert(1, '/')
+ url.insert(0, "http://")
+ url = ''.join(url)
+ print "Using HTTP:",url
+ request = urllib2.Request(url)
+
+ if re.match("/^http:\/\/github.com/", self.url):
+ request.add_header('User-agent', defaultUserAgent)
+
+ return urllib2.urlopen(request)
+
+ def do_scp(self, remote):
+ if not self._dir:
+ self._dir = tempfile.mkdtemp()
+ local = os.path.join(self._dir, remote.split('/')[-1:][0])
+ command = []
+ for part in (self._scp, remote, local):
+ if ' ' in part:
+ # I hate shell escaping.
+ part.replace('\\', '\\\\')
+ part.replace('"', '\\"')
+ command.append('"%s"' % part)
+ else:
+ command.append(part)
+ #print "forking:", command
+ rv = os.system(' '.join(command))
+ if rv != 0:
+ raise RuntimeError("Cannot fetch: %s" % remote)
+ return file(local, 'rb')
+
+ def cleanup(self):
+ if self._dir:
+ shutil.rmtree(self._dir)
+
+
+#
+# *NOTE: PULLED FROM PYTHON 2.5 tarfile.py Phoenix 2008-01-28
+#
+def _extractall(tar, path=".", members=None):
+ """Extract all members from the archive to the current working
+ directory and set owner, modification time and permissions on
+ directories afterwards. `path' specifies a different directory
+ to extract to. `members' is optional and must be a subset of the
+ list returned by getmembers().
+ """
+ directories = []
+
+ if members is None:
+ members = tar
+
+ for tarinfo in members:
+ if tarinfo.isdir():
+ # Extract directory with a safe mode, so that
+ # all files below can be extracted as well.
+ try:
+ os.makedirs(os.path.join(path, tarinfo.name), 0777)
+ except EnvironmentError:
+ pass
+ directories.append(tarinfo)
+ else:
+ tar.extract(tarinfo, path)
+
+ # Reverse sort directories.
+ directories.sort(lambda a, b: cmp(a.name, b.name))
+ directories.reverse()
+
+ # Set correct owner, mtime and filemode on directories.
+ for tarinfo in directories:
+ path = os.path.join(path, tarinfo.name)
+ try:
+ tar.chown(tarinfo, path)
+ tar.utime(tarinfo, path)
+ tar.chmod(tarinfo, path)
+ except tarfile.ExtractError, e:
+ if tar.errorlevel > 1:
+ raise
+ else:
+ tar._dbg(1, "tarfile: %s" % e)
+
+
+def _mkdir(directory):
+ "Safe, repeatable way to make a directory."
+ if not os.path.exists(directory):
+ os.makedirs(directory)
+
+def _get_platform():
+ "Return appropriate platform packages for the environment."
+ platform_map = {
+ 'darwin': 'darwin',
+ 'linux2': 'linux',
+ 'win32' : 'windows',
+ 'cygwin' : 'windows',
+ 'solaris' : 'solaris'
+ }
+ this_platform = platform_map[sys.platform]
+ if this_platform == 'linux':
+ if platform.architecture()[0] == '64bit':
+ # TODO -- someday when install.py accepts a platform of the form
+ # os/arch/compiler/compiler_version then we can replace the
+ # 'linux64' platform with 'linux/x86_64/gcc/4.1'
+ this_platform = 'linux'
+ return this_platform
+
+def _getuser():
+ "Get the user"
+ try:
+ # Unix-only.
+ import getpass
+ return getpass.getuser()
+ except ImportError:
+ import win32api
+ return win32api.GetUserName()
+
+def _default_installable_cache():
+ """In general, the installable files do not change much, so find a
+ host/user specific location to cache files."""
+ user = _getuser()
+ cache_dir = "/var/tmp/%s/install.cache" % user
+ if _get_platform() == 'windows':
+ cache_dir = os.path.join(tempfile.gettempdir(), \
+ 'install.cache.%s' % user)
+ return cache_dir
+
+def parse_args():
+ parser = optparse.OptionParser(
+ usage="usage: %prog [options] [installable1 [installable2...]]",
+ formatter = helpformatter.Formatter(),
+ description="""This script fetches and installs installable packages.
+It also handles uninstalling those packages and manages the mapping between
+packages and their license.
+
+The process is to open and read an install manifest file which specifies
+what files should be installed. For each installable to be installed.
+ * make sure it has a license
+ * check the installed version
+ ** if not installed and needs to be, download and install
+ ** if installed version differs, download & install
+
+If no installables are specified on the command line, then the defaut
+behavior is to install all known installables appropriate for the platform
+specified or uninstall all installables if --uninstall is set. You can specify
+more than one installable on the command line.
+
+When specifying a platform, you can specify 'all' to install all
+packages, or any platform of the form:
+
+OS[/arch[/compiler[/compiler_version]]]
+
+Where the supported values for each are:
+OS: darwin, linux, windows, solaris
+arch: i686, x86_64, ppc, universal
+compiler: vs, gcc
+compiler_version: 2003, 2005, 2008, 3.3, 3.4, 4.0, etc.
+
+No checks are made to ensure a valid combination of platform
+parts. Some exmples of valid platforms:
+
+windows
+windows/i686/vs/2005
+linux/x86_64/gcc/3.3
+linux/x86_64/gcc/4.0
+darwin/universal/gcc/4.0
+""")
+ parser.add_option(
+ '--dry-run',
+ action='store_true',
+ default=False,
+ dest='dryrun',
+ help='Do not actually install files. Downloads will still happen.')
+ parser.add_option(
+ '--install-manifest',
+ type='string',
+ default=os.path.join(base_dir, 'install.xml'),
+ dest='install_filename',
+ help='The file used to describe what should be installed.')
+ parser.add_option(
+ '--installed-manifest',
+ type='string',
+ default=os.path.join(base_dir, 'installed.xml'),
+ dest='installed_filename',
+ help='The file used to record what is installed.')
+ parser.add_option(
+ '--export-manifest',
+ action='store_true',
+ default=False,
+ dest='export_manifest',
+ help="Print the install manifest to stdout and exit.")
+ parser.add_option(
+ '-p', '--platform',
+ type='string',
+ default=_get_platform(),
+ dest='platform',
+ help="""Override the automatically determined platform. \
+You can specify 'all' to do a installation of installables for all platforms.""")
+ parser.add_option(
+ '--cache-dir',
+ type='string',
+ default=_default_installable_cache(),
+ dest='cache_dir',
+ help='Where to download files. Default: %s'% \
+ (_default_installable_cache()))
+ parser.add_option(
+ '--install-dir',
+ type='string',
+ default=base_dir,
+ dest='install_dir',
+ help='Where to unpack the installed files.')
+ parser.add_option(
+ '--list-installed',
+ action='store_true',
+ default=False,
+ dest='list_installed',
+ help="List the installed package names and exit.")
+ parser.add_option(
+ '--skip-license-check',
+ action='store_false',
+ default=True,
+ dest='check_license',
+ help="Do not perform the license check.")
+ parser.add_option(
+ '--list-licenses',
+ action='store_true',
+ default=False,
+ dest='list_licenses',
+ help="List known licenses and exit.")
+ parser.add_option(
+ '--detail-license',
+ type='string',
+ default=None,
+ dest='detail_license',
+ help="Get detailed information on specified license and exit.")
+ parser.add_option(
+ '--add-license',
+ type='string',
+ default=None,
+ dest='new_license',
+ help="""Add a license to the install file. Argument is the name of \
+license. Specify --license-url if the license is remote or specify \
+--license-text, otherwse the license text will be read from standard \
+input.""")
+ parser.add_option(
+ '--license-url',
+ type='string',
+ default=None,
+ dest='license_url',
+ help="""Put the specified url into an added license. \
+Ignored if --add-license is not specified.""")
+ parser.add_option(
+ '--license-text',
+ type='string',
+ default=None,
+ dest='license_text',
+ help="""Put the text into an added license. \
+Ignored if --add-license is not specified.""")
+ parser.add_option(
+ '--remove-license',
+ type='string',
+ default=None,
+ dest='remove_license',
+ help="Remove a named license.")
+ parser.add_option(
+ '--remove-installable',
+ type='string',
+ default=None,
+ dest='remove_installable',
+ help="Remove a installable from the install file.")
+ parser.add_option(
+ '--add-installable',
+ type='string',
+ default=None,
+ dest='add_installable',
+ help="""Add a installable into the install file. Argument is \
+the name of the installable to add.""")
+ parser.add_option(
+ '--add-installable-metadata',
+ type='string',
+ default=None,
+ dest='add_installable_metadata',
+ help="""Add package for library into the install file. Argument is \
+the name of the library to add.""")
+ parser.add_option(
+ '--installable-copyright',
+ type='string',
+ default=None,
+ dest='installable_copyright',
+ help="""Copyright for specified new package. Ignored if \
+--add-installable is not specified.""")
+ parser.add_option(
+ '--installable-license',
+ type='string',
+ default=None,
+ dest='installable_license',
+ help="""Name of license for specified new package. Ignored if \
+--add-installable is not specified.""")
+ parser.add_option(
+ '--installable-description',
+ type='string',
+ default=None,
+ dest='installable_description',
+ help="""Description for specified new package. Ignored if \
+--add-installable is not specified.""")
+ parser.add_option(
+ '--add-installable-package',
+ type='string',
+ default=None,
+ dest='add_installable_package',
+ help="""Add package for library into the install file. Argument is \
+the name of the library to add.""")
+ parser.add_option(
+ '--package-platform',
+ type='string',
+ default=None,
+ dest='package_platform',
+ help="""Platform for specified new package. \
+Ignored if --add-installable or --add-installable-package is not specified.""")
+ parser.add_option(
+ '--package-url',
+ type='string',
+ default=None,
+ dest='package_url',
+ help="""URL for specified package. \
+Ignored if --add-installable or --add-installable-package is not specified.""")
+ parser.add_option(
+ '--package-md5',
+ type='string',
+ default=None,
+ dest='package_md5',
+ help="""md5sum for new package. \
+Ignored if --add-installable or --add-installable-package is not specified.""")
+ parser.add_option(
+ '--list',
+ action='store_true',
+ default=False,
+ dest='list_installables',
+ help="List the installables in the install manifest and exit.")
+ parser.add_option(
+ '--detail',
+ type='string',
+ default=None,
+ dest='detail_installable',
+ help="Get detailed information on specified installable and exit.")
+ parser.add_option(
+ '--detail-installed',
+ type='string',
+ default=None,
+ dest='detail_installed',
+ help="Get list of files for specified installed installable and exit.")
+ parser.add_option(
+ '--uninstall',
+ action='store_true',
+ default=False,
+ dest='uninstall',
+ help="""Remove the installables specified in the arguments. Just like \
+during installation, if no installables are listed then all installed \
+installables are removed.""")
+ parser.add_option(
+ '--scp',
+ type='string',
+ default='scp',
+ dest='scp',
+ help="Specify the path to your scp program.")
+
+ return parser.parse_args()
+
+def main():
+ options, args = parse_args()
+ installer = Installer(
+ options.install_filename,
+ options.installed_filename,
+ options.dryrun)
+
+ #
+ # Handle the queries for information
+ #
+ if options.list_installed:
+ print "installed list:", installer.list_installed()
+ return 0
+ if options.list_installables:
+ print "installable list:", installer.list_installables()
+ return 0
+ if options.detail_installable:
+ try:
+ detail = installer.detail_installable(options.detail_installable)
+ print "Detail on installable",options.detail_installable+":"
+ pprint.pprint(detail)
+ except KeyError:
+ print "Installable '"+options.detail_installable+"' not found in",
+ print "install file."
+ return 0
+ if options.detail_installed:
+ try:
+ detail = installer.detail_installed(options.detail_installed)
+ #print "Detail on installed",options.detail_installed+":"
+ for line in detail:
+ print line
+ except:
+ raise
+ print "Installable '"+options.detail_installed+"' not found in ",
+ print "install file."
+ return 0
+ if options.list_licenses:
+ print "license list:", installer.list_licenses()
+ return 0
+ if options.detail_license:
+ try:
+ detail = installer.detail_license(options.detail_license)
+ print "Detail on license",options.detail_license+":"
+ pprint.pprint(detail)
+ except KeyError:
+ print "License '"+options.detail_license+"' not defined in",
+ print "install file."
+ return 0
+ if options.export_manifest:
+ # *HACK: just re-parse the install manifest and pretty print
+ # it. easier than looking at the datastructure designed for
+ # actually determining what to install
+ install = llsd.parse(file(options.install_filename, 'rb').read())
+ pprint.pprint(install)
+ return 0
+
+ #
+ # Handle updates -- can only do one of these
+ # *TODO: should this change the command line syntax?
+ #
+ if options.new_license:
+ if not installer.add_license(
+ options.new_license,
+ text=options.license_text,
+ url=options.license_url):
+ return 1
+ elif options.remove_license:
+ installer.remove_license(options.remove_license)
+ elif options.remove_installable:
+ installer.remove_installable(options.remove_installable)
+ elif options.add_installable:
+ if not installer.add_installable(
+ options.add_installable,
+ copyright=options.installable_copyright,
+ license=options.installable_license,
+ description=options.installable_description,
+ platform=options.package_platform,
+ url=options.package_url,
+ md5sum=options.package_md5):
+ return 1
+ elif options.add_installable_metadata:
+ if not installer.add_installable_metadata(
+ options.add_installable_metadata,
+ copyright=options.installable_copyright,
+ license=options.installable_license,
+ description=options.installable_description):
+ return 1
+ elif options.add_installable_package:
+ if not installer.add_installable_package(
+ options.add_installable_package,
+ platform=options.package_platform,
+ url=options.package_url,
+ md5sum=options.package_md5):
+ return 1
+ elif options.uninstall:
+ installer.do_uninstall(args, options.install_dir)
+ else:
+ installer.do_install(args, options.platform, options.install_dir,
+ options.cache_dir, options.check_license,
+ options.scp)
+
+ # save out any changes
+ installer.save()
+ return 0
+
+if __name__ == '__main__':
+ #print sys.argv
+ sys.exit(main())