/indra/newview/llpreviewnotecard.cpp
C++ | 606 lines | 483 code | 71 blank | 52 comment | 67 complexity | 250c3998a00954106e049592aa22599d MD5 | raw file
Possible License(s): LGPL-2.1
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