PageRenderTime 96ms CodeModel.GetById 20ms app.highlight 60ms RepoModel.GetById 1ms app.codeStats 7ms

/indra/newview/llpreviewnotecard.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 606 lines | 483 code | 71 blank | 52 comment | 67 complexity | 250c3998a00954106e049592aa22599d MD5 | raw file
  1/** 
  2 * @file llpreviewnotecard.cpp
  3 * @brief Implementation of the notecard editor
  4 *
  5 * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include "llviewerprecompiledheaders.h"
 28
 29#include "llpreviewnotecard.h"
 30
 31#include "llinventory.h"
 32#include "llinventoryfunctions.h" // for change_item_parent()
 33
 34#include "llagent.h"
 35#include "llassetuploadresponders.h"
 36#include "lldraghandle.h"
 37#include "llviewerwindow.h"
 38#include "llbutton.h"
 39#include "llfloaterreg.h"
 40#include "llinventorydefines.h"
 41#include "llinventorymodel.h"
 42#include "lllineeditor.h"
 43#include "llnotificationsutil.h"
 44#include "llresmgr.h"
 45#include "roles_constants.h"
 46#include "llscrollbar.h"
 47#include "llselectmgr.h"
 48#include "llviewertexteditor.h"
 49#include "llvfile.h"
 50#include "llviewerinventory.h"
 51#include "llviewerobject.h"
 52#include "llviewerobjectlist.h"
 53#include "llviewerregion.h"
 54#include "lldir.h"
 55#include "llviewerstats.h"
 56#include "llviewercontrol.h"		// gSavedSettings
 57#include "llappviewer.h"		// app_abort_quit()
 58#include "lllineeditor.h"
 59#include "lluictrlfactory.h"
 60
 61///----------------------------------------------------------------------------
 62/// Class LLPreviewNotecard
 63///----------------------------------------------------------------------------
 64
 65// Default constructor
 66LLPreviewNotecard::LLPreviewNotecard(const LLSD& key) //const LLUUID& item_id, 
 67	: LLPreview( key )
 68{
 69	const LLInventoryItem *item = getItem();
 70	if (item)
 71	{
 72		mAssetID = item->getAssetUUID();
 73	}	
 74}
 75
 76LLPreviewNotecard::~LLPreviewNotecard()
 77{
 78}
 79
 80BOOL LLPreviewNotecard::postBuild()
 81{
 82	LLViewerTextEditor *ed = getChild<LLViewerTextEditor>("Notecard Editor");
 83	ed->setNotecardInfo(mItemUUID, mObjectID, getKey());
 84	ed->makePristine();
 85
 86	childSetAction("Save", onClickSave, this);
 87	getChildView("lock")->setVisible( FALSE);	
 88
 89	childSetAction("Delete", onClickDelete, this);
 90	getChildView("Delete")->setEnabled(false);
 91
 92	const LLInventoryItem* item = getItem();
 93
 94	childSetCommitCallback("desc", LLPreview::onText, this);
 95	if (item)
 96	{
 97		getChild<LLUICtrl>("desc")->setValue(item->getDescription());
 98		getChildView("Delete")->setEnabled(true);
 99	}
100	getChild<LLLineEditor>("desc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
101
102	return LLPreview::postBuild();
103}
104
105bool LLPreviewNotecard::saveItem()
106{
107	LLInventoryItem* item = gInventory.getItem(mItemUUID);
108	return saveIfNeeded(item);
109}
110
111void LLPreviewNotecard::setEnabled( BOOL enabled )
112{
113
114	LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
115
116	getChildView("Notecard Editor")->setEnabled(enabled);
117	getChildView("lock")->setVisible( !enabled);
118	getChildView("desc")->setEnabled(enabled);
119	getChildView("Save")->setEnabled(enabled && editor && (!editor->isPristine()));
120}
121
122
123void LLPreviewNotecard::draw()
124{
125	LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
126	BOOL changed = !editor->isPristine();
127
128	getChildView("Save")->setEnabled(changed && getEnabled());
129	
130	LLPreview::draw();
131}
132
133// virtual
134BOOL LLPreviewNotecard::handleKeyHere(KEY key, MASK mask)
135{
136	if(('S' == key) && (MASK_CONTROL == (mask & MASK_CONTROL)))
137	{
138		saveIfNeeded();
139		return TRUE;
140	}
141
142	return LLPreview::handleKeyHere(key, mask);
143}
144
145// virtual
146BOOL LLPreviewNotecard::canClose()
147{
148	LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
149
150	if(mForceClose || editor->isPristine())
151	{
152		return TRUE;
153	}
154	else
155	{
156		// Bring up view-modal dialog: Save changes? Yes, No, Cancel
157		LLNotificationsUtil::add("SaveChanges", LLSD(), LLSD(), boost::bind(&LLPreviewNotecard::handleSaveChangesDialog,this, _1, _2));
158								  
159		return FALSE;
160	}
161}
162
163const LLInventoryItem* LLPreviewNotecard::getDragItem()
164{
165	LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
166
167	if(editor)
168	{
169		return editor->getDragItem();
170	}
171	return NULL;
172}
173
174bool LLPreviewNotecard::hasEmbeddedInventory()
175{
176	LLViewerTextEditor* editor = NULL;
177	editor = getChild<LLViewerTextEditor>("Notecard Editor");
178	if (!editor) return false;
179	return editor->hasEmbeddedInventory();
180}
181
182void LLPreviewNotecard::refreshFromInventory(const LLUUID& new_item_id)
183{
184	if (new_item_id.notNull())
185	{
186		mItemUUID = new_item_id;
187		setKey(LLSD(new_item_id));
188	}
189	lldebugs << "LLPreviewNotecard::refreshFromInventory()" << llendl;
190	loadAsset();
191}
192
193void LLPreviewNotecard::updateTitleButtons()
194{
195	LLPreview::updateTitleButtons();
196
197	LLUICtrl* lock_btn = getChild<LLUICtrl>("lock");
198	if(lock_btn->getVisible() && !isMinimized()) // lock button stays visible if floater is minimized.
199	{
200		LLRect lock_rc = lock_btn->getRect();
201		LLRect buttons_rect = getDragHandle()->getButtonsRect();
202		buttons_rect.mLeft = lock_rc.mLeft;
203		getDragHandle()->setButtonsRect(buttons_rect);
204	}
205}
206
207void LLPreviewNotecard::loadAsset()
208{
209	// request the asset.
210	const LLInventoryItem* item = getItem();
211	LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
212
213	if (!editor)
214		return;
215
216
217	if(item)
218	{
219		if (gAgent.allowOperation(PERM_COPY, item->getPermissions(),
220									GP_OBJECT_MANIPULATE)
221			|| gAgent.isGodlike())
222		{
223			mAssetID = item->getAssetUUID();
224			if(mAssetID.isNull())
225			{
226				editor->setText(LLStringUtil::null);
227				editor->makePristine();
228				editor->setEnabled(TRUE);
229				mAssetStatus = PREVIEW_ASSET_LOADED;
230			}
231			else
232			{
233				LLHost source_sim = LLHost::invalid;
234				if (mObjectUUID.notNull())
235				{
236					LLViewerObject *objectp = gObjectList.findObject(mObjectUUID);
237					if (objectp && objectp->getRegion())
238					{
239						source_sim = objectp->getRegion()->getHost();
240					}
241					else
242					{
243						// The object that we're trying to look at disappeared, bail.
244						llwarns << "Can't find object " << mObjectUUID << " associated with notecard." << llendl;
245						mAssetID.setNull();
246						editor->setText(getString("no_object"));
247						editor->makePristine();
248						editor->setEnabled(FALSE);
249						mAssetStatus = PREVIEW_ASSET_LOADED;
250						return;
251					}
252				}
253				gAssetStorage->getInvItemAsset(source_sim,
254												gAgent.getID(),
255												gAgent.getSessionID(),
256												item->getPermissions().getOwner(),
257												mObjectUUID,
258												item->getUUID(),
259												item->getAssetUUID(),
260												item->getType(),
261												&onLoadComplete,
262												(void*)new LLUUID(mItemUUID),
263												TRUE);
264				mAssetStatus = PREVIEW_ASSET_LOADING;
265			}
266		}
267		else
268		{
269			mAssetID.setNull();
270			editor->setText(getString("not_allowed"));
271			editor->makePristine();
272			editor->setEnabled(FALSE);
273			mAssetStatus = PREVIEW_ASSET_LOADED;
274		}
275		if(!gAgent.allowOperation(PERM_MODIFY, item->getPermissions(),
276								GP_OBJECT_MANIPULATE))
277		{
278			editor->setEnabled(FALSE);
279			getChildView("lock")->setVisible( TRUE);
280		}
281	}
282	else
283	{
284		editor->setText(LLStringUtil::null);
285		editor->makePristine();
286		editor->setEnabled(TRUE);
287		// Don't set asset status here; we may not have set the item id yet
288		// (e.g. when this gets called initially)
289		//mAssetStatus = PREVIEW_ASSET_LOADED;
290	}
291}
292
293// static
294void LLPreviewNotecard::onLoadComplete(LLVFS *vfs,
295									   const LLUUID& asset_uuid,
296									   LLAssetType::EType type,
297									   void* user_data, S32 status, LLExtStat ext_status)
298{
299	llinfos << "LLPreviewNotecard::onLoadComplete()" << llendl;
300	LLUUID* item_id = (LLUUID*)user_data;
301	
302	LLPreviewNotecard* preview = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", LLSD(*item_id));
303	if( preview )
304	{
305		if(0 == status)
306		{
307			LLVFile file(vfs, asset_uuid, type, LLVFile::READ);
308
309			S32 file_length = file.getSize();
310
311			std::vector<char> buffer(file_length+1);
312			file.read((U8*)&buffer[0], file_length);
313
314			// put a EOS at the end
315			buffer[file_length] = 0;
316
317			
318			LLViewerTextEditor* previewEditor = preview->getChild<LLViewerTextEditor>("Notecard Editor");
319
320			if( (file_length > 19) && !strncmp( &buffer[0], "Linden text version", 19 ) )
321			{
322				if( !previewEditor->importBuffer( &buffer[0], file_length+1 ) )
323				{
324					llwarns << "Problem importing notecard" << llendl;
325				}
326			}
327			else
328			{
329				// Version 0 (just text, doesn't include version number)
330				previewEditor->setText(LLStringExplicit(&buffer[0]));
331			}
332
333			previewEditor->makePristine();
334
335			const LLInventoryItem* item = preview->getItem();
336			BOOL modifiable = item && gAgent.allowOperation(PERM_MODIFY,
337								item->getPermissions(), GP_OBJECT_MANIPULATE);
338			preview->setEnabled(modifiable);
339			preview->mAssetStatus = PREVIEW_ASSET_LOADED;
340		}
341		else
342		{
343			LLViewerStats::getInstance()->incStat( LLViewerStats::ST_DOWNLOAD_FAILED );
344
345			if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
346				LL_ERR_FILE_EMPTY == status)
347			{
348				LLNotificationsUtil::add("NotecardMissing");
349			}
350			else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status)
351			{
352				LLNotificationsUtil::add("NotecardNoPermissions");
353			}
354			else
355			{
356				LLNotificationsUtil::add("UnableToLoadNotecard");
357			}
358
359			llwarns << "Problem loading notecard: " << status << llendl;
360			preview->mAssetStatus = PREVIEW_ASSET_ERROR;
361		}
362	}
363	delete item_id;
364}
365
366// static
367void LLPreviewNotecard::onClickSave(void* user_data)
368{
369	//llinfos << "LLPreviewNotecard::onBtnSave()" << llendl;
370	LLPreviewNotecard* preview = (LLPreviewNotecard*)user_data;
371	if(preview)
372	{
373		preview->saveIfNeeded();
374	}
375}
376
377
378// static
379void LLPreviewNotecard::onClickDelete(void* user_data)
380{
381	LLPreviewNotecard* preview = (LLPreviewNotecard*)user_data;
382	if(preview)
383	{
384		preview->deleteNotecard();
385	}
386}
387
388struct LLSaveNotecardInfo
389{
390	LLPreviewNotecard* mSelf;
391	LLUUID mItemUUID;
392	LLUUID mObjectUUID;
393	LLTransactionID mTransactionID;
394	LLPointer<LLInventoryItem> mCopyItem;
395	LLSaveNotecardInfo(LLPreviewNotecard* self, const LLUUID& item_id, const LLUUID& object_id,
396					   const LLTransactionID& transaction_id, LLInventoryItem* copyitem) :
397		mSelf(self), mItemUUID(item_id), mObjectUUID(object_id), mTransactionID(transaction_id), mCopyItem(copyitem)
398	{
399	}
400};
401
402bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem)
403{
404	LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
405
406	if(!editor)
407	{
408		llwarns << "Cannot get handle to the notecard editor." << llendl;
409		return false;
410	}
411
412	if(!editor->isPristine())
413	{
414		// We need to update the asset information
415		LLTransactionID tid;
416		LLAssetID asset_id;
417		tid.generate();
418		asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
419
420		LLVFile file(gVFS, asset_id, LLAssetType::AT_NOTECARD, LLVFile::APPEND);
421
422		std::string buffer;
423		if (!editor->exportBuffer(buffer))
424		{
425			return false;
426		}
427
428		editor->makePristine();
429
430		S32 size = buffer.length() + 1;
431		file.setMaxSize(size);
432		file.write((U8*)buffer.c_str(), size);
433
434		const LLInventoryItem* item = getItem();
435		// save it out to database
436		if (item)
437		{			
438			const LLViewerRegion* region = gAgent.getRegion();
439			if (!region)
440			{
441				llwarns << "Not connected to a region, cannot save notecard." << llendl;
442				return false;
443			}
444			std::string agent_url = region->getCapability("UpdateNotecardAgentInventory");
445			std::string task_url = region->getCapability("UpdateNotecardTaskInventory");
446
447			if (mObjectUUID.isNull() && !agent_url.empty())
448			{
449				// Saving into agent inventory
450				mAssetStatus = PREVIEW_ASSET_LOADING;
451				setEnabled(FALSE);
452				LLSD body;
453				body["item_id"] = mItemUUID;
454				llinfos << "Saving notecard " << mItemUUID
455					<< " into agent inventory via " << agent_url << llendl;
456				LLHTTPClient::post(agent_url, body,
457					new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD));
458			}
459			else if (!mObjectUUID.isNull() && !task_url.empty())
460			{
461				// Saving into task inventory
462				mAssetStatus = PREVIEW_ASSET_LOADING;
463				setEnabled(FALSE);
464				LLSD body;
465				body["task_id"] = mObjectUUID;
466				body["item_id"] = mItemUUID;
467				llinfos << "Saving notecard " << mItemUUID << " into task "
468					<< mObjectUUID << " via " << task_url << llendl;
469				LLHTTPClient::post(task_url, body,
470					new LLUpdateTaskInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD));
471			}
472			else if (gAssetStorage)
473			{
474				LLSaveNotecardInfo* info = new LLSaveNotecardInfo(this, mItemUUID, mObjectUUID,
475																tid, copyitem);
476				gAssetStorage->storeAssetData(tid, LLAssetType::AT_NOTECARD,
477												&onSaveComplete,
478												(void*)info,
479												FALSE);
480			}
481			else // !gAssetStorage
482			{
483				llwarns << "Not connected to an asset storage system." << llendl;
484				return false;
485			}
486		}
487	}
488	return true;
489}
490
491void LLPreviewNotecard::deleteNotecard()
492{
493	LLViewerInventoryItem* item = gInventory.getItem(mItemUUID);
494	if (item != NULL)
495	{
496		const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
497		change_item_parent(&gInventory, item, trash_id, FALSE);
498	}
499
500	closeFloater();
501}
502
503// static
504void LLPreviewNotecard::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed)
505{
506	LLSaveNotecardInfo* info = (LLSaveNotecardInfo*)user_data;
507	if(info && (0 == status))
508	{
509		if(info->mObjectUUID.isNull())
510		{
511			LLViewerInventoryItem* item;
512			item = (LLViewerInventoryItem*)gInventory.getItem(info->mItemUUID);
513			if(item)
514			{
515				LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
516				new_item->setAssetUUID(asset_uuid);
517				new_item->setTransactionID(info->mTransactionID);
518				new_item->updateServer(FALSE);
519				gInventory.updateItem(new_item);
520				gInventory.notifyObservers();
521			}
522			else
523			{
524				llwarns << "Inventory item for script " << info->mItemUUID
525						<< " is no longer in agent inventory." << llendl;
526			}
527		}
528		else
529		{
530			LLViewerObject* object = gObjectList.findObject(info->mObjectUUID);
531			LLViewerInventoryItem* item = NULL;
532			if(object)
533			{
534				item = (LLViewerInventoryItem*)object->getInventoryObject(info->mItemUUID);
535			}
536			if(object && item)
537			{
538				item->setAssetUUID(asset_uuid);
539				item->setTransactionID(info->mTransactionID);
540				object->updateInventory(item, TASK_INVENTORY_ITEM_KEY, false);
541				dialog_refresh_all();
542			}
543			else
544			{
545				LLNotificationsUtil::add("SaveNotecardFailObjectNotFound");
546			}
547		}
548		// Perform item copy to inventory
549		if (info->mCopyItem.notNull())
550		{
551			LLViewerTextEditor* editor = info->mSelf->getChild<LLViewerTextEditor>("Notecard Editor");
552			if (editor)
553			{
554				editor->copyInventory(info->mCopyItem);
555			}
556		}
557		
558		// Find our window and close it if requested.
559
560		LLPreviewNotecard* previewp = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", info->mItemUUID);
561		if (previewp && previewp->mCloseAfterSave)
562		{
563			previewp->closeFloater();
564		}
565	}
566	else
567	{
568		llwarns << "Problem saving notecard: " << status << llendl;
569		LLSD args;
570		args["REASON"] = std::string(LLAssetStorage::getErrorString(status));
571		LLNotificationsUtil::add("SaveNotecardFailReason", args);
572	}
573
574	std::string uuid_string;
575	asset_uuid.toString(uuid_string);
576	std::string filename;
577	filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string) + ".tmp";
578	LLFile::remove(filename);
579	delete info;
580}
581
582bool LLPreviewNotecard::handleSaveChangesDialog(const LLSD& notification, const LLSD& response)
583{
584	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
585	switch(option)
586	{
587	case 0:  // "Yes"
588		mCloseAfterSave = TRUE;
589		LLPreviewNotecard::onClickSave((void*)this);
590		break;
591
592	case 1:  // "No"
593		mForceClose = TRUE;
594		closeFloater();
595		break;
596
597	case 2: // "Cancel"
598	default:
599		// If we were quitting, we didn't really mean it.
600		LLAppViewer::instance()->abortQuit();
601		break;
602	}
603	return false;
604}
605
606// EOF