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 "llviewercontrol.h"
00059 #include "llappviewer.h"
00060 #include "lllineeditor.h"
00061 #include "lluictrlfactory.h"
00062
00066
00067 const S32 PREVIEW_MIN_WIDTH =
00068 2 * PREVIEW_BORDER +
00069 2 * PREVIEW_BUTTON_WIDTH +
00070 PREVIEW_PAD + RESIZE_HANDLE_WIDTH +
00071 PREVIEW_PAD;
00072 const S32 PREVIEW_MIN_HEIGHT =
00073 2 * PREVIEW_BORDER +
00074 3*(20 + PREVIEW_PAD) +
00075 2 * SCROLLBAR_SIZE + 128;
00076
00080
00081
00082 LLPreviewNotecard::LLPreviewNotecard(const std::string& name,
00083 const LLRect& rect,
00084 const std::string& title,
00085 const LLUUID& item_id,
00086 const LLUUID& object_id,
00087 const LLUUID& asset_id,
00088 BOOL show_keep_discard,
00089 LLPointer<LLViewerInventoryItem> inv_item) :
00090 LLPreview(name, rect, title, item_id, object_id, TRUE,
00091 PREVIEW_MIN_WIDTH,
00092 PREVIEW_MIN_HEIGHT,
00093 inv_item),
00094 mAssetID( asset_id ),
00095 mNotecardItemID(item_id),
00096 mObjectID(object_id)
00097 {
00098 LLRect curRect = rect;
00099
00100 if (show_keep_discard)
00101 {
00102 LLUICtrlFactory::getInstance()->buildFloater(this,"floater_preview_notecard_keep_discard.xml");
00103 childSetAction("Keep",onKeepBtn,this);
00104 childSetAction("Discard",onDiscardBtn,this);
00105 }
00106 else
00107 {
00108 LLUICtrlFactory::getInstance()->buildFloater(this,"floater_preview_notecard.xml");
00109 childSetAction("Save",onClickSave,this);
00110
00111 if( mAssetID.isNull() )
00112 {
00113 const LLInventoryItem* item = getItem();
00114 if( item )
00115 {
00116 mAssetID = item->getAssetUUID();
00117 }
00118 }
00119 }
00120
00121
00122 if (!getHost())
00123 {
00124 reshape(curRect.getWidth(), curRect.getHeight(), TRUE);
00125 setRect(curRect);
00126 }
00127
00128 childSetVisible("lock", FALSE);
00129
00130 const LLInventoryItem* item = getItem();
00131
00132 childSetCommitCallback("desc", LLPreview::onText, this);
00133 if (item)
00134 childSetText("desc", item->getDescription());
00135 childSetPrevalidate("desc", &LLLineEditor::prevalidatePrintableNotPipe);
00136
00137 setTitle(title);
00138
00139 LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
00140
00141 if (editor)
00142 {
00143 editor->setWordWrap(TRUE);
00144 editor->setSourceID(item_id);
00145 editor->setHandleEditKeysDirectly(TRUE);
00146 }
00147
00148 gAgent.changeCameraToDefault();
00149 }
00150
00151 LLPreviewNotecard::~LLPreviewNotecard()
00152 {
00153 }
00154
00155 BOOL LLPreviewNotecard::postBuild()
00156 {
00157 LLViewerTextEditor *ed = getChild<LLViewerTextEditor>("Notecard Editor");
00158 if (ed)
00159 {
00160 ed->setNotecardInfo(mNotecardItemID, mObjectID);
00161 ed->makePristine();
00162 }
00163 return TRUE;
00164 }
00165
00166 bool LLPreviewNotecard::saveItem(LLPointer<LLInventoryItem>* itemptr)
00167 {
00168 LLInventoryItem* item = NULL;
00169 if (itemptr && itemptr->notNull())
00170 {
00171 item = (LLInventoryItem*)(*itemptr);
00172 }
00173 bool res = saveIfNeeded(item);
00174 if (res)
00175 {
00176 delete itemptr;
00177 }
00178 return res;
00179 }
00180
00181 void LLPreviewNotecard::setEnabled( BOOL enabled )
00182 {
00183
00184 LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
00185
00186 childSetEnabled("Notecard Editor", enabled);
00187 childSetVisible("lock", !enabled);
00188 childSetEnabled("desc", enabled);
00189 childSetEnabled("Save", enabled && editor && (!editor->isPristine()));
00190
00191 }
00192
00193
00194 void LLPreviewNotecard::draw()
00195 {
00196
00197
00198
00199
00200 LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
00201 BOOL script_changed = !editor->isPristine();
00202
00203 childSetEnabled("Save", script_changed && getEnabled());
00204
00205 LLPreview::draw();
00206 }
00207
00208
00209 BOOL LLPreviewNotecard::handleKeyHere(KEY key, MASK mask)
00210 {
00211 if(('S' == key) && (MASK_CONTROL == (mask & MASK_CONTROL)))
00212 {
00213 saveIfNeeded();
00214 return TRUE;
00215 }
00216
00217 return LLPreview::handleKeyHere(key, mask);
00218 }
00219
00220
00221 BOOL LLPreviewNotecard::canClose()
00222 {
00223 LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
00224
00225 if(mForceClose || editor->isPristine())
00226 {
00227 return TRUE;
00228 }
00229 else
00230 {
00231
00232 gViewerWindow->alertXml("SaveChanges",
00233 &LLPreviewNotecard::handleSaveChangesDialog,
00234 this);
00235
00236 return FALSE;
00237 }
00238 }
00239
00240 const LLInventoryItem* LLPreviewNotecard::getDragItem()
00241 {
00242 LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
00243
00244 if(editor)
00245 {
00246 return editor->getDragItem();
00247 }
00248 return NULL;
00249 }
00250
00251 bool LLPreviewNotecard::hasEmbeddedInventory()
00252 {
00253 LLViewerTextEditor* editor = NULL;
00254 editor = getChild<LLViewerTextEditor>("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 = getChild<LLViewerTextEditor>("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(getString("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(getString("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 = preview->getChild<LLViewerTextEditor>("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 LLViewerStats::getInstance()->incStat( LLViewerStats::ST_DOWNLOAD_FAILED );
00402
00403 if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
00404 LL_ERR_FILE_EMPTY == status)
00405 {
00406 LLNotifyBox::showXml("NotecardMissing");
00407 }
00408 else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status)
00409 {
00410 LLNotifyBox::showXml("NotecardNoPermissions");
00411 }
00412 else
00413 {
00414 LLNotifyBox::showXml("UnableToLoadNotecard");
00415 }
00416
00417 llwarns << "Problem loading notecard: " << status << llendl;
00418 preview->mAssetStatus = PREVIEW_ASSET_ERROR;
00419 }
00420 }
00421 delete item_id;
00422 }
00423
00424
00425 LLPreviewNotecard* LLPreviewNotecard::getInstance(const LLUUID& item_id)
00426 {
00427 LLPreview* instance = NULL;
00428 preview_map_t::iterator found_it = LLPreview::sInstances.find(item_id);
00429 if(found_it != LLPreview::sInstances.end())
00430 {
00431 instance = found_it->second;
00432 }
00433 return (LLPreviewNotecard*)instance;
00434 }
00435
00436
00437 void LLPreviewNotecard::onClickSave(void* user_data)
00438 {
00439
00440 LLPreviewNotecard* preview = (LLPreviewNotecard*)user_data;
00441 if(preview)
00442 {
00443 preview->saveIfNeeded();
00444 }
00445 }
00446
00447 struct LLSaveNotecardInfo
00448 {
00449 LLPreviewNotecard* mSelf;
00450 LLUUID mItemUUID;
00451 LLUUID mObjectUUID;
00452 LLTransactionID mTransactionID;
00453 LLPointer<LLInventoryItem> mCopyItem;
00454 LLSaveNotecardInfo(LLPreviewNotecard* self, const LLUUID& item_id, const LLUUID& object_id,
00455 const LLTransactionID& transaction_id, LLInventoryItem* copyitem) :
00456 mSelf(self), mItemUUID(item_id), mObjectUUID(object_id), mTransactionID(transaction_id), mCopyItem(copyitem)
00457 {
00458 }
00459 };
00460
00461 bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem)
00462 {
00463 if(!gAssetStorage)
00464 {
00465 llwarns << "Not connected to an asset storage system." << llendl;
00466 return false;
00467 }
00468
00469
00470 LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
00471
00472 if(!editor->isPristine())
00473 {
00474
00475 LLTransactionID tid;
00476 LLAssetID asset_id;
00477 tid.generate();
00478 asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
00479
00480 LLVFile file(gVFS, asset_id, LLAssetType::AT_NOTECARD, LLVFile::APPEND);
00481
00482 LLString buffer;
00483 if (!editor->exportBuffer(buffer))
00484 {
00485 return false;
00486 }
00487
00488 editor->makePristine();
00489
00490 S32 size = buffer.length() + 1;
00491 file.setMaxSize(size);
00492 file.write((U8*)buffer.c_str(), size);
00493
00494 const LLInventoryItem* item = getItem();
00495
00496 if (item)
00497 {
00498 std::string agent_url = gAgent.getRegion()->getCapability("UpdateNotecardAgentInventory");
00499 std::string task_url = gAgent.getRegion()->getCapability("UpdateNotecardTaskInventory");
00500 if (mObjectUUID.isNull() && !agent_url.empty())
00501 {
00502
00503 mAssetStatus = PREVIEW_ASSET_LOADING;
00504 setEnabled(FALSE);
00505 LLSD body;
00506 body["item_id"] = mItemUUID;
00507 llinfos << "Saving notecard " << mItemUUID
00508 << " into agent inventory via " << agent_url << llendl;
00509 LLHTTPClient::post(agent_url, body,
00510 new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD));
00511 }
00512 else if (!mObjectUUID.isNull() && !task_url.empty())
00513 {
00514
00515 mAssetStatus = PREVIEW_ASSET_LOADING;
00516 setEnabled(FALSE);
00517 LLSD body;
00518 body["task_id"] = mObjectUUID;
00519 body["item_id"] = mItemUUID;
00520 llinfos << "Saving notecard " << mItemUUID << " into task "
00521 << mObjectUUID << " via " << task_url << llendl;
00522 LLHTTPClient::post(task_url, body,
00523 new LLUpdateTaskInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD));
00524 }
00525 else if (gAssetStorage)
00526 {
00527 LLSaveNotecardInfo* info = new LLSaveNotecardInfo(this, mItemUUID, mObjectUUID,
00528 tid, copyitem);
00529 gAssetStorage->storeAssetData(tid, LLAssetType::AT_NOTECARD,
00530 &onSaveComplete,
00531 (void*)info,
00532 FALSE);
00533 }
00534 }
00535 }
00536 return true;
00537 }
00538
00539
00540 void LLPreviewNotecard::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status)
00541 {
00542 LLSaveNotecardInfo* info = (LLSaveNotecardInfo*)user_data;
00543 if(info && (0 == status))
00544 {
00545 if(info->mObjectUUID.isNull())
00546 {
00547 LLViewerInventoryItem* item;
00548 item = (LLViewerInventoryItem*)gInventory.getItem(info->mItemUUID);
00549 if(item)
00550 {
00551 LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
00552 new_item->setAssetUUID(asset_uuid);
00553 new_item->setTransactionID(info->mTransactionID);
00554 new_item->updateServer(FALSE);
00555 gInventory.updateItem(new_item);
00556 gInventory.notifyObservers();
00557 }
00558 else
00559 {
00560 llwarns << "Inventory item for script " << info->mItemUUID
00561 << " is no longer in agent inventory." << llendl;
00562 }
00563 }
00564 else
00565 {
00566 LLViewerObject* object = gObjectList.findObject(info->mObjectUUID);
00567 LLViewerInventoryItem* item = NULL;
00568 if(object)
00569 {
00570 item = (LLViewerInventoryItem*)object->getInventoryObject(info->mItemUUID);
00571 }
00572 if(object && item)
00573 {
00574 item->setAssetUUID(asset_uuid);
00575 item->setTransactionID(info->mTransactionID);
00576 object->updateInventory(item, TASK_INVENTORY_ITEM_KEY, false);
00577 dialog_refresh_all();
00578 }
00579 else
00580 {
00581 gViewerWindow->alertXml("SaveNotecardFailObjectNotFound");
00582 }
00583 }
00584
00585 if (info->mCopyItem.notNull())
00586 {
00587 LLViewerTextEditor* editor = info->mSelf->getChild<LLViewerTextEditor>("Notecard Editor");
00588 if (editor)
00589 {
00590 editor->copyInventory(info->mCopyItem);
00591 }
00592 }
00593
00594
00595 LLPreviewNotecard* previewp = (LLPreviewNotecard*)LLPreview::find(info->mItemUUID);
00596 if (previewp && previewp->mCloseAfterSave)
00597 {
00598 previewp->close();
00599 }
00600 }
00601 else
00602 {
00603 llwarns << "Problem saving notecard: " << status << llendl;
00604 LLStringBase<char>::format_map_t args;
00605 args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status));
00606 gViewerWindow->alertXml("SaveNotecardFailReason",args);
00607 }
00608
00609 char uuid_string[UUID_STR_LENGTH];
00610 asset_uuid.toString(uuid_string);
00611 char filename[LL_MAX_PATH];
00612 snprintf(filename, LL_MAX_PATH, "%s.tmp", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string).c_str());
00613 LLFile::remove(filename);
00614 delete info;
00615 }
00616
00617
00618 void LLPreviewNotecard::handleSaveChangesDialog(S32 option, void* userdata)
00619 {
00620 LLPreviewNotecard* self = (LLPreviewNotecard*)userdata;
00621 switch(option)
00622 {
00623 case 0:
00624 self->mCloseAfterSave = TRUE;
00625 LLPreviewNotecard::onClickSave((void*)self);
00626 break;
00627
00628 case 1:
00629 self->mForceClose = TRUE;
00630 self->close();
00631 break;
00632
00633 case 2:
00634 default:
00635
00636 LLAppViewer::instance()->abortQuit();
00637 break;
00638 }
00639 }
00640
00641 void LLPreviewNotecard::reshape(S32 width, S32 height, BOOL called_from_parent)
00642 {
00643 LLPreview::reshape( width, height, called_from_parent );
00644
00645 if( !isMinimized() )
00646 {
00647
00648
00649 gSavedSettings.setRect("NotecardEditorRect", getRect());
00650 }
00651 }
00652
00653