diff --git a/indra/llui/lluixmltags.h b/indra/llui/lluixmltags.h index 4166131fe..ba5c26490 100644 --- a/indra/llui/lluixmltags.h +++ b/indra/llui/lluixmltags.h @@ -127,5 +127,6 @@ const std::string LL_FLYOUT_BUTTON_ITEM_TAG("flyout_button_item"), LL_SIMPLE_TEXT_EDITOR_TAG("simple_text_editor"), LL_RADIO_ITEM_TAG("radio_item"), - LL_PROGRESS_BAR_TAG("progress_bar"); + LL_PROGRESS_BAR_TAG("progress_bar"), + DO_HEX_EDITOR_TAG("hex_editor"); #endif diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index b5dbb3124..102a74c10 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -64,6 +64,9 @@ include_directories( ) set(viewer_SOURCE_FILES + dofloaterhex.cpp + dohexeditor.cpp + doinventorybackup.cpp jcfloaterareasearch.cpp llagent.cpp llagentaccess.cpp @@ -484,6 +487,9 @@ set(viewer_HEADER_FILES CMakeLists.txt ViewerInstall.cmake + dofloaterhex.h + dohexeditor.h + doinventorybackup.h jcfloaterareasearch.h llagent.h llagentaccess.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 1631c573e..99d959e95 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -12637,6 +12637,22 @@ 250 200 - + + FloaterHexRect + + Comment + Rectangle for hex editor floater. + Persist + 1 + Type + Rect + Value + + 343 + 687 + 901 + 473 + + diff --git a/indra/newview/dofloaterhex.cpp b/indra/newview/dofloaterhex.cpp new file mode 100644 index 000000000..2619e7dfb --- /dev/null +++ b/indra/newview/dofloaterhex.cpp @@ -0,0 +1,412 @@ +/** + * @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 "doinventorybackup.h" // for downloading +#include "llviewercontrol.h" // gSavedSettings +#include "llviewerwindow.h" // alertXML +#include "llagent.h" // gAgent getID +#include "llviewermenufile.h" +#include "llviewerregion.h" // getCapability +#include "llassetuploadresponders.h" // LLUpdateAgentInventoryResponder +#include "llinventorymodel.h" // gInventory.updateItem +#include "llappviewer.h" // gLocalInventoryRoot +#include "llfloaterperms.h" //get default perms + +std::list 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(mItem->getCreatorUUID() == gAgentID) + { + // Load the asset + editor->setVisible(FALSE); + childSetText("status_text", std::string("Loading...")); + DOInventoryBackup::download(mItem, this, imageCallback, assetCallback); + } else { + this->close(false); + } + + return TRUE; +} + +// static +void DOFloaterHex::imageCallback(BOOL success, + LLViewerImage *src_vi, + LLImageRaw* src, + LLImageRaw* aux_src, + S32 discard_level, + BOOL final, + void* userdata) +{ + if(final) + { + DOInventoryBackup::callbackdata* data = static_cast(userdata); + 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) +{ + DOInventoryBackup::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) + { + //U32 const std::string &display_name, LLAssetStorage::LLStoreAssetCallback callback, S32 expected_upload_cost, void *userdata) + upload_new_resource(transaction_id, + item->getType(), + item->getName(), + item->getDescription(), + 0, + item->getType(), + item->getInventoryType(), + LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(), + item->getName(), + callback, + sUploadAmount, + fake_user_data); + } + else // gestures and scripts, create an item first + { // AND notecards + //if(item->getType() == LLAssetType::AT_NOTECARD) gDontOpenNextNotecard = true; + create_inventory_item( gAgent.getID(), + gAgent.getSessionID(), + item->getParentUUID(), //gInventory.findCategoryUUIDForType(item->getType()), + LLTransactionID::tnull, + item->getName(), + fake_asset_id.asString(), + item->getType(), + item->getInventoryType(), + (EWearableType)item->getFlags(), + PERM_ITEM_UNRESTRICTED, + new NewResourceItemCallback); + } +} + +struct LLSaveInfo +{ + LLSaveInfo(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); + } +} + +// diff --git a/indra/newview/dofloaterhex.h b/indra/newview/dofloaterhex.h new file mode 100644 index 000000000..003507445 --- /dev/null +++ b/indra/newview/dofloaterhex.h @@ -0,0 +1,53 @@ +/** + * @file dofloaterhex.h + * @brief Hex Editor Floater made by Day + * @author Day Oh + * + * $LicenseInfo:firstyear=2009&license=WTFPLV2$ + * + */ + +// + + +#ifndef DO_DOFLOATERHEX_H +#define DO_DOFLOATERHEX_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 +// diff --git a/indra/newview/dohexeditor.cpp b/indra/newview/dohexeditor.cpp new file mode 100644 index 000000000..b2dde3242 --- /dev/null +++ b/indra/newview/dohexeditor.cpp @@ -0,0 +1,1238 @@ +/** + * @file dohexeditor.cpp + * @brief DOHexEditor Widget + * @author Day Oh + * + * $LicenseInfo:firstyear=2009&license=WTFPLV2$ + * + */ + +// +#include "linden_common.h" +#include "dohexeditor.h" +#include "llfocusmgr.h" +#include "llkeyboard.h" +#include "llclipboard.h" +#include "llwindow.h" // setCursor + +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); +} + + +// diff --git a/indra/newview/dohexeditor.h b/indra/newview/dohexeditor.h new file mode 100644 index 000000000..37f8ed35d --- /dev/null +++ b/indra/newview/dohexeditor.h @@ -0,0 +1,152 @@ +/** + * @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 +// diff --git a/indra/newview/doinventorybackup.cpp b/indra/newview/doinventorybackup.cpp new file mode 100644 index 000000000..0385a7690 --- /dev/null +++ b/indra/newview/doinventorybackup.cpp @@ -0,0 +1,786 @@ +/** + * @file doinventorybackup.cpp + * @brief DOInventoryBackup Floaters and Inventory Backup System + * @author Day Oh + * + * $LicenseInfo:firstyear=2009&license=WTFPLV2$ + * + */ + +// +#include "llviewerprecompiledheaders.h" + +#include "doinventorybackup.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 DOFloaterInventoryBackup::sInstances; + +DOInventoryBackupOrder::DOInventoryBackupOrder() +{ + // 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; +} + +DOFloaterInventoryBackupSettings::DOFloaterInventoryBackupSettings(DOInventoryBackupOrder* order) +: LLFloater(), + mOrder(order) +{ + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inventory_backup_settings.xml"); +} + +DOFloaterInventoryBackupSettings::~DOFloaterInventoryBackupSettings() +{ +} + +BOOL DOFloaterInventoryBackupSettings::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", DOFloaterInventoryBackupSettings::onClickNext, this); + + return TRUE; +} + +// static +void DOFloaterInventoryBackupSettings::onClickNext(void* userdata) +{ + DOFloaterInventoryBackupSettings* floater = (DOFloaterInventoryBackupSettings*)userdata; + DOInventoryBackupOrder* 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 + "\\" + DOInventoryBackup::getPath(*_cat_iter, order->mCats); + LLFile::mkdir(path); + } + + // Go go backup floater + DOFloaterInventoryBackup* backup_floater = new DOFloaterInventoryBackup(filename, order->mCats, order->mItems); + backup_floater->center(); + + // Close myself + floater->close(); +} + + + + +// static +bool DOInventoryBackup::itemIsFolder(LLInventoryItem* item) +{ + return ((item->getInventoryType() == LLInventoryType::IT_CATEGORY) + || (item->getInventoryType() == LLInventoryType::IT_ROOT_CATEGORY)); +} + +// static +LLFilePicker::ESaveFilter DOInventoryBackup::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 DOInventoryBackup::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 DOInventoryBackup::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 DOInventoryBackup::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 DOInventoryBackup::download(LLInventoryItem* item, LLFloater* floater, loaded_callback_func onImage, LLGetAssetCallback onAsset) +{ + DOInventoryBackup::callbackdata* userdata = new DOInventoryBackup::callbackdata(); + userdata->floater = floater; + userdata->item = item; + LLViewerImage* imagep; + + //don't be a jerk. (this check probably breaks stuff) + if(item->getCreatorUUID() == gAgentID) + { + 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; + } + } +} + +// static +void DOInventoryBackup::imageCallback(BOOL success, + LLViewerImage *src_vi, + LLImageRaw* src, + LLImageRaw* aux_src, + S32 discard_level, + BOOL final, + void* userdata) +{ + if(final) + { + DOInventoryBackup::callbackdata* data = static_cast(userdata); + 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 DOInventoryBackup::assetCallback(LLVFS *vfs, + const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) +{ + DOInventoryBackup::callbackdata* data = static_cast(user_data); + 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 DOInventoryBackup::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 DOInventoryBackup::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()) + "\\" + path; + parent = model->getCategory(parent->getParentUUID()); + } + return path; +} + +// static +void DOInventoryBackup::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 + DOInventoryBackup::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); + } + } + } + } + + DOInventoryBackupOrder* order = new DOInventoryBackupOrder(); + order->mCats = cats; + order->mItems = items; + DOFloaterInventoryBackupSettings* floater = new DOFloaterInventoryBackupSettings(order); + floater->center(); +} + + + +DOFloaterInventoryBackup::DOFloaterInventoryBackup(std::string path, std::vector cats, std::vector items) +: LLFloater(), + mPath(path), + mCats(cats), + mItems(items), + mBusy(0) +{ + mItemsTotal = mItems.size(); + mItemsCompleted = 0; + + DOFloaterInventoryBackup::sInstances.push_back(this); + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inventory_backup.xml"); +} + + +DOFloaterInventoryBackup::~DOFloaterInventoryBackup() +{ + DOFloaterInventoryBackup::sInstances.remove(this); +} + +BOOL DOFloaterInventoryBackup::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"); + DOInventoryBackup::download(*mItemIter, this, DOFloaterInventoryBackup::imageCallback, DOFloaterInventoryBackup::assetCallback); + advance(); + + return TRUE; +} + +void DOFloaterInventoryBackup::advance() +{ + while((mItemIter != mItems.end()) && (mBusy < 4)) + { + mBusy++; + mItemIter++; + if(mItemIter >= mItems.end()) break; + setStatus((*mItemIter)->getUUID(), "Downloading"); + DOInventoryBackup::download(*mItemIter, this, DOFloaterInventoryBackup::imageCallback, DOFloaterInventoryBackup::assetCallback); + } +} + +void DOFloaterInventoryBackup::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 DOFloaterInventoryBackup::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 DOFloaterInventoryBackup::imageCallback(BOOL success, + LLViewerImage *src_vi, + LLImageRaw* src, + LLImageRaw* aux_src, + S32 discard_level, + BOOL final, + void* userdata) +{ + if(final) + { + DOInventoryBackup::callbackdata* data = static_cast(userdata); + DOFloaterInventoryBackup* floater = (DOFloaterInventoryBackup*)(data->floater); + LLInventoryItem* item = data->item; + + if(std::find(DOFloaterInventoryBackup::sInstances.begin(), DOFloaterInventoryBackup::sInstances.end(), floater) == DOFloaterInventoryBackup::sInstances.end()) + { + return; + } + + if(!success) + { + floater->finishItem(item->getUUID(), "Failed download"); + return; + } + + std::string filename = floater->mPath + "\\" + DOInventoryBackup::getPath(gInventory.getCategory(item->getParentUUID()), floater->mCats) + "\\" + LLDir::getScrubbedFileName(item->getName()); + filename = DOInventoryBackup::getUniqueFilename(filename, DOInventoryBackup::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 DOFloaterInventoryBackup::assetCallback(LLVFS *vfs, + const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) +{ + DOInventoryBackup::callbackdata* data = static_cast(user_data); + DOFloaterInventoryBackup* floater = (DOFloaterInventoryBackup*)(data->floater); + LLInventoryItem* item = data->item; + + if(std::find(DOFloaterInventoryBackup::sInstances.begin(), DOFloaterInventoryBackup::sInstances.end(), floater) == DOFloaterInventoryBackup::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 + "\\" + DOInventoryBackup::getPath(gInventory.getCategory(item->getParentUUID()), floater->mCats) + "\\" + LLDir::getScrubbedFileName(item->getName()); + filename = DOInventoryBackup::getUniqueFilename(filename, DOInventoryBackup::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/doinventorybackup.h b/indra/newview/doinventorybackup.h new file mode 100644 index 000000000..fbd9df894 --- /dev/null +++ b/indra/newview/doinventorybackup.h @@ -0,0 +1,137 @@ +/** + * @file doinventorybackup.h + * @brief DOInventoryBackup Floaters and Inventory Backup System + * @author Day Oh + * + * $LicenseInfo:firstyear=2009&license=WTFPLV2$ + * + */ + +// +#ifndef DO_DOINVENTORYBACKUP_H +#define DO_DOINVENTORYBACKUP_H + +#include "llviewerinventory.h" +#include "llfolderview.h" +#include "llfilepicker.h" +#include "llviewerimage.h" +#include "llfloater.h" + + +class DOInventoryBackupOrder +{ +public: + DOInventoryBackupOrder(); + + 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 DOFloaterInventoryBackupSettings +: public LLFloater +{ +public: + DOFloaterInventoryBackupSettings(DOInventoryBackupOrder* order); + BOOL postBuild(void); + static void onClickNext(void* userdata); + + DOInventoryBackupOrder* mOrder; + virtual ~DOFloaterInventoryBackupSettings(); +}; + +class DOFloaterInventoryBackup +: public LLFloater +{ +public: + DOFloaterInventoryBackup(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 ~DOFloaterInventoryBackup(); + 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 DOInventoryBackup +{ +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/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh index 7a9fc3ee6..a43a6d8f5 100755 --- a/indra/newview/linux_tools/wrapper.sh +++ b/indra/newview/linux_tools/wrapper.sh @@ -7,14 +7,14 @@ ## - Avoids using any OpenAL audio driver. #export LL_BAD_OPENAL_DRIVER=x ## - Avoids using any FMOD audio driver. -#export LL_BAD_FMOD_DRIVER=x +export LL_BAD_FMOD_DRIVER=x ## - Avoids using the FMOD ESD audio driver. #export LL_BAD_FMOD_ESD=x ## - Avoids using the FMOD OSS audio driver. #export LL_BAD_FMOD_OSS=x ## - Avoids using the FMOD ALSA audio driver. -export LL_BAD_FMOD_ALSA=x +#export LL_BAD_FMOD_ALSA=x ## - Avoids the optional OpenGL extensions which have proven most problematic ## on some hardware. Disabling this option may cause BETTER PERFORMANCE but @@ -114,7 +114,7 @@ if [ -n "$LL_TCMALLOC" ]; then fi fi -export VIEWER_BINARY='inertia-do-not-run-directly' +export VIEWER_BINARY='snowglobe-do-not-run-directly' export SL_ENV='LD_LIBRARY_PATH="`pwd`"/lib:"`pwd`"/app_settings/mozilla-runtime-linux-i686:"${LD_LIBRARY_PATH}"' export SL_CMD='$LL_WRAPPER bin/$VIEWER_BINARY' export SL_OPT="`cat gridargs.dat` $@" diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 8f5882615..712d0c086 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -51,8 +51,11 @@ LLFilePicker LLFilePicker::sInstance; #if LL_WINDOWS -#define SOUND_FILTER L"Sounds (*.wav)\0*.wav\0" -#define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png)\0*.tga;*.bmp;*.jpg;*.jpeg;*.png\0" +// +#define SOUND_FILTER L"Sounds (*.wav; *.ogg)\0*.wav;*.ogg\0" +#define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png; *.jp2; *.j2k; *.j2c)\0*.tga;*.bmp;*.jpg;*.jpeg;*.png;*.jp2;*.j2k;*.j2c\0" +#define INVGZ_FILTER L"Inv cache (*.inv; *.inv.gz)\0*.inv;*.inv.gz\0" +// #define ANIM_FILTER L"Animations (*.bvh)\0*.bvh\0" #ifdef _CORY_TESTING #define GEOMETRY_FILTER L"SL Geometry (*.slg)\0*.slg\0" @@ -192,6 +195,16 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter) mOFN.lpstrFilter = RAW_FILTER \ L"\0"; break; + // + case FFLOAD_INVGZ: + mOFN.lpstrFilter = INVGZ_FILTER \ + L"\0"; + break; + case FFLOAD_AO: + mOFN.lpstrFilter = AO_FILTER \ + L"\0"; + break; + // default: res = FALSE; break; @@ -451,6 +464,218 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename) L"Compressed Images (*.j2c)\0*.j2c\0" \ L"\0"; break; + // + case FFSAVE_ANIMATN: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.animatn", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"animatn"; + mOFN.lpstrFilter = + L"SL Animations (*.animatn)\0*.animatn\0" \ + L"\0"; + break; + case FFSAVE_OGG: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.ogg", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"ogg"; + mOFN.lpstrFilter = + L"Ogg (*.ogg)\0*.ogg\0" \ + L"\0"; + break; + case FFSAVE_NOTECARD: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.notecard", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"notecard"; + mOFN.lpstrFilter = + L"Notecards (*.notecard)\0*.notecard\0" \ + L"\0"; + break; + case FFSAVE_GESTURE: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.gesture", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"gesture"; + mOFN.lpstrFilter = + L"Gestures (*.gesture)\0*.gesture\0" \ + L"\0"; + break; + case FFSAVE_LSL: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.lsl", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"lsl"; + mOFN.lpstrFilter = + L"LSL (*.lsl)\0*.lsl\0" \ + L"\0"; + break; + case FFSAVE_SHAPE: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.shape", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"shape"; + mOFN.lpstrFilter = + L"Shapes (*.shape)\0*.shape\0" \ + L"\0"; + break; + case FFSAVE_SKIN: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.skin", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"skin"; + mOFN.lpstrFilter = + L"Skins (*.skin)\0*.skin\0" \ + L"\0"; + break; + case FFSAVE_HAIR: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.hair", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"hair"; + mOFN.lpstrFilter = + L"Hair (*.hair)\0*.hair\0" \ + L"\0"; + break; + case FFSAVE_EYES: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.eyes", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"eyes"; + mOFN.lpstrFilter = + L"Eyes (*.eyes)\0*.eyes\0" \ + L"\0"; + break; + case FFSAVE_SHIRT: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.shirt", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"shirt"; + mOFN.lpstrFilter = + L"Shirts (*.shirt)\0*.shirt\0" \ + L"\0"; + break; + case FFSAVE_PANTS: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.pants", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"pants"; + mOFN.lpstrFilter = + L"Pants (*.pants)\0*.pants\0" \ + L"\0"; + break; + case FFSAVE_SHOES: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.shoes", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"shoes"; + mOFN.lpstrFilter = + L"Shoes (*.shoes)\0*.shoes\0" \ + L"\0"; + break; + case FFSAVE_SOCKS: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.socks", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"socks"; + mOFN.lpstrFilter = + L"Socks (*.socks)\0*.socks\0" \ + L"\0"; + break; + case FFSAVE_JACKET: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.jacket", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"jacket"; + mOFN.lpstrFilter = + L"Jackets (*.jacket)\0*.jacket\0" \ + L"\0"; + break; + case FFSAVE_GLOVES: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.gloves", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"gloves"; + mOFN.lpstrFilter = + L"Gloves (*.gloves)\0*.gloves\0" \ + L"\0"; + break; + case FFSAVE_UNDERSHIRT: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.undershirt", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"undershirt"; + mOFN.lpstrFilter = + L"Undershirts (*.undershirt)\0*.undershirt\0" \ + L"\0"; + break; + case FFSAVE_UNDERPANTS: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.underpants", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"underpants"; + mOFN.lpstrFilter = + L"Underpants (*.underpants)\0*.underpants\0" \ + L"\0"; + break; + case FFSAVE_SKIRT: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.skirt", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"skirt"; + mOFN.lpstrFilter = + L"Skirts (*.skirt)\0*.skirt\0" \ + L"\0"; + break; + case FFSAVE_LANDMARK: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.landmark", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"landmark"; + mOFN.lpstrFilter = + L"Landmarks (*.landmark)\0*.landmark\0" \ + L"\0"; + break; + case FFSAVE_AO: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.ao", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"ao"; + mOFN.lpstrFilter = + L"Animation overrides (*.ao)\0*.ao\0" \ + L"\0"; + break; + case FFSAVE_INVGZ: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.inv", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L".inv"; + mOFN.lpstrFilter = + L"InvCache (*.inv)\0*.inv\0" \ + L"\0"; + break; + // default: return FALSE; } diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index 104e0df29..da541cf3f 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -91,6 +91,10 @@ public: FFLOAD_XML = 6, FFLOAD_SLOBJECT = 7, FFLOAD_RAW = 8, + // + FFLOAD_INVGZ = 9, + FFLOAD_AO = 10, + // }; enum ESaveFilter @@ -110,6 +114,30 @@ public: FFSAVE_J2C = 12, FFSAVE_PNG = 13, FFSAVE_JPEG = 14, + // + FFSAVE_ANIMATN = 15, + FFSAVE_OGG = 16, + FFSAVE_NOTECARD = 17, + FFSAVE_GESTURE = 18, + FFSAVE_LSL = 19, + // good grief + FFSAVE_SHAPE = 20, + FFSAVE_SKIN = 21, + FFSAVE_HAIR = 22, + FFSAVE_EYES = 23, + FFSAVE_SHIRT = 24, + FFSAVE_PANTS = 25, + FFSAVE_SHOES = 26, + FFSAVE_SOCKS = 27, + FFSAVE_JACKET = 28, + FFSAVE_GLOVES = 29, + FFSAVE_UNDERSHIRT = 30, + FFSAVE_UNDERPANTS = 31, + FFSAVE_SKIRT = 32, + FFSAVE_INVGZ = 33, + FFSAVE_LANDMARK = 34, + FFSAVE_AO = 35, + // }; // open the dialog. This is a modal operation diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index bc6908a0c..44a05dde5 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -86,6 +86,7 @@ #include "lluictrlfactory.h" #include "llselectmgr.h" #include "llfloateropenobject.h" +#include "dofloaterhex.h" // Helpers // bug in busy count inc/dec right now, logic is complex... do we really need it? @@ -443,6 +444,8 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, std::vectorgetItem(mUUID); + if(!item) return; + if(item->getCreatorUUID() != gAgentID) return; + DOFloaterHex::show(mUUID); + } else if ("copy_uuid" == action) { // Single item only diff --git a/indra/newview/llviewerimage.cpp b/indra/newview/llviewerimage.cpp index 3a14bf009..d0be919d6 100644 --- a/indra/newview/llviewerimage.cpp +++ b/indra/newview/llviewerimage.cpp @@ -1320,6 +1320,31 @@ void LLViewerImage::setLoadedCallback( loaded_callback_func loaded_callback, } } +// this method is stupid, remove it if at all possible -Day +void LLViewerImage::setLoadedCallbackNoAux( loaded_callback_func loaded_callback, + S32 discard_level, BOOL keep_imageraw, BOOL needs_aux, void* userdata) +{ + // + // Don't do ANYTHING here, just add it to the global callback list + // + if (mLoadedCallbackList.empty()) + { + // Put in list to call this->doLoadedCallbacks() periodically + gImageList.mCallbackList.insert(this); + } + + LLLoadedCallbackEntry* entryp = new LLLoadedCallbackEntry(loaded_callback, discard_level, keep_imageraw, userdata); + mLoadedCallbackList.push_back(entryp); + mNeedsAux = needs_aux; + + if (mNeedsAux && mAuxRawImage.isNull() && getDiscardLevel() >= 0) + { + // We need aux data, but we've already loaded the image, and it didn't have any + llwarns << "No aux data available for callback for image:" << getID() << llendl; + } +} +// + bool LLViewerImage::doLoadedCallbacks() { if (mNeedsCreateTexture) diff --git a/indra/newview/llviewerimage.h b/indra/newview/llviewerimage.h index fdf8ff040..91037473b 100644 --- a/indra/newview/llviewerimage.h +++ b/indra/newview/llviewerimage.h @@ -246,6 +246,12 @@ public: void setLoadedCallback(loaded_callback_func cb, S32 discard_level, BOOL keep_imageraw, BOOL needs_aux, void* userdata); + +// + void setLoadedCallbackNoAux(loaded_callback_func cb, + S32 discard_level, BOOL keep_imageraw, BOOL needs_aux, + void* userdata); +// // ONLY call from LLViewerImageList BOOL createTexture(S32 usename = 0); @@ -445,4 +451,6 @@ public: static S32 sLLViewerImageCount ; }; + + #endif diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index dc5f5af21..3ad069eda 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -1092,3 +1092,43 @@ void init_menu_file() (new LLFileEnableUpload())->registerListener(gMenuHolder, "File.EnableUpload"); (new LLFileEnableSaveAs())->registerListener(gMenuHolder, "File.EnableSaveAs"); } + +// +void NewResourceItemCallback::fire(const LLUUID& new_item_id) +{ + LLViewerInventoryItem* new_item = (LLViewerInventoryItem*)gInventory.getItem(new_item_id); + if(!new_item) return; + LLUUID vfile_id = LLUUID(new_item->getDescription()); + if(vfile_id.isNull()) return; + new_item->setDescription("(No Description)"); + new_item->updateServer(FALSE); + gInventory.updateItem(new_item); + gInventory.notifyObservers(); + + std::string agent_url; + LLSD body; + body["item_id"] = new_item_id; + + if(new_item->getType() == LLAssetType::AT_GESTURE) + { + agent_url = gAgent.getRegion()->getCapability("UpdateGestureAgentInventory"); + } + else if(new_item->getType() == LLAssetType::AT_LSL_TEXT) + { + agent_url = gAgent.getRegion()->getCapability("UpdateScriptAgent"); + body["target"] = "lsl2"; + } + else if(new_item->getType() == LLAssetType::AT_NOTECARD) + { + agent_url = gAgent.getRegion()->getCapability("UpdateNotecardAgentInventory"); + } + else + { + return; + } + + if(agent_url.empty()) return; + LLHTTPClient::post(agent_url, body, + new LLUpdateAgentInventoryResponder(body, vfile_id, new_item->getType())); +} +// diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index bf2129208..c92e82da3 100644 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -35,6 +35,14 @@ #include "llassettype.h" #include "llinventorytype.h" +// +#include "llviewerinventory.h" + +class NewResourceItemCallback : public LLInventoryCallback +{ + void fire(const LLUUID& inv_item); +}; +// class LLTransactionID; diff --git a/indra/newview/skins/default/xui/en-us/floater_hex.xml b/indra/newview/skins/default/xui/en-us/floater_hex.xml new file mode 100644 index 000000000..ceb91a5ae --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/floater_hex.xml @@ -0,0 +1,9 @@ + + + Loading... +