diff --git a/indra/newview/llpreviewanim.cpp b/indra/newview/llpreviewanim.cpp index 3212de063..60741899e 100644 --- a/indra/newview/llpreviewanim.cpp +++ b/indra/newview/llpreviewanim.cpp @@ -44,6 +44,10 @@ #include "lllineeditor.h" #include "lluictrlfactory.h" #include "lluictrlfactory.h" +// +#include "llviewerwindow.h" // for alert +#include "llappviewer.h" // gStaticVFS +// extern LLAgent gAgent; @@ -54,6 +58,9 @@ LLPreviewAnim::LLPreviewAnim(const std::string& name, const LLRect& rect, const childSetAction("Anim play btn",playAnim,this); childSetAction("Anim audition btn",auditionAnim,this); + // + childSetAction("Anim copy uuid btn", copyAnimID, this); + // const LLInventoryItem* item = getItem(); @@ -181,6 +188,242 @@ void LLPreviewAnim::auditionAnim( void *userdata ) } } +// +// static +/* +void LLPreviewAnim::copyAnim(void *userdata) +{ + LLPreviewAnim* self = (LLPreviewAnim*) userdata; + const LLInventoryItem *item = self->getItem(); + + if(item) + { + // Some animations aren't hosted on the servers + // I guess they're in this static vfs thing + bool static_vfile = false; + LLVFile* anim_file = new LLVFile(gStaticVFS, item->getAssetUUID(), LLAssetType::AT_ANIMATION); + if (anim_file && anim_file->getSize()) + { + //S32 anim_file_size = anim_file->getSize(); + //U8* anim_data = new U8[anim_file_size]; + //if(anim_file->read(anim_data, anim_file_size)) + //{ + // static_vfile = true; + //} + static_vfile = true; // for method 2 + LLPreviewAnim::gotAssetForCopy(gStaticVFS, item->getAssetUUID(), LLAssetType::AT_ANIMATION, self, 0, 0); + } + delete anim_file; + anim_file = NULL; + + if(!static_vfile) + { + // Get it from the servers + gAssetStorage->getAssetData(item->getAssetUUID(), LLAssetType::AT_ANIMATION, LLPreviewAnim::gotAssetForCopy, self, TRUE); + } + } +} + +struct LLSaveInfo +{ + LLSaveInfo(const LLUUID& item_id, const LLUUID& object_id, const std::string& desc, + const LLTransactionID tid) + : mItemUUID(item_id), mObjectUUID(object_id), mDesc(desc), mTransactionID(tid) + { + } + + LLUUID mItemUUID; + LLUUID mObjectUUID; + std::string mDesc; + LLTransactionID mTransactionID; +}; + +// static +void LLPreviewAnim::gotAssetForCopy(LLVFS *vfs, + const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) +{ + LLPreviewAnim* self = (LLPreviewAnim*) user_data; + //const LLInventoryItem *item = self->getItem(); + + 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... + + LLTransactionID tid; + LLAssetID asset_id; + tid.generate(); + asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); + + LLVFile ofile(gVFS, asset_id, LLAssetType::AT_ANIMATION, LLVFile::APPEND); + + ofile.setMaxSize(size); + ofile.write((U8*)buffer, size); + + // Upload that asset to the database + LLSaveInfo* info = new LLSaveInfo(self->mItemUUID, self->mObjectUUID, "animation", tid); + gAssetStorage->storeAssetData(tid, LLAssetType::AT_ANIMATION, onSaveCopyComplete, info, FALSE); + + delete[] buffer; + buffer = NULL; +} + +// static +void LLPreviewAnim::onSaveCopyComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) +{ + LLSaveInfo* info = (LLSaveInfo*)user_data; + + if (status == 0) + { + std::string item_name = "New Animation"; + std::string item_desc = ""; + // Saving into user inventory + LLViewerInventoryItem* item; + item = (LLViewerInventoryItem*)gInventory.getItem(info->mItemUUID); + if(item) + { + item_name = item->getName(); + item_desc = item->getDescription(); + } + gMessageSystem->newMessageFast(_PREHASH_CreateInventoryItem); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_InventoryBlock); + gMessageSystem->addU32Fast(_PREHASH_CallbackID, 0); + gMessageSystem->addUUIDFast(_PREHASH_FolderID, LLUUID::null); + gMessageSystem->addUUIDFast(_PREHASH_TransactionID, info->mTransactionID); + gMessageSystem->addU32Fast(_PREHASH_NextOwnerMask, 2147483647); + gMessageSystem->addS8Fast(_PREHASH_Type, LLAssetType::AT_ANIMATION); + gMessageSystem->addS8Fast(_PREHASH_InvType, LLInventoryType::IT_ANIMATION); + gMessageSystem->addU8Fast(_PREHASH_WearableType, 0); + gMessageSystem->addStringFast(_PREHASH_Name, item_name); + gMessageSystem->addStringFast(_PREHASH_Description, item_desc); + gMessageSystem->sendReliable(gAgent.getRegionHost()); + } + else + { + llwarns << "Problem saving animation: " << status << llendl; + LLStringUtil::format_map_t args; + args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status)); + gViewerWindow->alertXml("CannotUploadReason",args); + } +} +*/ +void LLPreviewAnim::copyAnimID(void *userdata) +{ + LLPreviewAnim* self = (LLPreviewAnim*) userdata; + const LLInventoryItem *item = self->getItem(); + + if(item) + { + gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(item->getAssetUUID().asString())); + } +} +// + +// +// virtual +BOOL LLPreviewAnim::canSaveAs() const +{ + return TRUE; +} + +// virtual +void LLPreviewAnim::saveAs() +{ + const LLInventoryItem *item = getItem(); + + if(item) + { + // Some animations aren't hosted on the servers + // I guess they're in this static vfs thing + bool static_vfile = false; + LLVFile* anim_file = new LLVFile(gStaticVFS, item->getAssetUUID(), LLAssetType::AT_ANIMATION); + if (anim_file && anim_file->getSize()) + { + //S32 anim_file_size = anim_file->getSize(); + //U8* anim_data = new U8[anim_file_size]; + //if(anim_file->read(anim_data, anim_file_size)) + //{ + // static_vfile = true; + //} + static_vfile = true; // for method 2 + LLPreviewAnim::gotAssetForSave(gStaticVFS, item->getAssetUUID(), LLAssetType::AT_ANIMATION, this, 0, 0); + } + delete anim_file; + anim_file = NULL; + + if(!static_vfile) + { + gAssetStorage->getAssetData(item->getAssetUUID(), LLAssetType::AT_ANIMATION, LLPreviewAnim::gotAssetForSave, this, TRUE); + } + } +} + +// static +void LLPreviewAnim::gotAssetForSave(LLVFS *vfs, + const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) +{ + LLPreviewAnim* self = (LLPreviewAnim*) user_data; + //const LLInventoryItem *item = self->getItem(); + + 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( LLFilePicker::FFSAVE_ANIMATN, LLDir::getScrubbedFileName(self->getItem()->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(); + + delete[] buffer; + buffer = NULL; +} + +// virtual +LLUUID LLPreviewAnim::getItemID() +{ + const LLViewerInventoryItem* item = getItem(); + if(item) + { + return item->getUUID(); + } + return LLUUID::null; +} +// + void LLPreviewAnim::onClose(bool app_quitting) { const LLInventoryItem *item = getItem(); diff --git a/indra/newview/llpreviewanim.h b/indra/newview/llpreviewanim.h index fe794d428..b1d26c0ee 100644 --- a/indra/newview/llpreviewanim.h +++ b/indra/newview/llpreviewanim.h @@ -46,10 +46,30 @@ public: static void playAnim( void* userdata ); static void auditionAnim( void* userdata ); + // + /* + static void copyAnim(void* userdata); + static void gotAssetForCopy(LLVFS *vfs, + const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status); + static void onSaveCopyComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status); + */ + static void gotAssetForSave(LLVFS *vfs, + const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status); + static void copyAnimID(void* userdata); + // static void endAnimCallback( void *userdata ); protected: virtual void onClose(bool app_quitting); + // + virtual BOOL canSaveAs() const; + virtual void saveAs(); + virtual LLUUID getItemID(); + // virtual const char *getTitleName() const { return "Animation"; } LLAnimPauseRequest mPauseRequest; diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index b692b9ebd..7b6d952fb 100644 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -70,7 +70,14 @@ #include "llappviewer.h" // gVFS #include "llanimstatelabels.h" #include "llresmgr.h" - +// +#include "llviewercontrol.h" +#include "llpreviewsound.h" +#include "llpreviewanim.h" + +#include "lllocalinventory.h" +#include "llfilepicker.h" +// // *TODO: Translate? const std::string NONE_LABEL = "---"; @@ -163,7 +170,10 @@ LLPreviewGesture* LLPreviewGesture::show(const std::string& title, const LLUUID& // this will call refresh when we have everything. LLViewerInventoryItem* item = (LLViewerInventoryItem*)self->getItem(); - if(item && !item->isComplete()) + // + //if(item && !item->isComplete()) + if(item && !item->isComplete() && !(gInventory.isObjectDescendentOf(item->getUUID(), gLocalInventoryRoot))) + // { LLInventoryGestureAvailable* observer; observer = new LLInventoryGestureAvailable(); @@ -219,19 +229,26 @@ BOOL LLPreviewGesture::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, if (item && gInventory.getItem(item->getUUID())) { - LLPermissions perm = item->getPermissions(); - if (!((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)) - { - *accept = ACCEPT_NO; - if (tooltip_msg.empty()) - { - tooltip_msg.assign("Only animations and sounds\n" - "with unrestricted permissions\n" - "can be added to a gesture."); - } - break; - } - else if (drop) + // + /* + // + LLPermissions perm = item->getPermissions(); + if (!((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)) + { + *accept = ACCEPT_NO; + if (tooltip_msg.empty()) + { + tooltip_msg.assign("Only animations and sounds\n" + "with unrestricted permissions\n" + "can be added to a gesture."); + } + break; + } + else if (drop) + // + */ + if(drop) + // { LLScrollListItem* line = NULL; if (cargo_type == DAD_ANIMATION) @@ -364,6 +381,10 @@ LLPreviewGesture::LLPreviewGesture() mSoundCombo(NULL), mChatEditor(NULL), mSaveBtn(NULL), + // + mDuplicateBtn(NULL), + mOpenBtn(NULL), + // mPreviewBtn(NULL), mPreviewGesture(NULL), mDirty(FALSE) @@ -528,6 +549,18 @@ BOOL LLPreviewGesture::postBuild() btn->setCallbackUserData(this); mSaveBtn = btn; + // + btn = getChild( "duplicate_btn"); + btn->setClickedCallback(onClickDuplicate); + btn->setCallbackUserData(this); + mDuplicateBtn = btn; + + btn = getChild( "open_btn"); + btn->setClickedCallback(onClickOpen); + btn->setCallbackUserData(this); + mOpenBtn = btn; + // + btn = getChild( "preview_btn"); btn->setClickedCallback(onClickPreview); btn->setCallbackUserData(this); @@ -607,7 +640,10 @@ void LLPreviewGesture::addAnimations() LLViewerInventoryCategory::cat_array_t cats; LLViewerInventoryItem::item_array_t items; LLIsTypeWithPermissions is_copyable_animation(LLAssetType::AT_ANIMATION, - PERM_ITEM_UNRESTRICTED, + // + // PERM_ITEM_UNRESTRICTED, + PERM_NONE, + // gAgent.getID(), gAgent.getGroupID()); gInventory.collectDescendentsIf(gAgent.getInventoryRootID(), @@ -724,13 +760,22 @@ void LLPreviewGesture::refresh() mWaitTimeEditor->setEnabled(FALSE); mActiveCheck->setEnabled(FALSE); mSaveBtn->setEnabled(FALSE); + // + mDuplicateBtn->setEnabled(TRUE); + mOpenBtn->setEnabled(TRUE); + mStepList->setEnabled(TRUE); + // // Make sure preview button is enabled, so we can stop it mPreviewBtn->setEnabled(TRUE); return; } - BOOL modifiable = item->getPermissions().allowModifyBy(gAgent.getID()); + // + //BOOL modifiable = item->getPermissions().allowModifyBy(gAgent.getID()); + BOOL modifiable = TRUE; + mOpenBtn->setEnabled(TRUE); + // childSetEnabled("desc", modifiable); mTriggerEditor->setEnabled(TRUE); @@ -779,6 +824,9 @@ void LLPreviewGesture::refresh() mWaitAnimCheck->setVisible(FALSE); mWaitTimeCheck->setVisible(FALSE); mWaitTimeEditor->setVisible(FALSE); + // + mOpenBtn->setVisible(FALSE); + // std::string optionstext; @@ -798,6 +846,9 @@ void LLPreviewGesture::refresh() mAnimationRadio->setVisible(TRUE); mAnimationRadio->setSelectedIndex((anim_step->mFlags & ANIM_FLAG_STOP) ? 1 : 0); mAnimationCombo->setCurrentByID(anim_step->mAnimAssetID); + // + mOpenBtn->setVisible(TRUE); + // break; } case STEP_SOUND: @@ -806,6 +857,9 @@ void LLPreviewGesture::refresh() optionstext = getString("step_sound"); mSoundCombo->setVisible(TRUE); mSoundCombo->setCurrentByID(sound_step->mSoundAssetID); + // + mOpenBtn->setVisible(TRUE); + // break; } case STEP_CHAT: @@ -1117,7 +1171,10 @@ void LLPreviewGesture::saveIfNeeded() BOOL ok = gesture->serialize(dp); - if (dp.getCurrentSize() > 1000) + // + //if (dp.getCurrentSize() > 1000) + if(0) + // { LLNotifications::instance().add("GestureSaveFailedTooManySteps"); @@ -1216,6 +1273,62 @@ void LLPreviewGesture::saveIfNeeded() buffer = NULL; } +// +void LLPreviewGesture::saveDuplicate() +{ + LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(mItemUUID); + if(item) + { + create_inventory_item( gAgent.getID(), + gAgent.getSessionID(), + item->getParentUUID(), + LLTransactionID::tnull, + item->getName(), + item->getUUID().asString(), + item->getType(), + item->getInventoryType(), + NOT_WEARABLE, + PERM_ITEM_UNRESTRICTED, + new LLPreviewGesture::GestureItemForDuplicateCallback); + } +} + +void LLPreviewGesture::GestureItemForDuplicateCallback::fire(const LLUUID& new_item_id) +{ + LLViewerInventoryItem* new_item = (LLViewerInventoryItem*)gInventory.getItem(new_item_id); + LLUUID old_item_id = LLUUID(new_item->getDescription()); + if(old_item_id.isNull()) return; + LLViewerInventoryItem* old_item = (LLViewerInventoryItem*)gInventory.getItem(old_item_id); + if(!old_item) return; + new_item->setDescription(old_item->getDescription()); + new_item->updateServer(FALSE); + gInventory.updateItem(new_item); + gInventory.notifyObservers(); + LLPreviewGesture* preview = (LLPreviewGesture*)LLPreview::find(old_item_id); + if(!preview) return; + LLMultiGesture* gesture = preview->createGesture(); + S32 max_size = gesture->getMaxSerialSize(); + char* buffer = new char[max_size]; + LLDataPackerAsciiBuffer dp(buffer, max_size); + BOOL ok = gesture->serialize(dp); + if(!ok) return; + LLTransactionID tid; + LLAssetID asset_id; + tid.generate(); + asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); + LLVFile file(gVFS, asset_id, LLAssetType::AT_GESTURE, LLVFile::APPEND); + S32 size = dp.getCurrentSize(); + file.setMaxSize(size); + file.write((U8*)buffer, size); + + std::string agent_url = gAgent.getRegion()->getCapability("UpdateGestureAgentInventory"); + if(agent_url.empty()) return; + LLSD body; + body["item_id"] = new_item_id; + LLHTTPClient::post(agent_url, body, + new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_GESTURE)); +} +// // TODO: This is very similar to LLPreviewNotecard::onSaveComplete. // Could merge code. @@ -1287,6 +1400,58 @@ void LLPreviewGesture::onSaveComplete(const LLUUID& asset_uuid, void* user_data, info = NULL; } +// +void LLPreviewGesture::onSaveDuplicateComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed) +{ + LLSaveInfo* info = (LLSaveInfo*)user_data; + if (info && (status == 0)) + { + std::string item_name = "New Gesture"; + std::string item_desc = ""; + // Saving into user inventory + LLViewerInventoryItem* item; + item = (LLViewerInventoryItem*)gInventory.getItem(info->mItemUUID); + if(item) + { + item_name = item->getName(); + item_desc = item->getDescription(); + } + gMessageSystem->newMessageFast(_PREHASH_CreateInventoryItem); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_InventoryBlock); + gMessageSystem->addU32Fast(_PREHASH_CallbackID, 0); + gMessageSystem->addUUIDFast(_PREHASH_FolderID, LLUUID::null); + gMessageSystem->addUUIDFast(_PREHASH_TransactionID, info->mTransactionID); + gMessageSystem->addU32Fast(_PREHASH_NextOwnerMask, 2147483647); + gMessageSystem->addS8Fast(_PREHASH_Type, 21); + gMessageSystem->addS8Fast(_PREHASH_InvType, 20); + gMessageSystem->addU8Fast(_PREHASH_WearableType, 0); + gMessageSystem->addStringFast(_PREHASH_Name, item_name); + gMessageSystem->addStringFast(_PREHASH_Description, item_desc); + gMessageSystem->sendReliable(gAgent.getRegionHost()); + + // Find our window and close it if requested. + /* + LLPreviewGesture* previewp = (LLPreviewGesture*)LLPreview::find(info->mItemUUID); + if (previewp && previewp->mCloseAfterSave) + { + previewp->close(); + } + */ + } + else + { + llwarns << "Problem saving gesture: " << status << llendl; + LLSD args; + args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); + LLNotifications::instance().add("GestureSaveFailedReason", args); + } + delete info; + info = NULL; +} +// LLMultiGesture* LLPreviewGesture::createGesture() { @@ -1740,6 +1905,36 @@ void LLPreviewGesture::onClickSave(void* data) self->saveIfNeeded(); } +// +// static +void LLPreviewGesture::onClickDuplicate(void* data) +{ + LLPreviewGesture* self = (LLPreviewGesture*)data; + self->saveDuplicate(); +} + +// static +void LLPreviewGesture::onClickOpen(void* data) +{ + LLPreviewGesture* self = (LLPreviewGesture*)data; + + LLScrollListItem* step_item = self->mStepList->getFirstSelected(); + if (!step_item) return; + + LLGestureStep* step = (LLGestureStep*)step_item->getUserdata(); + if (step->getType() == STEP_SOUND) + { + LLGestureStepSound* sound_step = (LLGestureStepSound*)step; + LLLocalInventory::addItem(sound_step->mSoundName, (int)LLAssetType::AT_SOUND, sound_step->mSoundAssetID, true); + } + else if (step->getType() == STEP_ANIMATION) + { + LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step; + LLLocalInventory::addItem(anim_step->mAnimName, (int)LLAssetType::AT_ANIMATION, anim_step->mAnimAssetID, true); + } +} +// + // static void LLPreviewGesture::onClickPreview(void* data) { @@ -1784,3 +1979,64 @@ void LLPreviewGesture::onDonePreview(LLMultiGesture* gesture, void* data) self->refresh(); } + +// +// virtual +BOOL LLPreviewGesture::canSaveAs() const +{ + return TRUE; +} + +// virtual +void LLPreviewGesture::saveAs() +{ + std::string default_filename("untitled.gesture"); + const LLInventoryItem *item = getItem(); + if(item) + { + default_filename = LLDir::getScrubbedFileName(item->getName()); + } + + LLFilePicker& file_picker = LLFilePicker::instance(); + if( !file_picker.getSaveFile( LLFilePicker::FFSAVE_GESTURE, default_filename ) ) + { + // User canceled or we failed to acquire save file. + return; + } + // remember the user-approved/edited file name. + std::string filename = file_picker.getFirstFile(); + + // Copy the UI into a gesture + LLMultiGesture* gesture = createGesture(); + + // Serialize the gesture + S32 max_size = gesture->getMaxSerialSize(); + char* buffer = new char[max_size]; + LLDataPackerAsciiBuffer dp(buffer, max_size); + + if(!gesture->serialize(dp)) + { + // FIXME: Notify user + delete [] buffer; + return; + } + + S32 size = dp.getCurrentSize(); + + std::ofstream export_file(filename.c_str(), std::ofstream::binary); + export_file.write(buffer, size); + export_file.close(); + + delete [] buffer; +} + +LLUUID LLPreviewGesture::getItemID() +{ + const LLViewerInventoryItem* item = getItem(); + if(item) + { + return item->getUUID(); + } + return LLUUID::null; +} +// \ No newline at end of file diff --git a/indra/newview/llpreviewgesture.h b/indra/newview/llpreviewgesture.h index c245c0e8d..d7d297c6a 100644 --- a/indra/newview/llpreviewgesture.h +++ b/indra/newview/llpreviewgesture.h @@ -99,10 +99,24 @@ protected: void saveIfNeeded(); + // + void saveDuplicate(); + class GestureItemForDuplicateCallback : public LLInventoryCallback + { + void fire(const LLUUID& inv_item); + }; + // + static void onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status); + // + static void onSaveDuplicateComplete(const LLUUID& asset_uuid, + void* user_data, + S32 status, LLExtStat ext_status); + // + bool handleSaveChangesDialog(const LLSD& notification, const LLSD& response); // Write UI back into gesture @@ -135,12 +149,22 @@ protected: static void onCommitActive(LLUICtrl* ctrl, void* data); static void onClickSave(void* data); + // + static void onClickDuplicate(void* data); + static void onClickOpen(void* data); + virtual LLUUID getItemID(); + // static void onClickPreview(void* data); static void onDonePreview(LLMultiGesture* gesture, void* data); virtual const char *getTitleName() const { return "Gesture"; } + // + virtual BOOL canSaveAs() const; + virtual void saveAs(); + // + protected: // LLPreview contains mDescEditor LLLineEditor* mTriggerEditor; @@ -168,6 +192,10 @@ protected: LLCheckBoxCtrl* mActiveCheck; LLButton* mSaveBtn; + // + LLButton* mDuplicateBtn; + LLButton* mOpenBtn; + // LLButton* mPreviewBtn; LLMultiGesture* mPreviewGesture; diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index 897fd6a2e..3d4231c8e 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -60,6 +60,9 @@ #include "llappviewer.h" // app_abort_quit() #include "lllineeditor.h" #include "lluictrlfactory.h" +// +#include "llfilepicker.h" +// ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs @@ -108,7 +111,10 @@ LLPreviewNotecard::LLPreviewNotecard(const std::string& name, { LLUICtrlFactory::getInstance()->buildFloater(this,"floater_preview_notecard.xml"); childSetAction("Save",onClickSave,this); - + // + childSetAction("Get Items", onClickGetItems, this); + // + if( mAssetID.isNull() ) { const LLInventoryItem* item = getItem(); @@ -335,6 +341,9 @@ void LLPreviewNotecard::loadAsset() GP_OBJECT_MANIPULATE)) { editor->setEnabled(FALSE); + // You can always save in task inventory + if(!mObjectUUID.isNull()) editor->setEnabled(TRUE); + // childSetVisible("lock", TRUE); } } @@ -442,7 +451,51 @@ void LLPreviewNotecard::onClickSave(void* user_data) preview->saveIfNeeded(); } } - +// +// static +void LLPreviewNotecard::onClickGetItems(void* user_data) +{ + LLPreviewNotecard* preview = (LLPreviewNotecard*)user_data; + if(preview) + { + LLViewerTextEditor* editor = preview->getChild("Notecard Editor"); + if(editor) + { + std::vector> items = editor->getEmbeddedItems(); + if(items.size()) + { + const BOOL use_caps = FALSE; + + std::vector>::iterator iter = items.begin(); + std::vector>::iterator end = items.end(); + for( ; iter != end; ++iter) + { + LLInventoryItem* item = static_cast(*iter); + if(use_caps) + { + copy_inventory_from_notecard(preview->getObjectID(), preview->getNotecardItemID(), item, 0); + } + else + { + // Only one item per message actually works + gMessageSystem->newMessageFast(_PREHASH_CopyInventoryFromNotecard); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_NotecardData); + gMessageSystem->addUUIDFast(_PREHASH_NotecardItemID, preview->getNotecardItemID()); + gMessageSystem->addUUIDFast(_PREHASH_ObjectID, preview->getObjectID()); + gMessageSystem->nextBlockFast(_PREHASH_InventoryData); + gMessageSystem->addUUIDFast(_PREHASH_ItemID, item->getUUID()); + gMessageSystem->addUUIDFast(_PREHASH_FolderID, gInventory.findCategoryUUIDForType(item->getType())); + gAgent.sendReliableMessage(); + } + } + } + } + } +} +// struct LLSaveNotecardInfo { LLPreviewNotecard* mSelf; @@ -649,4 +702,69 @@ void LLPreviewNotecard::reshape(S32 width, S32 height, BOOL called_from_parent) } } -// EOF +// +// virtual +BOOL LLPreviewNotecard::canSaveAs() const +{ + return TRUE; +} + +// virtual +void LLPreviewNotecard::saveAs() +{ + std::string default_filename("untitled.notecard"); + const LLInventoryItem *item = getItem(); + if(item) + { + // gAssetStorage->getAssetData(item->getAssetUUID(), LLAssetType::AT_NOTECARD, LLPreviewNotecard::gotAssetForSave, this, TRUE); + default_filename = LLDir::getScrubbedFileName(item->getName()); + } + + LLFilePicker& file_picker = LLFilePicker::instance(); + if( !file_picker.getSaveFile( LLFilePicker::FFSAVE_NOTECARD, default_filename ) ) + { + // User canceled or we failed to acquire save file. + return; + } + // remember the user-approved/edited file name. + std::string filename = file_picker.getFirstFile(); + + LLViewerTextEditor* editor = getChild("Notecard Editor"); + + std::string buffer; + if (!editor->exportBuffer(buffer)) + { + // FIXME: Notify the user! + return; + } + + S32 size = buffer.length() + 1; + + std::ofstream export_file(filename.c_str(), std::ofstream::binary); + export_file.write(buffer.c_str(), size); + export_file.close(); +} + +LLUUID LLPreviewNotecard::getNotecardItemID() +{ + return mNotecardItemID; +} + +LLUUID LLPreviewNotecard::getObjectID() +{ + return mObjectID; +} + +// virtual +LLUUID LLPreviewNotecard::getItemID() +{ + const LLViewerInventoryItem* item = getItem(); + if(item) + { + return item->getUUID(); + } + return LLUUID::null; +} +// + +// EOF \ No newline at end of file diff --git a/indra/newview/llpreviewnotecard.h b/indra/newview/llpreviewnotecard.h index f5cd2bb2a..0342bdc83 100644 --- a/indra/newview/llpreviewnotecard.h +++ b/indra/newview/llpreviewnotecard.h @@ -84,6 +84,11 @@ public: // asset system. :( void refreshFromInventory(); + // + LLUUID getNotecardItemID(); + LLUUID getObjectID(); + virtual LLUUID getItemID(); + // protected: virtual void loadAsset(); @@ -97,6 +102,8 @@ protected: void* user_data, S32 status, LLExtStat ext_status); static void onClickSave(void* data); + // + static void onClickGetItems(void* data); static void onSaveComplete(const LLUUID& asset_uuid, void* user_data, @@ -114,6 +121,11 @@ protected: LLUUID mNotecardItemID; LLUUID mObjectID; + + // + virtual BOOL canSaveAs() const; + virtual void saveAs(); + // }; diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index bf3b3dc49..225e465b9 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -1684,7 +1684,39 @@ void LLPreviewLSL::reshape(S32 width, S32 height, BOOL called_from_parent) gSavedSettings.setRect("PreviewScriptRect", getRect()); } } - +// +// virtual +BOOL LLPreviewLSL::canSaveAs() const +{ + return TRUE; +} + +// virtual +void LLPreviewLSL::saveAs() +{ + std::string default_filename("untitled.lsl"); + const LLInventoryItem *item = getItem(); + if(item) + { + default_filename = LLDir::getScrubbedFileName(item->getName()); + } + + LLFilePicker& file_picker = LLFilePicker::instance(); + if( !file_picker.getSaveFile( LLFilePicker::FFSAVE_LSL, default_filename ) ) + { + // User canceled or we failed to acquire save file. + return; + } + // remember the user-approved/edited file name. + std::string filename = file_picker.getFirstFile(); + + std::string utf8text = mScriptEd->mEditor->getText(); + LLFILE* fp = LLFile::fopen(filename, "wb"); + fputs(utf8text.c_str(), fp); + fclose(fp); + fp = NULL; +} +// /// --------------------------------------------------------------------------- /// LLLiveLSLEditor /// --------------------------------------------------------------------------- diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h index 832f5bd08..6ba50652a 100644 --- a/indra/newview/llpreviewscript.h +++ b/indra/newview/llpreviewscript.h @@ -186,6 +186,10 @@ protected: void uploadAssetLegacy(const std::string& filename, const LLUUID& item_id, const LLTransactionID& tid); + // + virtual BOOL canSaveAs() const; + virtual void saveAs(); + // static void onSearchReplace(void* userdata); static void onLoad(void* userdata); diff --git a/indra/newview/llpreviewsound.cpp b/indra/newview/llpreviewsound.cpp index 0dd65ab0e..ef5400753 100644 --- a/indra/newview/llpreviewsound.cpp +++ b/indra/newview/llpreviewsound.cpp @@ -43,6 +43,15 @@ #include "llviewercontrol.h" #include "llviewermessage.h" // send_guid_sound_trigger #include "lluictrlfactory.h" +// +#include "llvoavatar.h" +#include "llchat.h" +#include "llfloaterchat.h" +#include "llviewerwindow.h" // for alert +#include "llfilepicker.h" +// for ambient play: +#include "llviewerregion.h" +// extern LLAudioEngine* gAudiop; extern LLAgent gAgent; @@ -57,6 +66,10 @@ LLPreviewSound::LLPreviewSound(const std::string& name, const LLRect& rect, cons childSetAction("Sound play btn",&LLPreviewSound::playSound,this); childSetAction("Sound audition btn",&LLPreviewSound::auditionSound,this); + // + childSetAction("Sound copy uuid btn", &LLPreviewSound::copyUUID, this); + childSetAction("Play ambient btn", &LLPreviewSound::playAmbient, this); + // LLButton* button = getChild("Sound play btn"); button->setSoundFlags(LLView::SILENT); @@ -74,6 +87,13 @@ LLPreviewSound::LLPreviewSound(const std::string& name, const LLRect& rect, cons if(item && gAudiop) { gAudiop->preloadSound(item->getAssetUUID()); + // + // that thing above doesn't actually start a sound transfer, so I will do it + //LLAudioSource *asp = new LLAudioSource(gAgent.getID(), gAgent.getID(), F32(1.0f), LLAudioEngine::AUDIO_TYPE_UI); + LLAudioSource *asp = gAgent.getAvatarObject()->getAudioSource(gAgent.getID()); + LLAudioData *datap = gAudiop->getAudioData(item->getAssetUUID()); + asp->addAudioData(datap, FALSE); + // } setTitle(title); @@ -110,3 +130,228 @@ void LLPreviewSound::auditionSound( void *userdata ) gAudiop->triggerSound(item->getAssetUUID(), gAgent.getID(), SOUND_GAIN, LLAudioEngine::AUDIO_TYPE_UI, lpos_global); } } + +// +void LLPreviewSound::playAmbient( void* userdata ) +{ + LLPreviewSound* self = (LLPreviewSound*) userdata; + const LLInventoryItem *item = self->getItem(); + + if(item && gAudiop) + { + int gain = 0.01f; + for(int i = 0; i < 2; i++) + { + gMessageSystem->newMessageFast(_PREHASH_SoundTrigger); + gMessageSystem->nextBlockFast(_PREHASH_SoundData); + gMessageSystem->addUUIDFast(_PREHASH_SoundID, LLUUID(item->getAssetUUID())); + gMessageSystem->addUUIDFast(_PREHASH_OwnerID, LLUUID::null); + gMessageSystem->addUUIDFast(_PREHASH_ObjectID, LLUUID::null); + gMessageSystem->addUUIDFast(_PREHASH_ParentID, LLUUID::null); + gMessageSystem->addU64Fast(_PREHASH_Handle, gAgent.getRegion()->getHandle()); + LLVector3d pos = -from_region_handle(gAgent.getRegion()->getHandle()); + gMessageSystem->addVector3Fast(_PREHASH_Position, (LLVector3)pos); + gMessageSystem->addF32Fast(_PREHASH_Gain, gain); + + gMessageSystem->sendReliable(gAgent.getRegionHost()); + + gain = 1.0f; + } + } +} +// +/* +struct LLSaveInfo +{ + LLSaveInfo(const LLUUID& item_id, const LLUUID& object_id, const std::string& desc, + const LLTransactionID tid) + : mItemUUID(item_id), mObjectUUID(object_id), mDesc(desc), mTransactionID(tid) + { + } + + LLUUID mItemUUID; + LLUUID mObjectUUID; + std::string mDesc; + LLTransactionID mTransactionID; +}; + +// static +void LLPreviewSound::makeCopy( void *userdata ) +{ + LLPreviewSound* self = (LLPreviewSound*) userdata; + const LLInventoryItem *item = self->getItem(); + + if(item && gAudiop) + { + // Find out if asset data is ready + // I might be able to get rid of this + if(!gAssetStorage->hasLocalAsset(item->getAssetUUID(), LLAssetType::AT_SOUND)) + { + LLChat chat("Sound isn't downloaded yet, please try again in a moment."); + LLFloaterChat::addChat(chat); + return; + } + + gAssetStorage->getAssetData(item->getAssetUUID(), LLAssetType::AT_SOUND, LLPreviewSound::gotAssetForCopy, self, TRUE); + } +} + +// static +void LLPreviewSound::gotAssetForCopy(LLVFS *vfs, + const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) +{ + LLPreviewSound* self = (LLPreviewSound*) user_data; + //const LLInventoryItem *item = self->getItem(); + + 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... + + LLTransactionID tid; + LLAssetID asset_id; + tid.generate(); + asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); + + LLVFile ofile(gVFS, asset_id, LLAssetType::AT_SOUND, LLVFile::APPEND); + + ofile.setMaxSize(size); + ofile.write((U8*)buffer, size); + + // Upload that asset to the database + LLSaveInfo* info = new LLSaveInfo(self->mItemUUID, self->mObjectUUID, "sound", tid); + gAssetStorage->storeAssetData(tid, LLAssetType::AT_SOUND, onSaveCopyComplete, info, FALSE); +} + +// static +void LLPreviewSound::onSaveCopyComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) +{ + LLSaveInfo* info = (LLSaveInfo*)user_data; + + if (status == 0) + { + std::string item_name = "New Sound"; + std::string item_desc = ""; + // Saving into user inventory + LLViewerInventoryItem* item; + item = (LLViewerInventoryItem*)gInventory.getItem(info->mItemUUID); + if(item) + { + item_name = item->getName(); + item_desc = item->getDescription(); + } + gMessageSystem->newMessageFast(_PREHASH_CreateInventoryItem); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_InventoryBlock); + gMessageSystem->addU32Fast(_PREHASH_CallbackID, 0); + gMessageSystem->addUUIDFast(_PREHASH_FolderID, LLUUID::null); + gMessageSystem->addUUIDFast(_PREHASH_TransactionID, info->mTransactionID); + gMessageSystem->addU32Fast(_PREHASH_NextOwnerMask, 2147483647); + gMessageSystem->addS8Fast(_PREHASH_Type, 1); + gMessageSystem->addS8Fast(_PREHASH_InvType, 1); + gMessageSystem->addU8Fast(_PREHASH_WearableType, 0); + gMessageSystem->addStringFast(_PREHASH_Name, item_name); + gMessageSystem->addStringFast(_PREHASH_Description, item_desc); + gMessageSystem->sendReliable(gAgent.getRegionHost()); + } + else + { + llwarns << "Problem saving sound: " << status << llendl; + LLStringUtil::format_map_t args; + args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status)); + gViewerWindow->alertXml("CannotUploadReason",args); + } +} +*/ +// static +void LLPreviewSound::copyUUID( void *userdata ) +{ + LLPreviewSound* self = (LLPreviewSound*) userdata; + const LLInventoryItem *item = self->getItem(); + + if(item ) + { + gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(item->getAssetUUID().asString())); + } +} +// + +// +// virtual +BOOL LLPreviewSound::canSaveAs() const +{ + return TRUE; +} + +// virtual +void LLPreviewSound::saveAs() +{ + const LLInventoryItem *item = getItem(); + + if(item) + { + gAssetStorage->getAssetData(item->getAssetUUID(), LLAssetType::AT_SOUND, LLPreviewSound::gotAssetForSave, this, TRUE); + } +} + +// static +void LLPreviewSound::gotAssetForSave(LLVFS *vfs, + const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) +{ + LLPreviewSound* self = (LLPreviewSound*) user_data; + //const LLInventoryItem *item = self->getItem(); + + 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( LLFilePicker::FFSAVE_OGG, LLDir::getScrubbedFileName(self->getItem()->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(); +} + +// virtual +LLUUID LLPreviewSound::getItemID() +{ + const LLViewerInventoryItem* item = getItem(); + if(item) + { + return item->getUUID(); + } + return LLUUID::null; +} +// diff --git a/indra/newview/llpreviewsound.h b/indra/newview/llpreviewsound.h index 061fbdf68..b137a1a9d 100644 --- a/indra/newview/llpreviewsound.h +++ b/indra/newview/llpreviewsound.h @@ -44,9 +44,30 @@ public: static void playSound( void* userdata ); static void auditionSound( void* userdata ); + // + /* + static void makeCopy(void* userdata); + static void gotAssetForCopy(LLVFS *vfs, + const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status); + static void onSaveCopyComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status); + */ + static void playAmbient(void* userdata); + static void copyUUID(void* userdata); + static void gotAssetForSave(LLVFS *vfs, + const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status); + // protected: virtual const char *getTitleName() const { return "Sound"; } + // + virtual BOOL canSaveAs() const; + virtual void saveAs(); + virtual LLUUID getItemID(); + // }; diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index ed94b72d6..191a9102f 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -1079,23 +1079,29 @@ BOOL LLViewerTextEditor::handleDragAndDrop(S32 x, S32 y, MASK mask, { switch( cargo_type ) { - case DAD_CALLINGCARD: - if(acceptsCallingCardNames()) - { - if (drop) - { - LLInventoryItem *item = (LLInventoryItem *)cargo_data; - std::string name = item->getName(); - appendText(name, true, true); - } - *accept = ACCEPT_YES_COPY_SINGLE; - } - else - { - *accept = ACCEPT_NO; - } - break; - + // + // This does not even appear to be used maybe + // Throwing it out so I can embed calling cards + /* + case DAD_CALLINGCARD: + if(acceptsCallingCardNames()) + { + if (drop) + { + LLInventoryItem *item = (LLInventoryItem *)cargo_data; + std::string name = item->getName(); + appendText(name, true, true); + } + *accept = ACCEPT_YES_COPY_SINGLE; + } + else + { + *accept = ACCEPT_NO; + } + break; + */ + case DAD_CALLINGCARD: + // case DAD_TEXTURE: case DAD_SOUND: case DAD_LANDMARK: @@ -1108,10 +1114,30 @@ BOOL LLViewerTextEditor::handleDragAndDrop(S32 x, S32 y, MASK mask, case DAD_GESTURE: { LLInventoryItem *item = (LLInventoryItem *)cargo_data; + // + if((item->getPermissions().getMaskOwner() & PERM_ITEM_UNRESTRICTED) != PERM_ITEM_UNRESTRICTED) + { + if(gSavedSettings.getBOOL("ForceNotecardDragCargoPermissive")) + { + item = new LLInventoryItem((LLInventoryItem *)cargo_data); + LLPermissions old = item->getPermissions(); + LLPermissions perm; + perm.init(old.getCreator(), old.getOwner(), old.getLastOwner(), old.getGroup()); + perm.setMaskBase(PERM_ITEM_UNRESTRICTED); + perm.setMaskEveryone(PERM_ITEM_UNRESTRICTED); + perm.setMaskGroup(PERM_ITEM_UNRESTRICTED); + perm.setMaskNext(PERM_ITEM_UNRESTRICTED); + perm.setMaskOwner(PERM_ITEM_UNRESTRICTED); + item->setPermissions(perm); + } + } + // if( item && allowsEmbeddedItems() ) { U32 mask_next = item->getPermissions().getMaskNextOwner(); - if((mask_next & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) + // + //if((mask_next & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) + if(((mask_next & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) || gSavedSettings.getBOOL("ForceNotecardDragCargoAcceptance")) { if( drop ) { @@ -1525,6 +1551,14 @@ bool LLViewerTextEditor::hasEmbeddedInventory() return ! mEmbeddedItemList->empty(); } +// +std::vector > LLViewerTextEditor::getEmbeddedItems() +{ + std::vector > items; + mEmbeddedItemList->getEmbeddedItemList(items); + return items; +} +// //////////////////////////////////////////////////////////////////////////// BOOL LLViewerTextEditor::importBuffer( const char* buffer, S32 length ) diff --git a/indra/newview/llviewertexteditor.h b/indra/newview/llviewertexteditor.h index c69b3f012..dd5831a3c 100644 --- a/indra/newview/llviewertexteditor.h +++ b/indra/newview/llviewertexteditor.h @@ -97,6 +97,9 @@ public: // should be changed to get a different asset id from the verifier // rather than checking if a re-load is necessary. Phoenix 2007-02-27 bool hasEmbeddedInventory(); + // + std::vector > getEmbeddedItems(); + // private: // Embedded object operations diff --git a/indra/newview/skins/default/xui/en-us/floater_preview_animation.xml b/indra/newview/skins/default/xui/en-us/floater_preview_animation.xml index 657898a2d..76c334c28 100644 --- a/indra/newview/skins/default/xui/en-us/floater_preview_animation.xml +++ b/indra/newview/skins/default/xui/en-us/floater_preview_animation.xml @@ -13,12 +13,24 @@ mouse_opaque="true" name="desc txt" v_pad="0" width="80"> Description: -