diff options
| author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 21:25:21 +0200 |
|---|---|---|
| committer | Andrey Lihatskiy <alihatskiy@productengine.com> | 2024-05-22 22:40:26 +0300 |
| commit | e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 (patch) | |
| tree | 1bb897489ce524986f6196201c10ac0d8861aa5f /indra/newview/llpreviewnotecard.cpp | |
| parent | 069ea06848f766466f1a281144c82a0f2bd79f3a (diff) | |
Fix line endlings
Diffstat (limited to 'indra/newview/llpreviewnotecard.cpp')
| -rw-r--r-- | indra/newview/llpreviewnotecard.cpp | 1836 |
1 files changed, 918 insertions, 918 deletions
diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index 96ba5a1d76..6fa9c59194 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 |
