summaryrefslogtreecommitdiff
path: root/indra/newview/llpreviewnotecard.cpp
diff options
context:
space:
mode:
authorAnsariel <ansariel.hiller@phoenixviewer.com>2024-05-22 19:04:52 +0200
committerAnsariel <ansariel.hiller@phoenixviewer.com>2024-05-22 19:04:52 +0200
commit1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch)
treeab243607f74f78200787bba5b9b88f07ef1b966f /indra/newview/llpreviewnotecard.cpp
parent6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff)
parente1623bb276f83a43ce7a197e388720c05bdefe61 (diff)
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts: # autobuild.xml # indra/cmake/CMakeLists.txt # indra/cmake/GoogleMock.cmake # indra/llaudio/llaudioengine_fmodstudio.cpp # indra/llaudio/llaudioengine_fmodstudio.h # indra/llaudio/lllistener_fmodstudio.cpp # indra/llaudio/lllistener_fmodstudio.h # indra/llaudio/llstreamingaudio_fmodstudio.cpp # indra/llaudio/llstreamingaudio_fmodstudio.h # indra/llcharacter/llmultigesture.cpp # indra/llcharacter/llmultigesture.h # indra/llimage/llimage.cpp # indra/llimage/llimagepng.cpp # indra/llimage/llimageworker.cpp # indra/llimage/tests/llimageworker_test.cpp # indra/llmessage/tests/llmockhttpclient.h # indra/llprimitive/llgltfmaterial.h # indra/llrender/llfontfreetype.cpp # indra/llui/llcombobox.cpp # indra/llui/llfolderview.cpp # indra/llui/llfolderviewmodel.h # indra/llui/lllineeditor.cpp # indra/llui/lllineeditor.h # indra/llui/lltextbase.cpp # indra/llui/lltextbase.h # indra/llui/lltexteditor.cpp # indra/llui/lltextvalidate.cpp # indra/llui/lltextvalidate.h # indra/llui/lluictrl.h # indra/llui/llview.cpp # indra/llwindow/llwindowmacosx.cpp # indra/newview/app_settings/settings.xml # indra/newview/llappearancemgr.cpp # indra/newview/llappearancemgr.h # indra/newview/llavatarpropertiesprocessor.cpp # indra/newview/llavatarpropertiesprocessor.h # indra/newview/llbreadcrumbview.cpp # indra/newview/llbreadcrumbview.h # indra/newview/llbreastmotion.cpp # indra/newview/llbreastmotion.h # indra/newview/llconversationmodel.h # indra/newview/lldensityctrl.cpp # indra/newview/lldensityctrl.h # indra/newview/llface.inl # indra/newview/llfloatereditsky.cpp # indra/newview/llfloatereditwater.cpp # indra/newview/llfloateremojipicker.h # indra/newview/llfloaterimsessiontab.cpp # indra/newview/llfloaterprofiletexture.cpp # indra/newview/llfloaterprofiletexture.h # indra/newview/llgesturemgr.cpp # indra/newview/llgesturemgr.h # indra/newview/llimpanel.cpp # indra/newview/llimpanel.h # indra/newview/llinventorybridge.cpp # indra/newview/llinventorybridge.h # indra/newview/llinventoryclipboard.cpp # indra/newview/llinventoryclipboard.h # indra/newview/llinventoryfunctions.cpp # indra/newview/llinventoryfunctions.h # indra/newview/llinventorygallery.cpp # indra/newview/lllistbrowser.cpp # indra/newview/lllistbrowser.h # indra/newview/llpanelobjectinventory.cpp # indra/newview/llpanelprofile.cpp # indra/newview/llpanelprofile.h # indra/newview/llpreviewgesture.cpp # indra/newview/llsavedsettingsglue.cpp # indra/newview/llsavedsettingsglue.h # indra/newview/lltooldraganddrop.cpp # indra/newview/llurllineeditorctrl.cpp # indra/newview/llvectorperfoptions.cpp # indra/newview/llvectorperfoptions.h # indra/newview/llviewerparceloverlay.cpp # indra/newview/llviewertexlayer.cpp # indra/newview/llviewertexturelist.cpp # indra/newview/macmain.h # indra/test/test.cpp
Diffstat (limited to 'indra/newview/llpreviewnotecard.cpp')
-rw-r--r--indra/newview/llpreviewnotecard.cpp1836
1 files changed, 918 insertions, 918 deletions
diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp
index 56ceadb62f..96ba5a1d76 100644
--- a/indra/newview/llpreviewnotecard.cpp
+++ b/indra/newview/llpreviewnotecard.cpp
@@ -1,918 +1,918 @@
-/**
- * @file llpreviewnotecard.cpp
- * @brief Implementation of the notecard editor
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llpreviewnotecard.h"
-
-#include "llinventory.h"
-
-#include "llagent.h"
-#include "lldraghandle.h"
-#include "llexternaleditor.h"
-#include "llviewerwindow.h"
-#include "llbutton.h"
-#include "llfloaterreg.h"
-#include "llinventorydefines.h"
-#include "llinventorymodel.h"
-#include "lllineeditor.h"
-#include "llmd5.h"
-#include "llnotificationsutil.h"
-#include "llmd5.h"
-#include "llresmgr.h"
-#include "roles_constants.h"
-#include "llscrollbar.h"
-#include "llselectmgr.h"
-#include "lltrans.h"
-#include "llviewertexteditor.h"
-#include "llfilesystem.h"
-#include "llviewerinventory.h"
-#include "llviewerobject.h"
-#include "llviewerobjectlist.h"
-#include "llviewerregion.h"
-#include "lldir.h"
-#include "llviewerstats.h"
-#include "llviewercontrol.h" // gSavedSettings
-#include "llappviewer.h" // app_abort_quit()
-#include "lllineeditor.h"
-#include "lluictrlfactory.h"
-#include "llviewerassetupload.h"
-
-///----------------------------------------------------------------------------
-/// Class LLPreviewNotecard
-///----------------------------------------------------------------------------
-
-// Default constructor
-LLPreviewNotecard::LLPreviewNotecard(const LLSD& key) //const LLUUID& item_id,
- : LLPreview( key ),
- mLiveFile(NULL)
-{
- const LLInventoryItem *item = getItem();
- if (item)
- {
- mAssetID = item->getAssetUUID();
- }
-}
-
-LLPreviewNotecard::~LLPreviewNotecard()
-{
- delete mLiveFile;
-}
-
-bool LLPreviewNotecard::postBuild()
-{
- mEditor = getChild<LLViewerTextEditor>("Notecard Editor");
- mEditor->setNotecardInfo(mItemUUID, mObjectID, getKey());
- mEditor->makePristine();
-
- childSetAction("Save", onClickSave, this);
- getChildView("lock")->setVisible( false);
-
- childSetAction("Delete", onClickDelete, this);
- getChildView("Delete")->setEnabled(false);
-
- childSetAction("Edit", onClickEdit, this);
-
- const LLInventoryItem* item = getItem();
-
- childSetCommitCallback("desc", LLPreview::onText, this);
- if (item)
- {
- getChild<LLUICtrl>("desc")->setValue(item->getDescription());
- bool source_library = mObjectUUID.isNull() && gInventory.isObjectDescendentOf(item->getUUID(), gInventory.getLibraryRootFolderID());
- getChildView("Delete")->setEnabled(!source_library);
- }
- getChild<LLLineEditor>("desc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
-
- return LLPreview::postBuild();
-}
-
-bool LLPreviewNotecard::saveItem()
-{
- LLInventoryItem* item = gInventory.getItem(mItemUUID);
- return saveIfNeeded(item);
-}
-
-void LLPreviewNotecard::setEnabled(bool enabled)
-{
-
- LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
-
- getChildView("Notecard Editor")->setEnabled(enabled);
- getChildView("lock")->setVisible( !enabled);
- getChildView("desc")->setEnabled(enabled);
- getChildView("Save")->setEnabled(enabled && editor && (!editor->isPristine()));
-}
-
-
-void LLPreviewNotecard::draw()
-{
- LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
- bool changed = !editor->isPristine();
-
- getChildView("Save")->setEnabled(changed && getEnabled());
-
- LLPreview::draw();
-}
-
-// virtual
-bool LLPreviewNotecard::handleKeyHere(KEY key, MASK mask)
-{
- if(('S' == key) && (MASK_CONTROL == (mask & MASK_CONTROL)))
- {
- saveIfNeeded();
- return true;
- }
-
- return LLPreview::handleKeyHere(key, mask);
-}
-
-// virtual
-bool LLPreviewNotecard::canClose()
-{
- LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
-
- if(mForceClose || editor->isPristine())
- {
- return true;
- }
- else
- {
- if(!mSaveDialogShown)
- {
- mSaveDialogShown = true;
- // Bring up view-modal dialog: Save changes? Yes, No, Cancel
- LLNotificationsUtil::add("SaveChanges", LLSD(), LLSD(), boost::bind(&LLPreviewNotecard::handleSaveChangesDialog,this, _1, _2));
- }
- return false;
- }
-}
-
-/* virtual */
-void LLPreviewNotecard::setObjectID(const LLUUID& object_id)
-{
- LLPreview::setObjectID(object_id);
-
- LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
- editor->setNotecardObjectID(mObjectUUID);
- editor->makePristine();
-}
-
-const LLInventoryItem* LLPreviewNotecard::getDragItem()
-{
- LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
-
- if(editor)
- {
- return editor->getDragItem();
- }
- return NULL;
-}
-
-bool LLPreviewNotecard::hasEmbeddedInventory()
-{
- LLViewerTextEditor* editor = NULL;
- editor = getChild<LLViewerTextEditor>("Notecard Editor");
- if (!editor) return false;
- return editor->hasEmbeddedInventory();
-}
-
-void LLPreviewNotecard::refreshFromInventory(const LLUUID& new_item_id)
-{
- if (new_item_id.notNull())
- {
- mItemUUID = new_item_id;
- setKey(LLSD(new_item_id));
- }
- LL_DEBUGS() << "LLPreviewNotecard::refreshFromInventory()" << LL_ENDL;
- loadAsset();
-}
-
-void LLPreviewNotecard::updateTitleButtons()
-{
- LLPreview::updateTitleButtons();
-
- LLUICtrl* lock_btn = getChild<LLUICtrl>("lock");
- if(lock_btn->getVisible() && !isMinimized()) // lock button stays visible if floater is minimized.
- {
- LLRect lock_rc = lock_btn->getRect();
- LLRect buttons_rect = getDragHandle()->getButtonsRect();
- buttons_rect.mLeft = lock_rc.mLeft;
- getDragHandle()->setButtonsRect(buttons_rect);
- }
-}
-
-void LLPreviewNotecard::loadAsset()
-{
- // request the asset.
- const LLInventoryItem* item = getItem();
- LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
-
- if (!editor)
- return;
-
- bool fail = false;
-
- if(item)
- {
- LLPermissions perm(item->getPermissions());
- bool is_owner = gAgent.allowOperation(PERM_OWNER, perm, GP_OBJECT_MANIPULATE);
- bool allow_copy = gAgent.allowOperation(PERM_COPY, perm, GP_OBJECT_MANIPULATE);
- bool allow_modify = canModify(mObjectUUID, item);
- bool source_library = mObjectUUID.isNull() && gInventory.isObjectDescendentOf(mItemUUID, gInventory.getLibraryRootFolderID());
-
- if (allow_copy || gAgent.isGodlike())
- {
- mAssetID = item->getAssetUUID();
- if(mAssetID.isNull())
- {
- editor->setText(LLStringUtil::null);
- editor->makePristine();
- editor->setEnabled(true);
- mAssetStatus = PREVIEW_ASSET_LOADED;
- }
- else
- {
- LLHost source_sim = LLHost();
- LLSD* user_data = nullptr;
- if (mObjectUUID.notNull())
- {
- LLViewerObject *objectp = gObjectList.findObject(mObjectUUID);
- if (objectp && objectp->getRegion())
- {
- source_sim = objectp->getRegion()->getHost();
- }
- else
- {
- // The object that we're trying to look at disappeared, bail.
- LL_WARNS() << "Can't find object " << mObjectUUID << " associated with notecard." << LL_ENDL;
- mAssetID.setNull();
- editor->setText(getString("no_object"));
- editor->makePristine();
- editor->setEnabled(false);
- mAssetStatus = PREVIEW_ASSET_LOADED;
- return;
- }
- user_data = new LLSD();
- user_data->with("taskid", mObjectUUID).with("itemid", mItemUUID);
- }
- else
- {
- user_data = new LLSD(mItemUUID);
- }
-
- gAssetStorage->getInvItemAsset(source_sim,
- gAgent.getID(),
- gAgent.getSessionID(),
- item->getPermissions().getOwner(),
- mObjectUUID,
- item->getUUID(),
- item->getAssetUUID(),
- item->getType(),
- &onLoadComplete,
- (void*)user_data,
- true);
- mAssetStatus = PREVIEW_ASSET_LOADING;
- }
- }
- else
- {
- mAssetID.setNull();
- editor->setText(getString("not_allowed"));
- editor->makePristine();
- editor->setEnabled(false);
- mAssetStatus = PREVIEW_ASSET_LOADED;
- }
-
- if(!allow_modify)
- {
- editor->setEnabled(false);
- getChildView("lock")->setVisible( true);
- getChildView("Edit")->setEnabled(false);
- }
-
- if((allow_modify || is_owner) && !source_library)
- {
- getChildView("Delete")->setEnabled(true);
- }
- }
- else if (mObjectUUID.notNull() && mItemUUID.notNull())
- {
- LLViewerObject* objectp = gObjectList.findObject(mObjectUUID);
- if (objectp && (objectp->isInventoryPending() || objectp->isInventoryDirty()))
- {
- // It's a notecard in object's inventory and we failed to get it because inventory is not up to date.
- // Subscribe for callback and retry at inventoryChanged()
- registerVOInventoryListener(objectp, NULL); //removes previous listener
-
- if (objectp->isInventoryDirty())
- {
- objectp->requestInventory();
- }
- }
- else
- {
- fail = true;
- }
- }
- else
- {
- fail = true;
- }
-
- if (fail)
- {
- editor->setText(LLStringUtil::null);
- editor->makePristine();
- editor->setEnabled(true);
- // Don't set asset status here; we may not have set the item id yet
- // (e.g. when this gets called initially)
- //mAssetStatus = PREVIEW_ASSET_LOADED;
- }
-}
-
-// static
-void LLPreviewNotecard::onLoadComplete(const LLUUID& asset_uuid,
- LLAssetType::EType type,
- void* user_data, S32 status, LLExtStat ext_status)
-{
- LL_INFOS() << "LLPreviewNotecard::onLoadComplete()" << LL_ENDL;
- LLSD* floater_key = (LLSD*)user_data;
- LLPreviewNotecard* preview = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", *floater_key);
- if( preview )
- {
- if(0 == status)
- {
- LLFileSystem file(asset_uuid, type, LLFileSystem::READ);
-
- S32 file_length = file.getSize();
-
- std::vector<char> buffer(file_length+1);
- file.read((U8*)&buffer[0], file_length);
-
- // put a EOS at the end
- buffer[file_length] = 0;
-
-
- LLViewerTextEditor* previewEditor = preview->getChild<LLViewerTextEditor>("Notecard Editor");
-
- if( (file_length > 19) && !strncmp( &buffer[0], "Linden text version", 19 ) )
- {
- if( !previewEditor->importBuffer( &buffer[0], file_length+1 ) )
- {
- LL_WARNS() << "Problem importing notecard" << LL_ENDL;
- }
- }
- else
- {
- // Version 0 (just text, doesn't include version number)
- previewEditor->setText(LLStringExplicit(&buffer[0]));
- }
-
- previewEditor->makePristine();
- bool modifiable = preview->canModify(preview->mObjectID, preview->getItem());
- preview->setEnabled(modifiable);
- preview->syncExternal();
- preview->mAssetStatus = PREVIEW_ASSET_LOADED;
- }
- else
- {
- if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
- LL_ERR_FILE_EMPTY == status)
- {
- LLNotificationsUtil::add("NotecardMissing");
- }
- else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status)
- {
- LLNotificationsUtil::add("NotecardNoPermissions");
- }
- else
- {
- LLNotificationsUtil::add("UnableToLoadNotecard");
- }
-
- LL_WARNS() << "Problem loading notecard: " << status << LL_ENDL;
- preview->mAssetStatus = PREVIEW_ASSET_ERROR;
- }
- }
- delete floater_key;
-}
-
-// static
-void LLPreviewNotecard::onClickSave(void* user_data)
-{
- //LL_INFOS() << "LLPreviewNotecard::onBtnSave()" << LL_ENDL;
- LLPreviewNotecard* preview = (LLPreviewNotecard*)user_data;
- if(preview)
- {
- preview->saveIfNeeded();
- }
-}
-
-
-// static
-void LLPreviewNotecard::onClickDelete(void* user_data)
-{
- LLPreviewNotecard* preview = (LLPreviewNotecard*)user_data;
- if(preview)
- {
- preview->deleteNotecard();
- }
-}
-
-// static
-void LLPreviewNotecard::onClickEdit(void* user_data)
-{
- LLPreviewNotecard* preview = (LLPreviewNotecard*)user_data;
- if (preview)
- {
- preview->openInExternalEditor();
- }
-}
-
-struct LLSaveNotecardInfo
-{
- LLPreviewNotecard* mSelf;
- LLUUID mItemUUID;
- LLUUID mObjectUUID;
- LLTransactionID mTransactionID;
- LLPointer<LLInventoryItem> mCopyItem;
- LLSaveNotecardInfo(LLPreviewNotecard* self, const LLUUID& item_id, const LLUUID& object_id,
- const LLTransactionID& transaction_id, LLInventoryItem* copyitem) :
- mSelf(self), mItemUUID(item_id), mObjectUUID(object_id), mTransactionID(transaction_id), mCopyItem(copyitem)
- {
- }
-};
-
-void LLPreviewNotecard::finishInventoryUpload(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId)
-{
- // Update the UI with the new asset.
- LLPreviewNotecard* nc = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", LLSD(itemId));
- if (nc)
- {
- // *HACK: we have to delete the asset in the cache so
- // that the viewer will redownload it. This is only
- // really necessary if the asset had to be modified by
- // the uploader, so this can be optimized away in some
- // cases. A better design is to have a new uuid if the
- // script actually changed the asset.
- if (nc->hasEmbeddedInventory())
- {
- LLFileSystem::removeFile(newAssetId, LLAssetType::AT_NOTECARD);
- }
- if (newItemId.isNull())
- {
- nc->setAssetId(newAssetId);
- nc->refreshFromInventory();
- }
- else
- {
- nc->refreshFromInventory(newItemId);
- }
- }
-}
-
-void LLPreviewNotecard::finishTaskUpload(LLUUID itemId, LLUUID newAssetId, LLUUID taskId)
-{
-
- LLSD floater_key;
- floater_key["taskid"] = taskId;
- floater_key["itemid"] = itemId;
- LLPreviewNotecard* nc = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", floater_key);
- if (nc)
- {
- if (nc->hasEmbeddedInventory())
- {
- LLFileSystem::removeFile(newAssetId, LLAssetType::AT_NOTECARD);
- }
- nc->setAssetId(newAssetId);
- nc->refreshFromInventory();
- }
-}
-
-bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem, bool sync)
-{
- LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
-
- if(!editor)
- {
- LL_WARNS() << "Cannot get handle to the notecard editor." << LL_ENDL;
- return false;
- }
-
- if(!editor->isPristine())
- {
- std::string buffer;
- if (!editor->exportBuffer(buffer))
- {
- return false;
- }
-
- editor->makePristine();
- const LLInventoryItem* item = getItem();
- // save it out to database
- if (item)
- {
- const LLViewerRegion* region = gAgent.getRegion();
- if (!region)
- {
- LL_WARNS() << "Not connected to a region, cannot save notecard." << LL_ENDL;
- return false;
- }
- std::string agent_url = region->getCapability("UpdateNotecardAgentInventory");
- std::string task_url = region->getCapability("UpdateNotecardTaskInventory");
-
- if (!agent_url.empty() && !task_url.empty())
- {
- std::string url;
- LLResourceUploadInfo::ptr_t uploadInfo;
-
- if (mObjectUUID.isNull() && !agent_url.empty())
- {
- uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(mItemUUID, LLAssetType::AT_NOTECARD, buffer,
- [](LLUUID itemId, LLUUID newAssetId, LLUUID newItemId, LLSD) {
- LLPreviewNotecard::finishInventoryUpload(itemId, newAssetId, newItemId);
- },
- nullptr);
- url = agent_url;
- }
- else if (!mObjectUUID.isNull() && !task_url.empty())
- {
- LLUUID object_uuid(mObjectUUID);
- uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(mObjectUUID, mItemUUID, LLAssetType::AT_NOTECARD, buffer,
- [object_uuid](LLUUID itemId, LLUUID, LLUUID newAssetId, LLSD) {
- LLPreviewNotecard::finishTaskUpload(itemId, newAssetId, object_uuid);
- },
- nullptr);
- url = task_url;
- }
-
- if (!url.empty() && uploadInfo)
- {
- mAssetStatus = PREVIEW_ASSET_LOADING;
- setEnabled(false);
-
- LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
- }
-
- }
- else if (gAssetStorage)
- {
- // We need to update the asset information
- LLTransactionID tid;
- LLAssetID asset_id;
- tid.generate();
- asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
-
- LLFileSystem file(asset_id, LLAssetType::AT_NOTECARD, LLFileSystem::APPEND);
-
-
- LLSaveNotecardInfo* info = new LLSaveNotecardInfo(this, mItemUUID, mObjectUUID,
- tid, copyitem);
-
- S32 size = buffer.length() + 1;
- file.write((U8*)buffer.c_str(), size);
-
- gAssetStorage->storeAssetData(tid, LLAssetType::AT_NOTECARD,
- &onSaveComplete,
- (void*)info,
- false);
- return true;
- }
- else // !gAssetStorage
- {
- LL_WARNS() << "Not connected to an asset storage system." << LL_ENDL;
- return false;
- }
- if(mCloseAfterSave)
- {
- closeFloater();
- }
- }
- }
- return true;
-}
-
-void LLPreviewNotecard::syncExternal()
-{
- // Sync with external editor.
- std::string tmp_file = getTmpFileName();
- llstat s;
- if (LLFile::stat(tmp_file, &s) == 0) // file exists
- {
- if (mLiveFile) mLiveFile->ignoreNextUpdate();
- writeToFile(tmp_file);
- }
-}
-
-/*virtual*/
-void LLPreviewNotecard::inventoryChanged(LLViewerObject* object,
- LLInventoryObject::object_list_t* inventory,
- S32 serial_num,
- void* user_data)
-{
- removeVOInventoryListener();
- loadAsset();
-}
-
-
-void LLPreviewNotecard::deleteNotecard()
-{
- LLNotificationsUtil::add("DeleteNotecard", LLSD(), LLSD(), boost::bind(&LLPreviewNotecard::handleConfirmDeleteDialog,this, _1, _2));
-}
-
-// static
-void LLPreviewNotecard::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed)
-{
- LLSaveNotecardInfo* info = (LLSaveNotecardInfo*)user_data;
- if(info && (0 == status))
- {
- if(info->mObjectUUID.isNull())
- {
- LLViewerInventoryItem* item;
- item = (LLViewerInventoryItem*)gInventory.getItem(info->mItemUUID);
- if(item)
- {
- LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
- new_item->setAssetUUID(asset_uuid);
- new_item->setTransactionID(info->mTransactionID);
- new_item->updateServer(false);
- gInventory.updateItem(new_item);
- gInventory.notifyObservers();
- }
- else
- {
- LL_WARNS() << "Inventory item for script " << info->mItemUUID
- << " is no longer in agent inventory." << LL_ENDL;
- }
- }
- else
- {
- LLViewerObject* object = gObjectList.findObject(info->mObjectUUID);
- LLViewerInventoryItem* item = NULL;
- if(object)
- {
- item = (LLViewerInventoryItem*)object->getInventoryObject(info->mItemUUID);
- }
- if(object && item)
- {
- item->setAssetUUID(asset_uuid);
- item->setTransactionID(info->mTransactionID);
- object->updateInventory(item, TASK_INVENTORY_ITEM_KEY, false);
- dialog_refresh_all();
- }
- else
- {
- LLNotificationsUtil::add("SaveNotecardFailObjectNotFound");
- }
- }
- // Perform item copy to inventory
- if (info->mCopyItem.notNull())
- {
- LLViewerTextEditor* editor = info->mSelf->getChild<LLViewerTextEditor>("Notecard Editor");
- if (editor)
- {
- editor->copyInventory(info->mCopyItem);
- }
- }
-
- // Find our window and close it if requested.
-
- LLPreviewNotecard* previewp = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", info->mItemUUID);
- if (previewp && previewp->mCloseAfterSave)
- {
- previewp->closeFloater();
- }
- }
- else
- {
- LL_WARNS() << "Problem saving notecard: " << status << LL_ENDL;
- LLSD args;
- args["REASON"] = std::string(LLAssetStorage::getErrorString(status));
- LLNotificationsUtil::add("SaveNotecardFailReason", args);
- }
-
- std::string uuid_string;
- asset_uuid.toString(uuid_string);
- std::string filename;
- filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string) + ".tmp";
- LLFile::remove(filename);
- delete info;
-}
-
-bool LLPreviewNotecard::handleSaveChangesDialog(const LLSD& notification, const LLSD& response)
-{
- mSaveDialogShown = false;
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- switch(option)
- {
- case 0: // "Yes"
- mCloseAfterSave = true;
- LLPreviewNotecard::onClickSave((void*)this);
- break;
-
- case 1: // "No"
- mForceClose = true;
- closeFloater();
- break;
-
- case 2: // "Cancel"
- default:
- // If we were quitting, we didn't really mean it.
- LLAppViewer::instance()->abortQuit();
- break;
- }
- return false;
-}
-
-bool LLPreviewNotecard::handleConfirmDeleteDialog(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (option != 0)
- {
- // canceled
- return false;
- }
-
- if (mObjectUUID.isNull())
- {
- // move item from agent's inventory into trash
- LLViewerInventoryItem* item = gInventory.getItem(mItemUUID);
- if (item != NULL)
- {
- const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
- gInventory.changeItemParent(item, trash_id, false);
- }
- }
- else
- {
- // delete item from inventory of in-world object
- LLViewerObject* object = gObjectList.findObject(mObjectUUID);
- if(object)
- {
- LLViewerInventoryItem* item = dynamic_cast<LLViewerInventoryItem*>(object->getInventoryObject(mItemUUID));
- if (item != NULL)
- {
- object->removeInventory(mItemUUID);
- }
- }
- }
-
- // close floater, ignore unsaved changes
- mForceClose = true;
- closeFloater();
- return false;
-}
-
-void LLPreviewNotecard::openInExternalEditor()
-{
- delete mLiveFile; // deletes file
-
- // Save the notecard to a temporary file.
- std::string filename = getTmpFileName();
- writeToFile(filename);
-
- // Start watching file changes.
- mLiveFile = new LLLiveLSLFile(filename, boost::bind(&LLPreviewNotecard::onExternalChange, this, _1));
- mLiveFile->ignoreNextUpdate();
- mLiveFile->addToEventTimer();
-
- // Open it in external editor.
- {
- LLExternalEditor ed;
- LLExternalEditor::EErrorCode status;
- std::string msg;
-
- status = ed.setCommand("LL_SCRIPT_EDITOR");
- if (status != LLExternalEditor::EC_SUCCESS)
- {
- if (status == LLExternalEditor::EC_NOT_SPECIFIED) // Use custom message for this error.
- {
- msg = LLTrans::getString("ExternalEditorNotSet");
- }
- else
- {
- msg = LLExternalEditor::getErrorMessage(status);
- }
-
- LLNotificationsUtil::add("GenericAlert", LLSD().with("MESSAGE", msg));
- return;
- }
-
- status = ed.run(filename);
- if (status != LLExternalEditor::EC_SUCCESS)
- {
- msg = LLExternalEditor::getErrorMessage(status);
- LLNotificationsUtil::add("GenericAlert", LLSD().with("MESSAGE", msg));
- }
- }
-}
-
-bool LLPreviewNotecard::onExternalChange(const std::string& filename)
-{
- if (!loadNotecardText(filename))
- {
- return false;
- }
-
- // Disable sync to avoid recursive load->save->load calls.
- saveIfNeeded(NULL, false);
- return true;
-}
-
-bool LLPreviewNotecard::loadNotecardText(const std::string& filename)
-{
- if (filename.empty())
- {
- LL_WARNS() << "Empty file name" << LL_ENDL;
- return false;
- }
-
- LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/
- if (!file)
- {
- LL_WARNS() << "Error opening " << filename << LL_ENDL;
- return false;
- }
-
- // read in the whole file
- fseek(file, 0L, SEEK_END);
- size_t file_length = (size_t)ftell(file);
- fseek(file, 0L, SEEK_SET);
- char* buffer = new char[file_length + 1];
- size_t nread = fread(buffer, 1, file_length, file);
- if (nread < file_length)
- {
- LL_WARNS() << "Short read" << LL_ENDL;
- }
- buffer[nread] = '\0';
- fclose(file);
-
- std::string text = std::string(buffer);
- LLStringUtil::replaceTabsWithSpaces(text, LLTextEditor::spacesPerTab());
-
- mEditor->setText(text);
- delete[] buffer;
-
- return true;
-}
-
-bool LLPreviewNotecard::writeToFile(const std::string& filename)
-{
- LLFILE* fp = LLFile::fopen(filename, "wb");
- if (!fp)
- {
- LL_WARNS() << "Unable to write to " << filename << LL_ENDL;
- return false;
- }
-
- std::string utf8text = mEditor->getText();
-
- if (utf8text.size() == 0)
- {
- utf8text = " ";
- }
-
- fputs(utf8text.c_str(), fp);
- fclose(fp);
- return true;
-}
-
-
-std::string LLPreviewNotecard::getTmpFileName()
-{
- std::string notecard_id = mObjectID.asString() + "_" + mItemUUID.asString();
-
- // Use MD5 sum to make the file name shorter and not exceed maximum path length.
- char notecard_id_hash_str[33]; /* Flawfinder: ignore */
- LLMD5 notecard_id_hash((const U8 *)notecard_id.c_str());
- notecard_id_hash.hex_digest(notecard_id_hash_str);
-
- return std::string(LLFile::tmpdir()) + "sl_notecard_" + notecard_id_hash_str + ".txt";
-}
-
-
-// EOF
+/**
+ * @file llpreviewnotecard.cpp
+ * @brief Implementation of the notecard editor
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llpreviewnotecard.h"
+
+#include "llinventory.h"
+
+#include "llagent.h"
+#include "lldraghandle.h"
+#include "llexternaleditor.h"
+#include "llviewerwindow.h"
+#include "llbutton.h"
+#include "llfloaterreg.h"
+#include "llinventorydefines.h"
+#include "llinventorymodel.h"
+#include "lllineeditor.h"
+#include "llmd5.h"
+#include "llnotificationsutil.h"
+#include "llmd5.h"
+#include "llresmgr.h"
+#include "roles_constants.h"
+#include "llscrollbar.h"
+#include "llselectmgr.h"
+#include "lltrans.h"
+#include "llviewertexteditor.h"
+#include "llfilesystem.h"
+#include "llviewerinventory.h"
+#include "llviewerobject.h"
+#include "llviewerobjectlist.h"
+#include "llviewerregion.h"
+#include "lldir.h"
+#include "llviewerstats.h"
+#include "llviewercontrol.h" // gSavedSettings
+#include "llappviewer.h" // app_abort_quit()
+#include "lllineeditor.h"
+#include "lluictrlfactory.h"
+#include "llviewerassetupload.h"
+
+///----------------------------------------------------------------------------
+/// Class LLPreviewNotecard
+///----------------------------------------------------------------------------
+
+// Default constructor
+LLPreviewNotecard::LLPreviewNotecard(const LLSD& key) //const LLUUID& item_id,
+ : LLPreview( key ),
+ mLiveFile(NULL)
+{
+ const LLInventoryItem *item = getItem();
+ if (item)
+ {
+ mAssetID = item->getAssetUUID();
+ }
+}
+
+LLPreviewNotecard::~LLPreviewNotecard()
+{
+ delete mLiveFile;
+}
+
+bool LLPreviewNotecard::postBuild()
+{
+ mEditor = getChild<LLViewerTextEditor>("Notecard Editor");
+ mEditor->setNotecardInfo(mItemUUID, mObjectID, getKey());
+ mEditor->makePristine();
+
+ childSetAction("Save", onClickSave, this);
+ getChildView("lock")->setVisible( false);
+
+ childSetAction("Delete", onClickDelete, this);
+ getChildView("Delete")->setEnabled(false);
+
+ childSetAction("Edit", onClickEdit, this);
+
+ const LLInventoryItem* item = getItem();
+
+ childSetCommitCallback("desc", LLPreview::onText, this);
+ if (item)
+ {
+ getChild<LLUICtrl>("desc")->setValue(item->getDescription());
+ bool source_library = mObjectUUID.isNull() && gInventory.isObjectDescendentOf(item->getUUID(), gInventory.getLibraryRootFolderID());
+ getChildView("Delete")->setEnabled(!source_library);
+ }
+ getChild<LLLineEditor>("desc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
+
+ return LLPreview::postBuild();
+}
+
+bool LLPreviewNotecard::saveItem()
+{
+ LLInventoryItem* item = gInventory.getItem(mItemUUID);
+ return saveIfNeeded(item);
+}
+
+void LLPreviewNotecard::setEnabled(bool enabled)
+{
+
+ LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
+
+ getChildView("Notecard Editor")->setEnabled(enabled);
+ getChildView("lock")->setVisible( !enabled);
+ getChildView("desc")->setEnabled(enabled);
+ getChildView("Save")->setEnabled(enabled && editor && (!editor->isPristine()));
+}
+
+
+void LLPreviewNotecard::draw()
+{
+ LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
+ bool changed = !editor->isPristine();
+
+ getChildView("Save")->setEnabled(changed && getEnabled());
+
+ LLPreview::draw();
+}
+
+// virtual
+bool LLPreviewNotecard::handleKeyHere(KEY key, MASK mask)
+{
+ if(('S' == key) && (MASK_CONTROL == (mask & MASK_CONTROL)))
+ {
+ saveIfNeeded();
+ return true;
+ }
+
+ return LLPreview::handleKeyHere(key, mask);
+}
+
+// virtual
+bool LLPreviewNotecard::canClose()
+{
+ LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
+
+ if(mForceClose || editor->isPristine())
+ {
+ return true;
+ }
+ else
+ {
+ if(!mSaveDialogShown)
+ {
+ mSaveDialogShown = true;
+ // Bring up view-modal dialog: Save changes? Yes, No, Cancel
+ LLNotificationsUtil::add("SaveChanges", LLSD(), LLSD(), boost::bind(&LLPreviewNotecard::handleSaveChangesDialog,this, _1, _2));
+ }
+ return false;
+ }
+}
+
+/* virtual */
+void LLPreviewNotecard::setObjectID(const LLUUID& object_id)
+{
+ LLPreview::setObjectID(object_id);
+
+ LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
+ editor->setNotecardObjectID(mObjectUUID);
+ editor->makePristine();
+}
+
+const LLInventoryItem* LLPreviewNotecard::getDragItem()
+{
+ LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
+
+ if(editor)
+ {
+ return editor->getDragItem();
+ }
+ return NULL;
+}
+
+bool LLPreviewNotecard::hasEmbeddedInventory()
+{
+ LLViewerTextEditor* editor = NULL;
+ editor = getChild<LLViewerTextEditor>("Notecard Editor");
+ if (!editor) return false;
+ return editor->hasEmbeddedInventory();
+}
+
+void LLPreviewNotecard::refreshFromInventory(const LLUUID& new_item_id)
+{
+ if (new_item_id.notNull())
+ {
+ mItemUUID = new_item_id;
+ setKey(LLSD(new_item_id));
+ }
+ LL_DEBUGS() << "LLPreviewNotecard::refreshFromInventory()" << LL_ENDL;
+ loadAsset();
+}
+
+void LLPreviewNotecard::updateTitleButtons()
+{
+ LLPreview::updateTitleButtons();
+
+ LLUICtrl* lock_btn = getChild<LLUICtrl>("lock");
+ if(lock_btn->getVisible() && !isMinimized()) // lock button stays visible if floater is minimized.
+ {
+ LLRect lock_rc = lock_btn->getRect();
+ LLRect buttons_rect = getDragHandle()->getButtonsRect();
+ buttons_rect.mLeft = lock_rc.mLeft;
+ getDragHandle()->setButtonsRect(buttons_rect);
+ }
+}
+
+void LLPreviewNotecard::loadAsset()
+{
+ // request the asset.
+ const LLInventoryItem* item = getItem();
+ LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
+
+ if (!editor)
+ return;
+
+ bool fail = false;
+
+ if(item)
+ {
+ LLPermissions perm(item->getPermissions());
+ bool is_owner = gAgent.allowOperation(PERM_OWNER, perm, GP_OBJECT_MANIPULATE);
+ bool allow_copy = gAgent.allowOperation(PERM_COPY, perm, GP_OBJECT_MANIPULATE);
+ bool allow_modify = canModify(mObjectUUID, item);
+ bool source_library = mObjectUUID.isNull() && gInventory.isObjectDescendentOf(mItemUUID, gInventory.getLibraryRootFolderID());
+
+ if (allow_copy || gAgent.isGodlike())
+ {
+ mAssetID = item->getAssetUUID();
+ if(mAssetID.isNull())
+ {
+ editor->setText(LLStringUtil::null);
+ editor->makePristine();
+ editor->setEnabled(true);
+ mAssetStatus = PREVIEW_ASSET_LOADED;
+ }
+ else
+ {
+ LLHost source_sim = LLHost();
+ LLSD* user_data = nullptr;
+ if (mObjectUUID.notNull())
+ {
+ LLViewerObject *objectp = gObjectList.findObject(mObjectUUID);
+ if (objectp && objectp->getRegion())
+ {
+ source_sim = objectp->getRegion()->getHost();
+ }
+ else
+ {
+ // The object that we're trying to look at disappeared, bail.
+ LL_WARNS() << "Can't find object " << mObjectUUID << " associated with notecard." << LL_ENDL;
+ mAssetID.setNull();
+ editor->setText(getString("no_object"));
+ editor->makePristine();
+ editor->setEnabled(false);
+ mAssetStatus = PREVIEW_ASSET_LOADED;
+ return;
+ }
+ user_data = new LLSD();
+ user_data->with("taskid", mObjectUUID).with("itemid", mItemUUID);
+ }
+ else
+ {
+ user_data = new LLSD(mItemUUID);
+ }
+
+ gAssetStorage->getInvItemAsset(source_sim,
+ gAgent.getID(),
+ gAgent.getSessionID(),
+ item->getPermissions().getOwner(),
+ mObjectUUID,
+ item->getUUID(),
+ item->getAssetUUID(),
+ item->getType(),
+ &onLoadComplete,
+ (void*)user_data,
+ true);
+ mAssetStatus = PREVIEW_ASSET_LOADING;
+ }
+ }
+ else
+ {
+ mAssetID.setNull();
+ editor->setText(getString("not_allowed"));
+ editor->makePristine();
+ editor->setEnabled(false);
+ mAssetStatus = PREVIEW_ASSET_LOADED;
+ }
+
+ if(!allow_modify)
+ {
+ editor->setEnabled(false);
+ getChildView("lock")->setVisible( true);
+ getChildView("Edit")->setEnabled(false);
+ }
+
+ if((allow_modify || is_owner) && !source_library)
+ {
+ getChildView("Delete")->setEnabled(true);
+ }
+ }
+ else if (mObjectUUID.notNull() && mItemUUID.notNull())
+ {
+ LLViewerObject* objectp = gObjectList.findObject(mObjectUUID);
+ if (objectp && (objectp->isInventoryPending() || objectp->isInventoryDirty()))
+ {
+ // It's a notecard in object's inventory and we failed to get it because inventory is not up to date.
+ // Subscribe for callback and retry at inventoryChanged()
+ registerVOInventoryListener(objectp, NULL); //removes previous listener
+
+ if (objectp->isInventoryDirty())
+ {
+ objectp->requestInventory();
+ }
+ }
+ else
+ {
+ fail = true;
+ }
+ }
+ else
+ {
+ fail = true;
+ }
+
+ if (fail)
+ {
+ editor->setText(LLStringUtil::null);
+ editor->makePristine();
+ editor->setEnabled(true);
+ // Don't set asset status here; we may not have set the item id yet
+ // (e.g. when this gets called initially)
+ //mAssetStatus = PREVIEW_ASSET_LOADED;
+ }
+}
+
+// static
+void LLPreviewNotecard::onLoadComplete(const LLUUID& asset_uuid,
+ LLAssetType::EType type,
+ void* user_data, S32 status, LLExtStat ext_status)
+{
+ LL_INFOS() << "LLPreviewNotecard::onLoadComplete()" << LL_ENDL;
+ LLSD* floater_key = (LLSD*)user_data;
+ LLPreviewNotecard* preview = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", *floater_key);
+ if( preview )
+ {
+ if(0 == status)
+ {
+ LLFileSystem file(asset_uuid, type, LLFileSystem::READ);
+
+ S32 file_length = file.getSize();
+
+ std::vector<char> buffer(file_length+1);
+ file.read((U8*)&buffer[0], file_length);
+
+ // put a EOS at the end
+ buffer[file_length] = 0;
+
+
+ LLViewerTextEditor* previewEditor = preview->getChild<LLViewerTextEditor>("Notecard Editor");
+
+ if( (file_length > 19) && !strncmp( &buffer[0], "Linden text version", 19 ) )
+ {
+ if( !previewEditor->importBuffer( &buffer[0], file_length+1 ) )
+ {
+ LL_WARNS() << "Problem importing notecard" << LL_ENDL;
+ }
+ }
+ else
+ {
+ // Version 0 (just text, doesn't include version number)
+ previewEditor->setText(LLStringExplicit(&buffer[0]));
+ }
+
+ previewEditor->makePristine();
+ bool modifiable = preview->canModify(preview->mObjectID, preview->getItem());
+ preview->setEnabled(modifiable);
+ preview->syncExternal();
+ preview->mAssetStatus = PREVIEW_ASSET_LOADED;
+ }
+ else
+ {
+ if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
+ LL_ERR_FILE_EMPTY == status)
+ {
+ LLNotificationsUtil::add("NotecardMissing");
+ }
+ else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status)
+ {
+ LLNotificationsUtil::add("NotecardNoPermissions");
+ }
+ else
+ {
+ LLNotificationsUtil::add("UnableToLoadNotecard");
+ }
+
+ LL_WARNS() << "Problem loading notecard: " << status << LL_ENDL;
+ preview->mAssetStatus = PREVIEW_ASSET_ERROR;
+ }
+ }
+ delete floater_key;
+}
+
+// static
+void LLPreviewNotecard::onClickSave(void* user_data)
+{
+ //LL_INFOS() << "LLPreviewNotecard::onBtnSave()" << LL_ENDL;
+ LLPreviewNotecard* preview = (LLPreviewNotecard*)user_data;
+ if(preview)
+ {
+ preview->saveIfNeeded();
+ }
+}
+
+
+// static
+void LLPreviewNotecard::onClickDelete(void* user_data)
+{
+ LLPreviewNotecard* preview = (LLPreviewNotecard*)user_data;
+ if(preview)
+ {
+ preview->deleteNotecard();
+ }
+}
+
+// static
+void LLPreviewNotecard::onClickEdit(void* user_data)
+{
+ LLPreviewNotecard* preview = (LLPreviewNotecard*)user_data;
+ if (preview)
+ {
+ preview->openInExternalEditor();
+ }
+}
+
+struct LLSaveNotecardInfo
+{
+ LLPreviewNotecard* mSelf;
+ LLUUID mItemUUID;
+ LLUUID mObjectUUID;
+ LLTransactionID mTransactionID;
+ LLPointer<LLInventoryItem> mCopyItem;
+ LLSaveNotecardInfo(LLPreviewNotecard* self, const LLUUID& item_id, const LLUUID& object_id,
+ const LLTransactionID& transaction_id, LLInventoryItem* copyitem) :
+ mSelf(self), mItemUUID(item_id), mObjectUUID(object_id), mTransactionID(transaction_id), mCopyItem(copyitem)
+ {
+ }
+};
+
+void LLPreviewNotecard::finishInventoryUpload(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId)
+{
+ // Update the UI with the new asset.
+ LLPreviewNotecard* nc = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", LLSD(itemId));
+ if (nc)
+ {
+ // *HACK: we have to delete the asset in the cache so
+ // that the viewer will redownload it. This is only
+ // really necessary if the asset had to be modified by
+ // the uploader, so this can be optimized away in some
+ // cases. A better design is to have a new uuid if the
+ // script actually changed the asset.
+ if (nc->hasEmbeddedInventory())
+ {
+ LLFileSystem::removeFile(newAssetId, LLAssetType::AT_NOTECARD);
+ }
+ if (newItemId.isNull())
+ {
+ nc->setAssetId(newAssetId);
+ nc->refreshFromInventory();
+ }
+ else
+ {
+ nc->refreshFromInventory(newItemId);
+ }
+ }
+}
+
+void LLPreviewNotecard::finishTaskUpload(LLUUID itemId, LLUUID newAssetId, LLUUID taskId)
+{
+
+ LLSD floater_key;
+ floater_key["taskid"] = taskId;
+ floater_key["itemid"] = itemId;
+ LLPreviewNotecard* nc = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", floater_key);
+ if (nc)
+ {
+ if (nc->hasEmbeddedInventory())
+ {
+ LLFileSystem::removeFile(newAssetId, LLAssetType::AT_NOTECARD);
+ }
+ nc->setAssetId(newAssetId);
+ nc->refreshFromInventory();
+ }
+}
+
+bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem, bool sync)
+{
+ LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
+
+ if(!editor)
+ {
+ LL_WARNS() << "Cannot get handle to the notecard editor." << LL_ENDL;
+ return false;
+ }
+
+ if(!editor->isPristine())
+ {
+ std::string buffer;
+ if (!editor->exportBuffer(buffer))
+ {
+ return false;
+ }
+
+ editor->makePristine();
+ const LLInventoryItem* item = getItem();
+ // save it out to database
+ if (item)
+ {
+ const LLViewerRegion* region = gAgent.getRegion();
+ if (!region)
+ {
+ LL_WARNS() << "Not connected to a region, cannot save notecard." << LL_ENDL;
+ return false;
+ }
+ std::string agent_url = region->getCapability("UpdateNotecardAgentInventory");
+ std::string task_url = region->getCapability("UpdateNotecardTaskInventory");
+
+ if (!agent_url.empty() && !task_url.empty())
+ {
+ std::string url;
+ LLResourceUploadInfo::ptr_t uploadInfo;
+
+ if (mObjectUUID.isNull() && !agent_url.empty())
+ {
+ uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(mItemUUID, LLAssetType::AT_NOTECARD, buffer,
+ [](LLUUID itemId, LLUUID newAssetId, LLUUID newItemId, LLSD) {
+ LLPreviewNotecard::finishInventoryUpload(itemId, newAssetId, newItemId);
+ },
+ nullptr);
+ url = agent_url;
+ }
+ else if (!mObjectUUID.isNull() && !task_url.empty())
+ {
+ LLUUID object_uuid(mObjectUUID);
+ uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(mObjectUUID, mItemUUID, LLAssetType::AT_NOTECARD, buffer,
+ [object_uuid](LLUUID itemId, LLUUID, LLUUID newAssetId, LLSD) {
+ LLPreviewNotecard::finishTaskUpload(itemId, newAssetId, object_uuid);
+ },
+ nullptr);
+ url = task_url;
+ }
+
+ if (!url.empty() && uploadInfo)
+ {
+ mAssetStatus = PREVIEW_ASSET_LOADING;
+ setEnabled(false);
+
+ LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
+ }
+
+ }
+ else if (gAssetStorage)
+ {
+ // We need to update the asset information
+ LLTransactionID tid;
+ LLAssetID asset_id;
+ tid.generate();
+ asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
+
+ LLFileSystem file(asset_id, LLAssetType::AT_NOTECARD, LLFileSystem::APPEND);
+
+
+ LLSaveNotecardInfo* info = new LLSaveNotecardInfo(this, mItemUUID, mObjectUUID,
+ tid, copyitem);
+
+ S32 size = buffer.length() + 1;
+ file.write((U8*)buffer.c_str(), size);
+
+ gAssetStorage->storeAssetData(tid, LLAssetType::AT_NOTECARD,
+ &onSaveComplete,
+ (void*)info,
+ false);
+ return true;
+ }
+ else // !gAssetStorage
+ {
+ LL_WARNS() << "Not connected to an asset storage system." << LL_ENDL;
+ return false;
+ }
+ if(mCloseAfterSave)
+ {
+ closeFloater();
+ }
+ }
+ }
+ return true;
+}
+
+void LLPreviewNotecard::syncExternal()
+{
+ // Sync with external editor.
+ std::string tmp_file = getTmpFileName();
+ llstat s;
+ if (LLFile::stat(tmp_file, &s) == 0) // file exists
+ {
+ if (mLiveFile) mLiveFile->ignoreNextUpdate();
+ writeToFile(tmp_file);
+ }
+}
+
+/*virtual*/
+void LLPreviewNotecard::inventoryChanged(LLViewerObject* object,
+ LLInventoryObject::object_list_t* inventory,
+ S32 serial_num,
+ void* user_data)
+{
+ removeVOInventoryListener();
+ loadAsset();
+}
+
+
+void LLPreviewNotecard::deleteNotecard()
+{
+ LLNotificationsUtil::add("DeleteNotecard", LLSD(), LLSD(), boost::bind(&LLPreviewNotecard::handleConfirmDeleteDialog,this, _1, _2));
+}
+
+// static
+void LLPreviewNotecard::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed)
+{
+ LLSaveNotecardInfo* info = (LLSaveNotecardInfo*)user_data;
+ if(info && (0 == status))
+ {
+ if(info->mObjectUUID.isNull())
+ {
+ LLViewerInventoryItem* item;
+ item = (LLViewerInventoryItem*)gInventory.getItem(info->mItemUUID);
+ if(item)
+ {
+ LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
+ new_item->setAssetUUID(asset_uuid);
+ new_item->setTransactionID(info->mTransactionID);
+ new_item->updateServer(false);
+ gInventory.updateItem(new_item);
+ gInventory.notifyObservers();
+ }
+ else
+ {
+ LL_WARNS() << "Inventory item for script " << info->mItemUUID
+ << " is no longer in agent inventory." << LL_ENDL;
+ }
+ }
+ else
+ {
+ LLViewerObject* object = gObjectList.findObject(info->mObjectUUID);
+ LLViewerInventoryItem* item = NULL;
+ if(object)
+ {
+ item = (LLViewerInventoryItem*)object->getInventoryObject(info->mItemUUID);
+ }
+ if(object && item)
+ {
+ item->setAssetUUID(asset_uuid);
+ item->setTransactionID(info->mTransactionID);
+ object->updateInventory(item, TASK_INVENTORY_ITEM_KEY, false);
+ dialog_refresh_all();
+ }
+ else
+ {
+ LLNotificationsUtil::add("SaveNotecardFailObjectNotFound");
+ }
+ }
+ // Perform item copy to inventory
+ if (info->mCopyItem.notNull())
+ {
+ LLViewerTextEditor* editor = info->mSelf->getChild<LLViewerTextEditor>("Notecard Editor");
+ if (editor)
+ {
+ editor->copyInventory(info->mCopyItem);
+ }
+ }
+
+ // Find our window and close it if requested.
+
+ LLPreviewNotecard* previewp = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", info->mItemUUID);
+ if (previewp && previewp->mCloseAfterSave)
+ {
+ previewp->closeFloater();
+ }
+ }
+ else
+ {
+ LL_WARNS() << "Problem saving notecard: " << status << LL_ENDL;
+ LLSD args;
+ args["REASON"] = std::string(LLAssetStorage::getErrorString(status));
+ LLNotificationsUtil::add("SaveNotecardFailReason", args);
+ }
+
+ std::string uuid_string;
+ asset_uuid.toString(uuid_string);
+ std::string filename;
+ filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string) + ".tmp";
+ LLFile::remove(filename);
+ delete info;
+}
+
+bool LLPreviewNotecard::handleSaveChangesDialog(const LLSD& notification, const LLSD& response)
+{
+ mSaveDialogShown = false;
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ switch(option)
+ {
+ case 0: // "Yes"
+ mCloseAfterSave = true;
+ LLPreviewNotecard::onClickSave((void*)this);
+ break;
+
+ case 1: // "No"
+ mForceClose = true;
+ closeFloater();
+ break;
+
+ case 2: // "Cancel"
+ default:
+ // If we were quitting, we didn't really mean it.
+ LLAppViewer::instance()->abortQuit();
+ break;
+ }
+ return false;
+}
+
+bool LLPreviewNotecard::handleConfirmDeleteDialog(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option != 0)
+ {
+ // canceled
+ return false;
+ }
+
+ if (mObjectUUID.isNull())
+ {
+ // move item from agent's inventory into trash
+ LLViewerInventoryItem* item = gInventory.getItem(mItemUUID);
+ if (item != NULL)
+ {
+ const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ gInventory.changeItemParent(item, trash_id, false);
+ }
+ }
+ else
+ {
+ // delete item from inventory of in-world object
+ LLViewerObject* object = gObjectList.findObject(mObjectUUID);
+ if(object)
+ {
+ LLViewerInventoryItem* item = dynamic_cast<LLViewerInventoryItem*>(object->getInventoryObject(mItemUUID));
+ if (item != NULL)
+ {
+ object->removeInventory(mItemUUID);
+ }
+ }
+ }
+
+ // close floater, ignore unsaved changes
+ mForceClose = true;
+ closeFloater();
+ return false;
+}
+
+void LLPreviewNotecard::openInExternalEditor()
+{
+ delete mLiveFile; // deletes file
+
+ // Save the notecard to a temporary file.
+ std::string filename = getTmpFileName();
+ writeToFile(filename);
+
+ // Start watching file changes.
+ mLiveFile = new LLLiveLSLFile(filename, boost::bind(&LLPreviewNotecard::onExternalChange, this, _1));
+ mLiveFile->ignoreNextUpdate();
+ mLiveFile->addToEventTimer();
+
+ // Open it in external editor.
+ {
+ LLExternalEditor ed;
+ LLExternalEditor::EErrorCode status;
+ std::string msg;
+
+ status = ed.setCommand("LL_SCRIPT_EDITOR");
+ if (status != LLExternalEditor::EC_SUCCESS)
+ {
+ if (status == LLExternalEditor::EC_NOT_SPECIFIED) // Use custom message for this error.
+ {
+ msg = LLTrans::getString("ExternalEditorNotSet");
+ }
+ else
+ {
+ msg = LLExternalEditor::getErrorMessage(status);
+ }
+
+ LLNotificationsUtil::add("GenericAlert", LLSD().with("MESSAGE", msg));
+ return;
+ }
+
+ status = ed.run(filename);
+ if (status != LLExternalEditor::EC_SUCCESS)
+ {
+ msg = LLExternalEditor::getErrorMessage(status);
+ LLNotificationsUtil::add("GenericAlert", LLSD().with("MESSAGE", msg));
+ }
+ }
+}
+
+bool LLPreviewNotecard::onExternalChange(const std::string& filename)
+{
+ if (!loadNotecardText(filename))
+ {
+ return false;
+ }
+
+ // Disable sync to avoid recursive load->save->load calls.
+ saveIfNeeded(NULL, false);
+ return true;
+}
+
+bool LLPreviewNotecard::loadNotecardText(const std::string& filename)
+{
+ if (filename.empty())
+ {
+ LL_WARNS() << "Empty file name" << LL_ENDL;
+ return false;
+ }
+
+ LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/
+ if (!file)
+ {
+ LL_WARNS() << "Error opening " << filename << LL_ENDL;
+ return false;
+ }
+
+ // read in the whole file
+ fseek(file, 0L, SEEK_END);
+ size_t file_length = (size_t)ftell(file);
+ fseek(file, 0L, SEEK_SET);
+ char* buffer = new char[file_length + 1];
+ size_t nread = fread(buffer, 1, file_length, file);
+ if (nread < file_length)
+ {
+ LL_WARNS() << "Short read" << LL_ENDL;
+ }
+ buffer[nread] = '\0';
+ fclose(file);
+
+ std::string text = std::string(buffer);
+ LLStringUtil::replaceTabsWithSpaces(text, LLTextEditor::spacesPerTab());
+
+ mEditor->setText(text);
+ delete[] buffer;
+
+ return true;
+}
+
+bool LLPreviewNotecard::writeToFile(const std::string& filename)
+{
+ LLFILE* fp = LLFile::fopen(filename, "wb");
+ if (!fp)
+ {
+ LL_WARNS() << "Unable to write to " << filename << LL_ENDL;
+ return false;
+ }
+
+ std::string utf8text = mEditor->getText();
+
+ if (utf8text.size() == 0)
+ {
+ utf8text = " ";
+ }
+
+ fputs(utf8text.c_str(), fp);
+ fclose(fp);
+ return true;
+}
+
+
+std::string LLPreviewNotecard::getTmpFileName()
+{
+ std::string notecard_id = mObjectID.asString() + "_" + mItemUUID.asString();
+
+ // Use MD5 sum to make the file name shorter and not exceed maximum path length.
+ char notecard_id_hash_str[33]; /* Flawfinder: ignore */
+ LLMD5 notecard_id_hash((const U8 *)notecard_id.c_str());
+ notecard_id_hash.hex_digest(notecard_id_hash_str);
+
+ return std::string(LLFile::tmpdir()) + "sl_notecard_" + notecard_id_hash_str + ".txt";
+}
+
+
+// EOF