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... +