00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "llpreviewnotecard.h"
00035
00036 #include "llinventory.h"
00037
00038 #include "llagent.h"
00039 #include "llassetuploadresponders.h"
00040 #include "llviewerwindow.h"
00041 #include "llbutton.h"
00042 #include "llinventorymodel.h"
00043 #include "lllineeditor.h"
00044 #include "llnotify.h"
00045 #include "llresmgr.h"
00046 #include "roles_constants.h"
00047 #include "llscrollbar.h"
00048 #include "llselectmgr.h"
00049 #include "llviewertexteditor.h"
00050 #include "llvfile.h"
00051 #include "llviewerinventory.h"
00052 #include "llviewerobject.h"
00053 #include "llviewerobjectlist.h"
00054 #include "llviewerregion.h"
00055 #include "lldir.h"
00056
00057 #include "llviewerstats.h"
00058 #include "viewer.h"
00059 #include "lllineeditor.h"
00060 #include "llvieweruictrlfactory.h"
00061
00065
00066 const S32 PREVIEW_MIN_WIDTH =
00067 2 * PREVIEW_BORDER +
00068 2 * PREVIEW_BUTTON_WIDTH +
00069 PREVIEW_PAD + RESIZE_HANDLE_WIDTH +
00070 PREVIEW_PAD;
00071 const S32 PREVIEW_MIN_HEIGHT =
00072 2 * PREVIEW_BORDER +
00073 3*(20 + PREVIEW_PAD) +
00074 2 * SCROLLBAR_SIZE + 128;
00075
00079
00080
00081 LLPreviewNotecard::LLPreviewNotecard(const std::string& name,
00082 const LLRect& rect,
00083 const std::string& title,
00084 const LLUUID& item_id,
00085 const LLUUID& object_id,
00086 const LLUUID& asset_id,
00087 BOOL show_keep_discard,
00088 LLPointer<LLViewerInventoryItem> inv_item) :
00089 LLPreview(name, rect, title, item_id, object_id, TRUE,
00090 PREVIEW_MIN_WIDTH,
00091 PREVIEW_MIN_HEIGHT,
00092 inv_item),
00093 mAssetID( asset_id ),
00094 mNotecardItemID(item_id),
00095 mObjectID(object_id)
00096 {
00097 LLRect curRect = rect;
00098
00099 if (show_keep_discard)
00100 {
00101 gUICtrlFactory->buildFloater(this,"floater_preview_notecard_keep_discard.xml");
00102 childSetAction("Keep",onKeepBtn,this);
00103 childSetAction("Discard",onDiscardBtn,this);
00104 }
00105 else
00106 {
00107 gUICtrlFactory->buildFloater(this,"floater_preview_notecard.xml");
00108 childSetAction("Save",onClickSave,this);
00109
00110 if( mAssetID.isNull() )
00111 {
00112 const LLInventoryItem* item = getItem();
00113 if( item )
00114 {
00115 mAssetID = item->getAssetUUID();
00116 }
00117 }
00118 }
00119
00120
00121 if (!getHost())
00122 {
00123 reshape(curRect.getWidth(), curRect.getHeight(), TRUE);
00124 setRect(curRect);
00125 }
00126
00127 childSetVisible("lock", FALSE);
00128
00129 const LLInventoryItem* item = getItem();
00130
00131 childSetCommitCallback("desc", LLPreview::onText, this);
00132 if (item)
00133 childSetText("desc", item->getDescription());
00134 childSetPrevalidate("desc", &LLLineEditor::prevalidatePrintableNotPipe);
00135
00136 setTitle(title);
00137
00138 LLViewerTextEditor* editor = LLViewerUICtrlFactory::getViewerTextEditorByName(this, "Notecard Editor");
00139
00140 if (editor)
00141 {
00142 editor->setWordWrap(TRUE);
00143 editor->setSourceID(item_id);
00144 editor->setHandleEditKeysDirectly(TRUE);
00145 }
00146
00147 gAgent.changeCameraToDefault();
00148 }
00149
00150 BOOL LLPreviewNotecard::postBuild()
00151 {
00152 LLViewerTextEditor *ed = (LLViewerTextEditor *)gUICtrlFactory->getTextEditorByName(this, "Notecard Editor");
00153 if (ed)
00154 {
00155 ed->setNotecardInfo(mNotecardItemID, mObjectID);
00156 ed->makePristine();
00157 }
00158 return TRUE;
00159 }
00160
00161 bool LLPreviewNotecard::saveItem(LLPointer<LLInventoryItem>* itemptr)
00162 {
00163 LLInventoryItem* item = NULL;
00164 if (itemptr && itemptr->notNull())
00165 {
00166 item = (LLInventoryItem*)(*itemptr);
00167 }
00168 bool res = saveIfNeeded(item);
00169 if (res)
00170 {
00171 delete itemptr;
00172 }
00173 return res;
00174 }
00175
00176 void LLPreviewNotecard::setEnabled( BOOL enabled )
00177 {
00178
00179 LLViewerTextEditor* editor = LLViewerUICtrlFactory::getViewerTextEditorByName(this, "Notecard Editor");
00180
00181 childSetEnabled("Notecard Editor", enabled);
00182 childSetVisible("lock", !enabled);
00183 childSetEnabled("desc", enabled);
00184 childSetEnabled("Save", enabled && editor && (!editor->isPristine()));
00185
00186 }
00187
00188
00189 void LLPreviewNotecard::draw()
00190 {
00191
00192
00193
00194
00195 LLViewerTextEditor* editor = LLViewerUICtrlFactory::getViewerTextEditorByName(this, "Notecard Editor");
00196 BOOL script_changed = !editor->isPristine();
00197
00198 childSetEnabled("Save", script_changed && getEnabled());
00199
00200 LLPreview::draw();
00201 }
00202
00203
00204 BOOL LLPreviewNotecard::handleKeyHere(KEY key, MASK mask,
00205 BOOL called_from_parent)
00206 {
00207 if(getVisible() && getEnabled())
00208 {
00209 if(('S' == key) && (MASK_CONTROL == (mask & MASK_CONTROL)))
00210 {
00211 saveIfNeeded();
00212 return TRUE;
00213 }
00214 }
00215 return FALSE;
00216 }
00217
00218
00219 BOOL LLPreviewNotecard::canClose()
00220 {
00221 LLViewerTextEditor* editor = LLViewerUICtrlFactory::getViewerTextEditorByName(this, "Notecard Editor");
00222
00223 if(mForceClose || editor->isPristine())
00224 {
00225 return TRUE;
00226 }
00227 else
00228 {
00229
00230 gViewerWindow->alertXml("SaveChanges",
00231 &LLPreviewNotecard::handleSaveChangesDialog,
00232 this);
00233
00234 return FALSE;
00235 }
00236 }
00237
00238 const LLInventoryItem* LLPreviewNotecard::getDragItem()
00239 {
00240 LLViewerTextEditor* editor = LLViewerUICtrlFactory::getViewerTextEditorByName(this, "Notecard Editor");
00241
00242 if(editor)
00243 {
00244 return editor->getDragItem();
00245 }
00246 return NULL;
00247 }
00248
00249 bool LLPreviewNotecard::hasEmbeddedInventory()
00250 {
00251 LLViewerTextEditor* editor = NULL;
00252 editor = LLViewerUICtrlFactory::getViewerTextEditorByName(
00253 this,
00254 "Notecard Editor");
00255 if (!editor) return false;
00256 return editor->hasEmbeddedInventory();
00257 }
00258
00259 void LLPreviewNotecard::refreshFromInventory()
00260 {
00261 lldebugs << "LLPreviewNotecard::refreshFromInventory()" << llendl;
00262 loadAsset();
00263 }
00264
00265 void LLPreviewNotecard::loadAsset()
00266 {
00267
00268 const LLInventoryItem* item = getItem();
00269 LLViewerTextEditor* editor = LLViewerUICtrlFactory::getViewerTextEditorByName(this, "Notecard Editor");
00270
00271 if (!editor)
00272 return;
00273
00274
00275 if(item)
00276 {
00277 if (gAgent.allowOperation(PERM_COPY, item->getPermissions(),
00278 GP_OBJECT_MANIPULATE)
00279 || gAgent.isGodlike())
00280 {
00281 mAssetID = item->getAssetUUID();
00282 if(mAssetID.isNull())
00283 {
00284 editor->setText(LLString::null);
00285 editor->makePristine();
00286 editor->setEnabled(TRUE);
00287 mAssetStatus = PREVIEW_ASSET_LOADED;
00288 }
00289 else
00290 {
00291 LLUUID* new_uuid = new LLUUID(mItemUUID);
00292 LLHost source_sim = LLHost::invalid;
00293 if (mObjectUUID.notNull())
00294 {
00295 LLViewerObject *objectp = gObjectList.findObject(mObjectUUID);
00296 if (objectp && objectp->getRegion())
00297 {
00298 source_sim = objectp->getRegion()->getHost();
00299 }
00300 else
00301 {
00302
00303 llwarns << "Can't find object " << mObjectUUID << " associated with notecard." << llendl;
00304 mAssetID.setNull();
00305 editor->setText(childGetText("no_object"));
00306 editor->makePristine();
00307 editor->setEnabled(FALSE);
00308 mAssetStatus = PREVIEW_ASSET_LOADED;
00309 delete new_uuid;
00310 return;
00311 }
00312 }
00313 gAssetStorage->getInvItemAsset(source_sim,
00314 gAgent.getID(),
00315 gAgent.getSessionID(),
00316 item->getPermissions().getOwner(),
00317 mObjectUUID,
00318 item->getUUID(),
00319 item->getAssetUUID(),
00320 item->getType(),
00321 &onLoadComplete,
00322 (void*)new_uuid,
00323 TRUE);
00324 mAssetStatus = PREVIEW_ASSET_LOADING;
00325 }
00326 }
00327 else
00328 {
00329 mAssetID.setNull();
00330 editor->setText(childGetText("not_allowed"));
00331 editor->makePristine();
00332 editor->setEnabled(FALSE);
00333 mAssetStatus = PREVIEW_ASSET_LOADED;
00334 }
00335 if(!gAgent.allowOperation(PERM_MODIFY, item->getPermissions(),
00336 GP_OBJECT_MANIPULATE))
00337 {
00338 editor->setEnabled(FALSE);
00339 childSetVisible("lock", TRUE);
00340 }
00341 }
00342 else
00343 {
00344 editor->setText(LLString::null);
00345 editor->makePristine();
00346 editor->setEnabled(TRUE);
00347 mAssetStatus = PREVIEW_ASSET_LOADED;
00348 }
00349 }
00350
00351
00352 void LLPreviewNotecard::onLoadComplete(LLVFS *vfs,
00353 const LLUUID& asset_uuid,
00354 LLAssetType::EType type,
00355 void* user_data, S32 status, LLExtStat ext_status)
00356 {
00357 llinfos << "LLPreviewNotecard::onLoadComplete()" << llendl;
00358 LLUUID* item_id = (LLUUID*)user_data;
00359 LLPreviewNotecard* preview = LLPreviewNotecard::getInstance(*item_id);
00360 if( preview )
00361 {
00362 if(0 == status)
00363 {
00364 LLVFile file(vfs, asset_uuid, type, LLVFile::READ);
00365
00366 S32 file_length = file.getSize();
00367
00368 char* buffer = new char[file_length+1];
00369 file.read((U8*)buffer, file_length);
00370
00371
00372 buffer[file_length] = 0;
00373
00374
00375 LLViewerTextEditor* previewEditor = LLViewerUICtrlFactory::getViewerTextEditorByName(preview, "Notecard Editor");
00376
00377 if( (file_length > 19) && !strncmp( buffer, "Linden text version", 19 ) )
00378 {
00379 if( !previewEditor->importBuffer( buffer ) )
00380 {
00381 llwarns << "Problem importing notecard" << llendl;
00382 }
00383 }
00384 else
00385 {
00386
00387 previewEditor->setText(LLStringExplicit(buffer));
00388 }
00389
00390 previewEditor->makePristine();
00391
00392 const LLInventoryItem* item = preview->getItem();
00393 BOOL modifiable = item && gAgent.allowOperation(PERM_MODIFY,
00394 item->getPermissions(), GP_OBJECT_MANIPULATE);
00395 preview->setEnabled(modifiable);
00396 delete[] buffer;
00397 preview->mAssetStatus = PREVIEW_ASSET_LOADED;
00398 }
00399 else
00400 {
00401 if( gViewerStats )
00402 {
00403 gViewerStats->incStat( LLViewerStats::ST_DOWNLOAD_FAILED );
00404 }
00405
00406 if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
00407 LL_ERR_FILE_EMPTY == status)
00408 {
00409 LLNotifyBox::showXml("NotecardMissing");
00410 }
00411 else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status)
00412 {
00413 LLNotifyBox::showXml("NotecardNoPermissions");
00414 }
00415 else
00416 {
00417 LLNotifyBox::showXml("UnableToLoadNotecard");
00418 }
00419
00420 llwarns << "Problem loading notecard: " << status << llendl;
00421 preview->mAssetStatus = PREVIEW_ASSET_ERROR;
00422 }
00423 }
00424 delete item_id;
00425 }
00426
00427
00428 LLPreviewNotecard* LLPreviewNotecard::getInstance(const LLUUID& item_id)
00429 {
00430 LLPreview* instance = NULL;
00431 preview_map_t::iterator found_it = LLPreview::sInstances.find(item_id);
00432 if(found_it != LLPreview::sInstances.end())
00433 {
00434 instance = found_it->second;
00435 }
00436 return (LLPreviewNotecard*)instance;
00437 }
00438
00439
00440 void LLPreviewNotecard::onClickSave(void* user_data)
00441 {
00442
00443 LLPreviewNotecard* preview = (LLPreviewNotecard*)user_data;
00444 if(preview)
00445 {
00446 preview->saveIfNeeded();
00447 }
00448 }
00449
00450 struct LLSaveNotecardInfo
00451 {
00452 LLPreviewNotecard* mSelf;
00453 LLUUID mItemUUID;
00454 LLUUID mObjectUUID;
00455 LLTransactionID mTransactionID;
00456 LLPointer<LLInventoryItem> mCopyItem;
00457 LLSaveNotecardInfo(LLPreviewNotecard* self, const LLUUID& item_id, const LLUUID& object_id,
00458 const LLTransactionID& transaction_id, LLInventoryItem* copyitem) :
00459 mSelf(self), mItemUUID(item_id), mObjectUUID(object_id), mTransactionID(transaction_id), mCopyItem(copyitem)
00460 {
00461 }
00462 };
00463
00464 bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem)
00465 {
00466 if(!gAssetStorage)
00467 {
00468 llwarns << "Not connected to an asset storage system." << llendl;
00469 return false;
00470 }
00471
00472
00473 LLViewerTextEditor* editor = LLViewerUICtrlFactory::getViewerTextEditorByName(this, "Notecard Editor");
00474
00475 if(!editor->isPristine())
00476 {
00477
00478 LLTransactionID tid;
00479 LLAssetID asset_id;
00480 tid.generate();
00481 asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
00482
00483 LLVFile file(gVFS, asset_id, LLAssetType::AT_NOTECARD, LLVFile::APPEND);
00484
00485 LLString buffer;
00486 if (!editor->exportBuffer(buffer))
00487 {
00488 return false;
00489 }
00490
00491 editor->makePristine();
00492
00493 S32 size = buffer.length() + 1;
00494 file.setMaxSize(size);
00495 file.write((U8*)buffer.c_str(), size);
00496
00497 const LLInventoryItem* item = getItem();
00498
00499 if (item)
00500 {
00501 std::string agent_url = gAgent.getRegion()->getCapability("UpdateNotecardAgentInventory");
00502 std::string task_url = gAgent.getRegion()->getCapability("UpdateNotecardTaskInventory");
00503 if (mObjectUUID.isNull() && !agent_url.empty())
00504 {
00505
00506 mAssetStatus = PREVIEW_ASSET_LOADING;
00507 setEnabled(FALSE);
00508 LLSD body;
00509 body["item_id"] = mItemUUID;
00510 llinfos << "Saving notecard " << mItemUUID
00511 << " into agent inventory via " << agent_url << llendl;
00512 LLHTTPClient::post(agent_url, body,
00513 new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD));
00514 }
00515 else if (!mObjectUUID.isNull() && !task_url.empty())
00516 {
00517
00518 mAssetStatus = PREVIEW_ASSET_LOADING;
00519 setEnabled(FALSE);
00520 LLSD body;
00521 body["task_id"] = mObjectUUID;
00522 body["item_id"] = mItemUUID;
00523 llinfos << "Saving notecard " << mItemUUID << " into task "
00524 << mObjectUUID << " via " << task_url << llendl;
00525 LLHTTPClient::post(task_url, body,
00526 new LLUpdateTaskInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD));
00527 }
00528 else if (gAssetStorage)
00529 {
00530 LLSaveNotecardInfo* info = new LLSaveNotecardInfo(this, mItemUUID, mObjectUUID,
00531 tid, copyitem);
00532 gAssetStorage->storeAssetData(tid, LLAssetType::AT_NOTECARD,
00533 &onSaveComplete,
00534 (void*)info,
00535 FALSE);
00536 }
00537 }
00538 }
00539 return true;
00540 }
00541
00542
00543 void LLPreviewNotecard::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status)
00544 {
00545 LLSaveNotecardInfo* info = (LLSaveNotecardInfo*)user_data;
00546 if(info && (0 == status))
00547 {
00548 if(info->mObjectUUID.isNull())
00549 {
00550 LLViewerInventoryItem* item;
00551 item = (LLViewerInventoryItem*)gInventory.getItem(info->mItemUUID);
00552 if(item)
00553 {
00554 LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
00555 new_item->setAssetUUID(asset_uuid);
00556 new_item->setTransactionID(info->mTransactionID);
00557 new_item->updateServer(FALSE);
00558 gInventory.updateItem(new_item);
00559 gInventory.notifyObservers();
00560 }
00561 else
00562 {
00563 llwarns << "Inventory item for script " << info->mItemUUID
00564 << " is no longer in agent inventory." << llendl;
00565 }
00566 }
00567 else
00568 {
00569 LLViewerObject* object = gObjectList.findObject(info->mObjectUUID);
00570 LLViewerInventoryItem* item = NULL;
00571 if(object)
00572 {
00573 item = (LLViewerInventoryItem*)object->getInventoryObject(info->mItemUUID);
00574 }
00575 if(object && item)
00576 {
00577 item->setAssetUUID(asset_uuid);
00578 item->setTransactionID(info->mTransactionID);
00579 object->updateInventory(item, TASK_INVENTORY_ITEM_KEY, false);
00580 dialog_refresh_all();
00581 }
00582 else
00583 {
00584 gViewerWindow->alertXml("SaveNotecardFailObjectNotFound");
00585 }
00586 }
00587
00588 if (info->mCopyItem.notNull())
00589 {
00590 LLViewerTextEditor* editor = LLViewerUICtrlFactory::getViewerTextEditorByName(info->mSelf, "Notecard Editor");
00591 if (editor)
00592 {
00593 editor->copyInventory(info->mCopyItem);
00594 }
00595 }
00596
00597
00598 LLPreviewNotecard* previewp = (LLPreviewNotecard*)LLPreview::find(info->mItemUUID);
00599 if (previewp && previewp->mCloseAfterSave)
00600 {
00601 previewp->close();
00602 }
00603 }
00604 else
00605 {
00606 llwarns << "Problem saving notecard: " << status << llendl;
00607 LLStringBase<char>::format_map_t args;
00608 args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status));
00609 gViewerWindow->alertXml("SaveNotecardFailReason",args);
00610 }
00611
00612 char uuid_string[UUID_STR_LENGTH];
00613 asset_uuid.toString(uuid_string);
00614 char filename[LL_MAX_PATH];
00615 snprintf(filename, LL_MAX_PATH, "%s.tmp", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string).c_str());
00616 LLFile::remove(filename);
00617 delete info;
00618 }
00619
00620
00621 void LLPreviewNotecard::handleSaveChangesDialog(S32 option, void* userdata)
00622 {
00623 LLPreviewNotecard* self = (LLPreviewNotecard*)userdata;
00624 switch(option)
00625 {
00626 case 0:
00627 self->mCloseAfterSave = TRUE;
00628 LLPreviewNotecard::onClickSave((void*)self);
00629 break;
00630
00631 case 1:
00632 self->mForceClose = TRUE;
00633 self->close();
00634 break;
00635
00636 case 2:
00637 default:
00638
00639 app_abort_quit();
00640 break;
00641 }
00642 }
00643
00644 void LLPreviewNotecard::reshape(S32 width, S32 height, BOOL called_from_parent)
00645 {
00646 LLPreview::reshape( width, height, called_from_parent );
00647
00648 if( !isMinimized() )
00649 {
00650
00651
00652 gSavedSettings.setRect("NotecardEditorRect", mRect);
00653 }
00654 }
00655
00656