aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llinventorybridge.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llinventorybridge.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to '')
-rw-r--r--linden/indra/newview/llinventorybridge.cpp4426
1 files changed, 4426 insertions, 0 deletions
diff --git a/linden/indra/newview/llinventorybridge.cpp b/linden/indra/newview/llinventorybridge.cpp
new file mode 100644
index 0000000..a7628d7
--- /dev/null
+++ b/linden/indra/newview/llinventorybridge.cpp
@@ -0,0 +1,4426 @@
1/**
2 * @file llinventorybridge.cpp
3 * @brief Implementation of the Inventory-Folder-View-Bridge classes.
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "llviewerprecompiledheaders.h"
29
30#include <utility> // for std::pair<>
31
32#include "llinventoryview.h"
33#include "llinventorybridge.h"
34
35#include "message.h"
36
37#include "llagent.h"
38#include "llcallingcard.h"
39#include "llcheckboxctrl.h" // for radio buttons
40#include "llradiogroup.h"
41#include "llspinctrl.h"
42#include "lltextbox.h"
43#include "llui.h"
44
45#include "llviewercontrol.h"
46#include "llfirstuse.h"
47#include "llfloateravatarinfo.h"
48#include "llfloaterchat.h"
49#include "llfloatercustomize.h"
50#include "llfloaterproperties.h"
51#include "llfloaterworldmap.h"
52#include "llfocusmgr.h"
53#include "llfolderview.h"
54#include "llgesturemgr.h"
55#include "lliconctrl.h"
56#include "llinventorymodel.h"
57#include "llinventoryclipboard.h"
58#include "lllineeditor.h"
59#include "llmenugl.h"
60#include "llpreviewanim.h"
61#include "llpreviewgesture.h"
62#include "llpreviewlandmark.h"
63#include "llpreviewnotecard.h"
64#include "llpreviewscript.h"
65#include "llpreviewsound.h"
66#include "llpreviewtexture.h"
67#include "llresmgr.h"
68#include "llscrollcontainer.h"
69#include "llimview.h"
70#include "lltooldraganddrop.h"
71#include "llviewerimagelist.h"
72#include "llviewerinventory.h"
73#include "llviewerobjectlist.h"
74#include "llviewerwindow.h"
75#include "llwearable.h"
76#include "llwearablelist.h"
77#include "viewer.h"
78#include "llviewermessage.h"
79#include "llviewerregion.h"
80#include "lltabcontainer.h"
81#include "llvieweruictrlfactory.h"
82#include "llselectmgr.h"
83#include "llfloateropenobject.h"
84
85// Helpers
86// bug in busy count inc/dec right now, logic is complex... do we really need it?
87void inc_busy_count()
88{
89// gViewerWindow->getWindow()->incBusyCount();
90}
91void dec_busy_count()
92{
93// gViewerWindow->getWindow()->decBusyCount();
94}
95
96// Function declarations
97struct LLWearableHoldingPattern;
98void wear_inventory_category_on_avatar(LLInventoryCategory* category, BOOL append);
99void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata);
100void wear_inventory_category_on_avatar_loop(LLWearable* wearable, void*);
101void wear_inventory_category_on_avatar_step3(LLWearableHoldingPattern* holder, BOOL append);
102void remove_inventory_category_from_avatar(LLInventoryCategory* category);
103void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata);
104void move_task_inventory_callback(S32 option, void* user_data);
105void confirm_replace_attachment_rez(S32 option, void* user_data);
106
107// TomY XUI: translate
108const char* FIND_HINT = "Start typing to select an item by name";
109const char* NAME_SEARCH_DESC = "Find items whose name contains (leave blank for all):";
110const char* NEW_LSL_NAME = "New Script";
111const char* NEW_NOTECARD_NAME = "New Note";
112const char* NEW_GESTURE_NAME = "New Gesture";
113
114const char* ICON_NAME[ICON_NAME_COUNT] =
115{
116 "inv_item_texture.tga",
117 "inv_item_sound.tga",
118 "inv_item_callingcard_online.tga",
119 "inv_item_callingcard_offline.tga",
120 "inv_item_landmark.tga",
121 "inv_item_landmark_visited.tga",
122 "inv_item_script.tga",
123 "inv_item_clothing.tga",
124 "inv_item_object.tga",
125 "inv_item_notecard.tga",
126 "inv_item_bodypart.tga",
127 "inv_item_snapshot.tga",
128
129 "inv_item_shape.tga",
130 "inv_item_bodypart.tga",
131 "inv_item_hair.tga",
132 "inv_item_eyes.tga",
133 "inv_item_shirt.tga",
134 "inv_item_pants.tga",
135 "inv_item_shoes.tga",
136 "inv_item_socks.tga",
137 "inv_item_jacket.tga",
138 "inv_item_gloves.tga",
139 "inv_item_undershirt.tga",
140 "inv_item_underpants.tga",
141 "inv_item_skirt.tga",
142
143 "inv_item_animation.tga",
144 "inv_item_gesture.tga",
145};
146
147struct LLWearInfo
148{
149 LLUUID mCategoryID;
150 BOOL mAppend;
151};
152
153BOOL gAddToOutfit = FALSE;
154
155// +=================================================+
156// | LLInvFVBridge |
157// +=================================================+
158
159const LLString& LLInvFVBridge::getName() const
160{
161 LLInventoryObject* obj = getInventoryObject();
162 if(obj)
163 {
164 return obj->getName();
165 }
166 return LLString::null;
167}
168
169const LLString& LLInvFVBridge::getDisplayName() const
170{
171 return getName();
172}
173
174// Folders have full perms
175PermissionMask LLInvFVBridge::getPermissionMask() const
176{
177
178 return PERM_ALL;
179}
180
181// Folders don't have creation dates.
182U32 LLInvFVBridge::getCreationDate() const
183{
184 return 0;
185}
186
187// Can be destoryed (or moved to trash)
188BOOL LLInvFVBridge::isItemRemovable()
189{
190 LLInventoryModel* model = mInventoryPanel->getModel();
191 if(!model) return FALSE;
192 if(model->isObjectDescendentOf(mUUID, gAgent.getInventoryRootID()))
193 {
194 return TRUE;
195 }
196 return FALSE;
197}
198
199// Can be moved to another folder
200BOOL LLInvFVBridge::isItemMovable()
201{
202 return TRUE;
203}
204
205// *TODO: make sure this does the right thing
206void LLInvFVBridge::showProperties()
207{
208 LLShowProps::showProperties(mUUID);
209}
210
211void LLInvFVBridge::removeBatch(LLDynamicArray<LLFolderViewEventListener*>& batch)
212{
213 removeBatchNoCheck(batch);
214}
215
216void LLInvFVBridge::removeBatchNoCheck(LLDynamicArray<LLFolderViewEventListener*>& batch)
217{
218 // this method moves a bunch of items and folders to the trash. As
219 // per design guidelines for the inventory model, the message is
220 // built and the accounting is performed first. After all of that,
221 // we call LLInventoryModel::moveObject() to move everything
222 // around.
223 LLInvFVBridge* bridge;
224 LLInventoryModel* model = mInventoryPanel->getModel();
225 if(!model) return;
226 LLMessageSystem* msg = gMessageSystem;
227 LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
228 LLViewerInventoryItem* item = NULL;
229 LLViewerInventoryCategory* cat = NULL;
230 std::vector<LLUUID> move_ids;
231 LLInventoryModel::update_map_t update;
232 bool start_new_message = true;
233 S32 count = batch.count();
234 S32 i;
235 for(i = 0; i < count; ++i)
236 {
237 bridge = (LLInvFVBridge*)(batch.get(i));
238 if(!bridge || !bridge->isItemRemovable()) continue;
239 item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID());
240 if(item)
241 {
242 if(item->getParentUUID() == trash_id) continue;
243 move_ids.push_back(item->getUUID());
244 LLPreview::hide(item->getUUID());
245 --update[item->getParentUUID()];
246 ++update[trash_id];
247 if(start_new_message)
248 {
249 start_new_message = false;
250 msg->newMessageFast(_PREHASH_MoveInventoryItem);
251 msg->nextBlockFast(_PREHASH_AgentData);
252 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
253 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
254 msg->addBOOLFast(_PREHASH_Stamp, TRUE);
255 }
256 msg->nextBlockFast(_PREHASH_InventoryData);
257 msg->addUUIDFast(_PREHASH_ItemID, item->getUUID());
258 msg->addUUIDFast(_PREHASH_FolderID, trash_id);
259 msg->addString("NewName", NULL);
260 if(msg->isSendFullFast(_PREHASH_InventoryData))
261 {
262 start_new_message = true;
263 gAgent.sendReliableMessage();
264 gInventory.accountForUpdate(update);
265 update.clear();
266 }
267 }
268 }
269 if(!start_new_message)
270 {
271 start_new_message = true;
272 gAgent.sendReliableMessage();
273 gInventory.accountForUpdate(update);
274 update.clear();
275 }
276 for(i = 0; i < count; ++i)
277 {
278 bridge = (LLInvFVBridge*)(batch.get(i));
279 if(!bridge || !bridge->isItemRemovable()) continue;
280 cat = (LLViewerInventoryCategory*)model->getCategory(bridge->getUUID());
281 if(cat)
282 {
283 if(cat->getParentUUID() == trash_id) continue;
284 move_ids.push_back(cat->getUUID());
285 --update[cat->getParentUUID()];
286 ++update[trash_id];
287 if(start_new_message)
288 {
289 start_new_message = false;
290 msg->newMessageFast(_PREHASH_MoveInventoryFolder);
291 msg->nextBlockFast(_PREHASH_AgentData);
292 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
293 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
294 msg->addBOOL("Stamp", TRUE);
295 }
296 msg->nextBlockFast(_PREHASH_InventoryData);
297 msg->addUUIDFast(_PREHASH_FolderID, cat->getUUID());
298 msg->addUUIDFast(_PREHASH_ParentID, trash_id);
299 if(msg->isSendFullFast(_PREHASH_InventoryData))
300 {
301 start_new_message = true;
302 gAgent.sendReliableMessage();
303 gInventory.accountForUpdate(update);
304 update.clear();
305 }
306 }
307 }
308 if(!start_new_message)
309 {
310 gAgent.sendReliableMessage();
311 gInventory.accountForUpdate(update);
312 }
313
314 // move everything.
315 std::vector<LLUUID>::iterator it = move_ids.begin();
316 std::vector<LLUUID>::iterator end = move_ids.end();
317 for(; it != end; ++it)
318 {
319 gInventory.moveObject((*it), trash_id);
320 }
321
322 // notify inventory observers.
323 model->notifyObservers();
324}
325
326BOOL LLInvFVBridge::isClipboardPasteable() const
327{
328 LLInventoryModel* model = mInventoryPanel->getModel();
329 if(!model) return FALSE;
330 BOOL is_agent_inventory = model->isObjectDescendentOf(mUUID, gAgent.getInventoryRootID());
331
332 if(LLInventoryClipboard::instance().hasContents() && is_agent_inventory)
333 {
334 return TRUE;
335 }
336 return FALSE;
337}
338
339void hideContextEntries(LLMenuGL& menu,
340 const std::vector<LLString> &entries_to_show,
341 const std::vector<LLString> &disabled_entries)
342{
343 const LLView::child_list_t *list = menu.getChildList();
344
345 LLView::child_list_t::const_iterator itor;
346 for (itor = list->begin(); itor != list->end(); ++itor)
347 {
348 LLString name = (*itor)->getName();
349 bool found = false;
350 std::vector<LLString>::const_iterator itor2;
351 for (itor2 = entries_to_show.begin(); itor2 != entries_to_show.end(); ++itor2)
352 {
353 if (*itor2 == name)
354 {
355 found = true;
356 }
357 }
358 if (!found)
359 {
360 (*itor)->setVisible(FALSE);
361 }
362 else
363 {
364 for (itor2 = disabled_entries.begin(); itor2 != disabled_entries.end(); ++itor2)
365 {
366 if (*itor2 == name)
367 {
368 (*itor)->setEnabled(FALSE);
369 }
370 }
371 }
372 }
373}
374
375// Helper for commonly-used entries
376void LLInvFVBridge::getClipboardEntries(bool show_asset_id, std::vector<LLString> &items,
377 std::vector<LLString> &disabled_items, U32 flags)
378{
379 items.push_back("Rename");
380 if (!isItemRenameable() || (flags & FIRST_SELECTED_ITEM) == 0)
381 {
382 disabled_items.push_back("Rename");
383 }
384
385 if (show_asset_id)
386 {
387 items.push_back("Copy Asset UUID");
388 if ( (! ( isItemPermissive() || gAgent.isGodlike() ) )
389 || (flags & FIRST_SELECTED_ITEM) == 0)
390 {
391 disabled_items.push_back("Copy Asset UUID");
392 }
393 }
394
395 items.push_back("Copy Separator");
396
397 items.push_back("Copy");
398 if (!isItemCopyable())
399 {
400 disabled_items.push_back("Copy");
401 }
402
403 items.push_back("Paste");
404 if (!isClipboardPasteable() || (flags & FIRST_SELECTED_ITEM) == 0)
405 {
406 disabled_items.push_back("Paste");
407 }
408
409 items.push_back("Paste Separator");
410
411 items.push_back("Delete");
412 if (!isItemRemovable())
413 {
414 disabled_items.push_back("Delete");
415 }
416}
417
418void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
419{
420 lldebugs << "LLInvFVBridge::buildContextMenu()" << llendl;
421 std::vector<LLString> items;
422 std::vector<LLString> disabled_items;
423 if(isInTrash())
424 {
425 items.push_back("Purge Item");
426 if (!isItemRemovable())
427 {
428 disabled_items.push_back("Purge Item");
429 }
430 items.push_back("Restore Item");
431 }
432 else
433 {
434 items.push_back("Open");
435 items.push_back("Properties");
436
437 getClipboardEntries(true, items, disabled_items, flags);
438 }
439 hideContextEntries(menu, items, disabled_items);
440}
441
442// *TODO: remove this
443BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id)
444{
445 BOOL rv = FALSE;
446
447 LLInventoryObject* obj = getInventoryObject();
448
449 if(obj)
450 {
451 *type = LLAssetType::lookupDragAndDropType(obj->getType());
452 if(*type == DAD_NONE)
453 {
454 return FALSE;
455 }
456
457 *id = obj->getUUID();
458 //object_ids.put(obj->getUUID());
459
460 if (*type == DAD_CATEGORY)
461 {
462 gInventory.startBackgroundFetch(obj->getUUID());
463 }
464
465 rv = TRUE;
466 }
467
468 return rv;
469}
470
471LLInventoryObject* LLInvFVBridge::getInventoryObject() const
472{
473 LLInventoryObject* obj = NULL;
474 LLInventoryModel* model = mInventoryPanel->getModel();
475 if(model)
476 {
477 obj = (LLInventoryObject*)model->getObject(mUUID);
478 }
479 return obj;
480}
481
482BOOL LLInvFVBridge::isInTrash() const
483{
484 LLInventoryModel* model = mInventoryPanel->getModel();
485 if(!model) return FALSE;
486 LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
487 return model->isObjectDescendentOf(mUUID, trash_id);
488}
489
490BOOL LLInvFVBridge::isAgentInventory() const
491{
492 LLInventoryModel* model = mInventoryPanel->getModel();
493 if(!model) return FALSE;
494 if(gAgent.getInventoryRootID() == mUUID) return TRUE;
495 return model->isObjectDescendentOf(mUUID, gAgent.getInventoryRootID());
496}
497
498BOOL LLInvFVBridge::isItemPermissive() const
499{
500 return FALSE;
501}
502
503// static
504void LLInvFVBridge::changeItemParent(LLInventoryModel* model,
505 LLViewerInventoryItem* item,
506 const LLUUID& new_parent,
507 BOOL restamp)
508{
509 if(item->getParentUUID() != new_parent)
510 {
511 LLInventoryModel::update_list_t update;
512 LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1);
513 update.push_back(old_folder);
514 LLInventoryModel::LLCategoryUpdate new_folder(new_parent, 1);
515 update.push_back(new_folder);
516 gInventory.accountForUpdate(update);
517
518 LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
519 new_item->setParent(new_parent);
520 new_item->updateParentOnServer(restamp);
521 model->updateItem(new_item);
522 model->notifyObservers();
523 }
524}
525
526// static
527void LLInvFVBridge::changeCategoryParent(LLInventoryModel* model,
528 LLViewerInventoryCategory* cat,
529 const LLUUID& new_parent,
530 BOOL restamp)
531{
532 if(cat->getParentUUID() != new_parent)
533 {
534 LLInventoryModel::update_list_t update;
535 LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1);
536 update.push_back(old_folder);
537 LLInventoryModel::LLCategoryUpdate new_folder(new_parent, 1);
538 update.push_back(new_folder);
539 gInventory.accountForUpdate(update);
540
541 LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat);
542 new_cat->setParent(new_parent);
543 new_cat->updateParentOnServer(restamp);
544 model->updateCategory(new_cat);
545 model->notifyObservers();
546 }
547}
548
549
550const char* safe_inv_type_lookup(LLInventoryType::EType inv_type)
551{
552 const char* rv = LLInventoryType::lookup(inv_type);
553 if(!rv)
554 {
555 const char* INVALID_TYPE = "<invalid>";
556 rv = INVALID_TYPE;
557 }
558 return rv;
559}
560
561LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,
562 LLInventoryType::EType inv_type,
563 LLInventoryPanel* inventory,
564 const LLUUID& uuid,
565 U32 flags)
566{
567 LLInvFVBridge* new_listener = NULL;
568 switch(asset_type)
569 {
570 case LLAssetType::AT_TEXTURE:
571 if(!(inv_type == LLInventoryType::IT_TEXTURE || inv_type == LLInventoryType::IT_SNAPSHOT))
572 {
573 llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
574 }
575 new_listener = new LLTextureBridge(inventory, uuid, inv_type);
576 break;
577
578 case LLAssetType::AT_SOUND:
579 if(!(inv_type == LLInventoryType::IT_SOUND))
580 {
581 llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
582 }
583 new_listener = new LLSoundBridge(inventory, uuid);
584 break;
585
586 case LLAssetType::AT_LANDMARK:
587 if(!(inv_type == LLInventoryType::IT_LANDMARK))
588 {
589 llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
590 }
591 new_listener = new LLLandmarkBridge(inventory, uuid, flags);
592 break;
593
594 case LLAssetType::AT_CALLINGCARD:
595 if(!(inv_type == LLInventoryType::IT_CALLINGCARD))
596 {
597 llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
598 }
599 new_listener = new LLCallingCardBridge(inventory, uuid);
600 break;
601
602 case LLAssetType::AT_SCRIPT:
603 if(!(inv_type == LLInventoryType::IT_LSL))
604 {
605 llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
606 }
607 new_listener = new LLScriptBridge(inventory, uuid);
608 break;
609
610 case LLAssetType::AT_OBJECT:
611 if(!(inv_type == LLInventoryType::IT_OBJECT || inv_type == LLInventoryType::IT_ATTACHMENT))
612 {
613 llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
614 }
615 new_listener = new LLObjectBridge(inventory, uuid, inv_type, flags);
616 break;
617
618 case LLAssetType::AT_NOTECARD:
619 if(!(inv_type == LLInventoryType::IT_NOTECARD))
620 {
621 llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
622 }
623 new_listener = new LLNotecardBridge(inventory, uuid);
624 break;
625
626 case LLAssetType::AT_ANIMATION:
627 if(!(inv_type == LLInventoryType::IT_ANIMATION))
628 {
629 llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
630 }
631 new_listener = new LLAnimationBridge(inventory, uuid);
632 break;
633
634 case LLAssetType::AT_GESTURE:
635 if(!(inv_type == LLInventoryType::IT_GESTURE))
636 {
637 llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
638 }
639 new_listener = new LLGestureBridge(inventory, uuid);
640 break;
641
642 case LLAssetType::AT_LSL_TEXT:
643 if(!(inv_type == LLInventoryType::IT_LSL))
644 {
645 llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
646 }
647 new_listener = new LLLSLTextBridge(inventory, uuid);
648 break;
649
650 case LLAssetType::AT_CLOTHING:
651 case LLAssetType::AT_BODYPART:
652 if(!(inv_type == LLInventoryType::IT_WEARABLE))
653 {
654 llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
655 }
656 new_listener = new LLWearableBridge(inventory, uuid, asset_type, inv_type, (EWearableType)flags);
657 break;
658
659 case LLAssetType::AT_CATEGORY:
660 case LLAssetType::AT_ROOT_CATEGORY:
661 new_listener = new LLFolderBridge(inventory, uuid);
662 break;
663
664 default:
665 llinfos << "Unhandled asset type (llassetstorage.h): "
666 << (S32)asset_type << llendl;
667 break;
668 }
669
670 new_listener->mInvType = inv_type;
671 return new_listener;
672}
673
674// +=================================================+
675// | LLItemBridge |
676// +=================================================+
677
678void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model, LLString action)
679{
680 if ("open" == action)
681 {
682 openItem();
683 }
684 else if ("properties" == action)
685 {
686 showProperties();
687 }
688 else if ("purge" == action)
689 {
690 LLInventoryCategory* cat = model->getCategory(mUUID);
691 if(cat)
692 {
693 model->purgeDescendentsOf(mUUID);
694 }
695 LLInventoryObject* obj = model->getObject(mUUID);
696 if(!obj) return;
697 obj->removeFromServer();
698 LLPreview::hide(mUUID);
699 model->deleteObject(mUUID);
700 model->notifyObservers();
701 }
702 else if ("restore" == action)
703 {
704 restoreItem();
705 }
706 else if ("copy_uuid" == action)
707 {
708 // Single item only
709 LLInventoryItem* item = model->getItem(mUUID);
710 if(!item) return;
711 LLUUID asset_id = item->getAssetUUID();
712 char buffer[UUID_STR_LENGTH];
713 asset_id.toString(buffer);
714
715 gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(buffer));
716 return;
717 }
718 else if ("copy" == action)
719 {
720 copyToClipboard();
721 return;
722 }
723 else if ("paste" == action)
724 {
725 // Single item only
726 LLInventoryItem* itemp = model->getItem(mUUID);
727 if (!itemp) return;
728
729 LLFolderViewItem* folder_view_itemp = folder->getItemByID(itemp->getParentUUID());
730 if (!folder_view_itemp) return;
731
732 folder_view_itemp->getListener()->pasteFromClipboard();
733 return;
734 }
735}
736
737void LLItemBridge::selectItem()
738{
739 LLViewerInventoryItem* item = (LLViewerInventoryItem*)getItem();
740 if(item && !item->isComplete())
741 {
742 item->fetchFromServer();
743 }
744}
745
746void LLItemBridge::restoreItem()
747{
748 LLViewerInventoryItem* item = (LLViewerInventoryItem*)getItem();
749 if(item)
750 {
751 LLInventoryModel* model = mInventoryPanel->getModel();
752 LLUUID new_parent = model->findCategoryUUIDForType(item->getType());
753 // do not restamp on restore.
754 LLInvFVBridge::changeItemParent(model, item, new_parent, FALSE);
755 }
756}
757
758LLViewerImage* LLItemBridge::getIcon() const
759{
760 LLString uuid_string = gViewerArt.getString(ICON_NAME[OBJECT_ICON_NAME]);
761 return gImageList.getImage(LLUUID(uuid_string), MIPMAP_FALSE, TRUE);
762}
763
764PermissionMask LLItemBridge::getPermissionMask() const
765{
766 LLViewerInventoryItem* item = getItem();
767 PermissionMask perm_mask = 0;
768 if(item)
769 {
770 BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID());
771 BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID());
772 BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER,
773 gAgent.getID());
774
775 if (copy) perm_mask |= PERM_COPY;
776 if (mod) perm_mask |= PERM_MODIFY;
777 if (xfer) perm_mask |= PERM_TRANSFER;
778
779 }
780 return perm_mask;
781}
782
783const LLString& LLItemBridge::getDisplayName() const
784{
785 if(mDisplayName.empty())
786 {
787 buildDisplayName(getItem(), mDisplayName);
788 }
789 return mDisplayName;
790}
791
792void LLItemBridge::buildDisplayName(LLInventoryItem* item, LLString& name)
793{
794 if(item)
795 {
796 name.assign(item->getName());
797 }
798 else
799 {
800 name.assign(LLString::null);
801 }
802}
803
804LLString LLItemBridge::getLabelSuffix() const
805{
806 LLString suffix;
807 LLInventoryItem* item = getItem();
808 if(item)
809 {
810 // it's a bit confusing to put nocopy/nomod/etc on calling cards.
811 if(LLAssetType::AT_CALLINGCARD != item->getType()
812 && item->getPermissions().getOwner() == gAgent.getID())
813 {
814 BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID());
815 BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID());
816 BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER,
817 gAgent.getID());
818 const char* EMPTY = "";
819 const char* NO_COPY = " (no copy)";
820 const char* NO_MOD = " (no modify)";
821 const char* NO_XFER = " (no transfer)";
822 const char* scopy;
823 if(copy) scopy = EMPTY;
824 else scopy = NO_COPY;
825 const char* smod;
826 if(mod) smod = EMPTY;
827 else smod = NO_MOD;
828 const char* sxfer;
829 if(xfer) sxfer = EMPTY;
830 else sxfer = NO_XFER;
831 char buffer[MAX_STRING];
832 snprintf(
833 buffer,
834 MAX_STRING,
835 "%s%s%s",
836 scopy,
837 smod,
838 sxfer);
839 suffix.assign(buffer);
840 }
841 }
842 return suffix;
843}
844
845U32 LLItemBridge::getCreationDate() const
846{
847 LLViewerInventoryItem* item = getItem();
848 if (item)
849 {
850 return item->getCreationDate();
851 }
852 return 0;
853}
854
855
856BOOL LLItemBridge::isItemRenameable() const
857{
858 LLViewerInventoryItem* item = getItem();
859 if(item)
860 {
861 return (item->getPermissions().allowModifyBy(gAgent.getID()));
862 }
863 return FALSE;
864}
865
866BOOL LLItemBridge::renameItem(const LLString& new_name)
867{
868 if(!isItemRenameable()) return FALSE;
869 LLPreview::rename(mUUID, getPrefix() + new_name);
870 LLInventoryModel* model = mInventoryPanel->getModel();
871 if(!model) return FALSE;
872 LLViewerInventoryItem* item = getItem();
873 if(item && (item->getName() != new_name))
874 {
875 LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
876 new_item->rename(new_name);
877 buildDisplayName(new_item, mDisplayName);
878 new_item->updateServer(FALSE);
879 model->updateItem(new_item);
880 model->notifyObservers();
881 }
882 // return FALSE because we either notified observers (& therefore
883 // rebuilt) or we didn't update.
884 return FALSE;
885}
886
887
888BOOL LLItemBridge::removeItem()
889{
890 if(!isItemRemovable())
891 {
892 return FALSE;
893 }
894 // move it to the trash
895 LLPreview::hide(mUUID);
896 LLInventoryModel* model = mInventoryPanel->getModel();
897 if(!model) return FALSE;
898 LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
899 LLViewerInventoryItem* item = getItem();
900 if(item)
901 {
902 // restamp on move to trash.
903 LLInvFVBridge::changeItemParent(model, item, trash_id, TRUE);
904 }
905
906 // return false anyway, so that if it's called from the folder
907 // view, it doesn't remove the view - it's just being moved to the
908 // trash.
909 return FALSE;
910}
911
912BOOL LLItemBridge::isItemCopyable() const
913{
914 LLViewerInventoryItem* item = getItem();
915 if (item)
916 {
917 return (item->getPermissions().allowCopyBy(gAgent.getID()));
918 }
919 return FALSE;
920}
921BOOL LLItemBridge::copyToClipboard() const
922{
923 if(isItemCopyable())
924 {
925 LLInventoryClipboard::instance().add(mUUID);
926 return TRUE;
927 }
928 return FALSE;
929}
930
931LLViewerInventoryItem* LLItemBridge::getItem() const
932{
933 LLViewerInventoryItem* item = NULL;
934 LLInventoryModel* model = mInventoryPanel->getModel();
935 if(model)
936 {
937 item = (LLViewerInventoryItem*)model->getItem(mUUID);
938 }
939 return item;
940}
941
942BOOL LLItemBridge::isItemPermissive() const
943{
944 LLViewerInventoryItem* item = getItem();
945 if(item)
946 {
947 U32 mask = item->getPermissions().getMaskBase();
948 if((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
949 {
950 return TRUE;
951 }
952 }
953 return FALSE;
954}
955
956// +=================================================+
957// | LLFolderBridge |
958// +=================================================+
959
960LLFolderBridge* LLFolderBridge::sSelf=NULL;
961
962// Can be moved to another folder
963BOOL LLFolderBridge::isItemMovable()
964{
965 LLInventoryObject* obj = getInventoryObject();
966 if(obj)
967 {
968 return (LLAssetType::AT_NONE == ((LLInventoryCategory*)obj)->getPreferredType());
969 }
970 return FALSE;
971}
972
973void LLFolderBridge::selectItem()
974{
975}
976
977
978// Can be destroyed (or moved to trash)
979BOOL LLFolderBridge::isItemRemovable()
980{
981 LLInventoryModel* model = mInventoryPanel->getModel();
982 if(!model)
983 {
984 return FALSE;
985 }
986
987 if(!model->isObjectDescendentOf(mUUID, gAgent.getInventoryRootID()))
988 {
989 return FALSE;
990 }
991
992 LLVOAvatar* avatar = gAgent.getAvatarObject();
993 if( !avatar )
994 {
995 return FALSE;
996 }
997
998 LLInventoryCategory* category = model->getCategory(mUUID);
999 if( !category )
1000 {
1001 return FALSE;
1002 }
1003
1004 if( LLAssetType::AT_NONE != category->getPreferredType() )
1005 {
1006 return FALSE;
1007 }
1008
1009 LLInventoryModel::cat_array_t descendent_categories;
1010 LLInventoryModel::item_array_t descendent_items;
1011 gInventory.collectDescendents( mUUID, descendent_categories, descendent_items, FALSE );
1012
1013 S32 i;
1014 for( i = 0; i < descendent_categories.count(); i++ )
1015 {
1016 LLInventoryCategory* category = descendent_categories[i];
1017 if( LLAssetType::AT_NONE != category->getPreferredType() )
1018 {
1019 return FALSE;
1020 }
1021 }
1022
1023 for( i = 0; i < descendent_items.count(); i++ )
1024 {
1025 LLInventoryItem* item = descendent_items[i];
1026 if( (item->getType() == LLAssetType::AT_CLOTHING) ||
1027 (item->getType() == LLAssetType::AT_BODYPART) )
1028 {
1029 if( gAgent.isWearingItem( item->getUUID() ) )
1030 {
1031 return FALSE;
1032 }
1033 }
1034 else
1035 if( item->getType() == LLAssetType::AT_OBJECT )
1036 {
1037 if( avatar->isWearingAttachment( item->getUUID() ) )
1038 {
1039 return FALSE;
1040 }
1041 }
1042 }
1043
1044 return TRUE;
1045}
1046
1047BOOL LLFolderBridge::isUpToDate() const
1048{
1049 LLInventoryModel* model = mInventoryPanel->getModel();
1050 if(!model) return FALSE;
1051 LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID);
1052 if( !category )
1053 {
1054 return FALSE;
1055 }
1056
1057 return category->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN;
1058}
1059
1060BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
1061 BOOL drop)
1062{
1063 // This should never happen, but if an inventory item is incorrectly parented,
1064 // the UI will get confused and pass in a NULL.
1065 if(!inv_cat) return FALSE;
1066
1067 LLInventoryModel* model = mInventoryPanel->getModel();
1068 if(!model) return FALSE;
1069
1070 LLVOAvatar* avatar = gAgent.getAvatarObject();
1071 if(!avatar) return FALSE;
1072
1073 // cannot drag into library
1074 if(!isAgentInventory())
1075 {
1076 return FALSE;
1077 }
1078
1079 // check to make sure source is agent inventory, and is represented there.
1080 LLToolDragAndDrop::ESource source = gToolDragAndDrop->getSource();
1081 BOOL is_agent_inventory = (model->getCategory(inv_cat->getUUID()) != NULL)
1082 && (LLToolDragAndDrop::SOURCE_AGENT == source);
1083
1084 BOOL accept = FALSE;
1085 S32 i;
1086 LLInventoryModel::cat_array_t descendent_categories;
1087 LLInventoryModel::item_array_t descendent_items;
1088 if(is_agent_inventory)
1089 {
1090 const LLUUID& cat_id = inv_cat->getUUID();
1091
1092 // Is the destination the trash?
1093 LLUUID trash_id;
1094 trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
1095 BOOL move_is_into_trash = (mUUID == trash_id)
1096 || model->isObjectDescendentOf(mUUID, trash_id);
1097 BOOL is_movable = (LLAssetType::AT_NONE == inv_cat->getPreferredType());
1098 if( is_movable )
1099 {
1100 gInventory.collectDescendents( cat_id, descendent_categories, descendent_items, FALSE );
1101
1102 for( i = 0; i < descendent_categories.count(); i++ )
1103 {
1104 LLInventoryCategory* category = descendent_categories[i];
1105 if( LLAssetType::AT_NONE != category->getPreferredType() )
1106 {
1107 // ...can't move "special folders" like Textures
1108 is_movable = FALSE;
1109 break;
1110 }
1111 }
1112
1113 if( is_movable )
1114 {
1115 if( move_is_into_trash )
1116 {
1117 for( i = 0; i < descendent_items.count(); i++ )
1118 {
1119 LLInventoryItem* item = descendent_items[i];
1120 if( (item->getType() == LLAssetType::AT_CLOTHING) ||
1121 (item->getType() == LLAssetType::AT_BODYPART) )
1122 {
1123 if( gAgent.isWearingItem( item->getUUID() ) )
1124 {
1125 is_movable = FALSE; // It's generally movable, but not into the trash!
1126 break;
1127 }
1128 }
1129 else
1130 if( item->getType() == LLAssetType::AT_OBJECT )
1131 {
1132 if( avatar->isWearingAttachment( item->getUUID() ) )
1133 {
1134 is_movable = FALSE; // It's generally movable, but not into the trash!
1135 break;
1136 }
1137 }
1138 }
1139 }
1140 }
1141 }
1142
1143
1144 accept = is_movable
1145 && (mUUID != cat_id) // Can't move a folder into itself
1146 && (mUUID != inv_cat->getParentUUID()) // Avoid moves that would change nothing
1147 && !(model->isObjectDescendentOf(mUUID, cat_id)); // Avoid circularity
1148 if(accept && drop)
1149 {
1150 // Look for any gestures and deactivate them
1151 if (move_is_into_trash)
1152 {
1153 for (i = 0; i < descendent_items.count(); i++)
1154 {
1155 LLInventoryItem* item = descendent_items[i];
1156 if (item->getType() == LLAssetType::AT_GESTURE
1157 && gGestureManager.isGestureActive(item->getUUID()))
1158 {
1159 gGestureManager.deactivateGesture(item->getUUID());
1160 }
1161 }
1162 }
1163
1164 // Reparent the folder and restamp children if it's moving
1165 // into trash.
1166 LLInvFVBridge::changeCategoryParent(
1167 model,
1168 (LLViewerInventoryCategory*)inv_cat,
1169 mUUID,
1170 move_is_into_trash);
1171 }
1172 }
1173 else if(LLToolDragAndDrop::SOURCE_WORLD == source)
1174 {
1175 // content category has same ID as object itself
1176 LLUUID object_id = inv_cat->getUUID();
1177 LLUUID category_id = mUUID;
1178 accept = move_inv_category_world_to_agent(object_id, category_id, drop);
1179 }
1180 return accept;
1181}
1182
1183void warn_move_inventory(LLViewerObject* object, LLMoveInv* move_inv)
1184{
1185 const char* dialog = NULL;
1186 if (object->flagScripted())
1187 {
1188 dialog = "MoveInventoryFromScriptedObject";
1189 }
1190 else
1191 {
1192 dialog = "MoveInventoryFromObject";
1193 }
1194 gViewerWindow->alertXml(dialog, move_task_inventory_callback, move_inv);
1195}
1196
1197// Move/copy all inventory items from the Contents folder of an in-world
1198// object to the agent's inventory, inside a given category.
1199BOOL move_inv_category_world_to_agent(const LLUUID& object_id,
1200 const LLUUID& category_id,
1201 BOOL drop,
1202 void (*callback)(S32, void*),
1203 void* user_data)
1204{
1205 // Make sure the object exists. If we allowed dragging from
1206 // anonymous objects, it would be possible to bypass
1207 // permissions.
1208 // content category has same ID as object itself
1209 LLViewerObject* object = gObjectList.findObject(object_id);
1210 if(!object)
1211 {
1212 llinfos << "Object not found for drop." << llendl;
1213 return FALSE;
1214 }
1215
1216 // this folder is coming from an object, as there is only one folder in an object, the root,
1217 // we need to collect the entire contents and handle them as a group
1218 InventoryObjectList inventory_objects;
1219 object->getInventoryContents(inventory_objects);
1220
1221 if (inventory_objects.empty())
1222 {
1223 llinfos << "Object contents not found for drop." << llendl;
1224 return FALSE;
1225 }
1226
1227 BOOL accept = TRUE;
1228 BOOL is_move = FALSE;
1229
1230 // coming from a task. Need to figure out if the person can
1231 // move/copy this item.
1232 InventoryObjectList::iterator it = inventory_objects.begin();
1233 InventoryObjectList::iterator end = inventory_objects.end();
1234 for ( ; it != end; ++it)
1235 {
1236 // coming from a task. Need to figure out if the person can
1237 // move/copy this item.
1238 LLPermissions perm(((LLInventoryItem*)((LLInventoryObject*)(*it)))->getPermissions());
1239 if((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID())
1240 && perm.allowTransferTo(gAgent.getID())))
1241// || gAgent.isGodlike())
1242 {
1243 accept = TRUE;
1244 }
1245 else if(object->permYouOwner())
1246 {
1247 // If the object cannot be copied, but the object the
1248 // inventory is owned by the agent, then the item can be
1249 // moved from the task to agent inventory.
1250 is_move = TRUE;
1251 accept = TRUE;
1252 }
1253 else
1254 {
1255 accept = FALSE;
1256 break;
1257 }
1258 }
1259
1260 if(drop && accept)
1261 {
1262 it = inventory_objects.begin();
1263 InventoryObjectList::iterator first_it = inventory_objects.begin();
1264 LLMoveInv* move_inv = new LLMoveInv;
1265 move_inv->mObjectID = object_id;
1266 move_inv->mCategoryID = category_id;
1267 move_inv->mCallback = callback;
1268 move_inv->mUserData = user_data;
1269
1270 for ( ; it != end; ++it)
1271 {
1272 two_uuids_t two(category_id, (*it)->getUUID());
1273 move_inv->mMoveList.push_back(two);
1274 }
1275
1276 if(is_move)
1277 {
1278 // Callback called from within here.
1279 warn_move_inventory(object, move_inv);
1280 }
1281 else
1282 {
1283 move_task_inventory_callback(0, (void*)(move_inv));
1284 }
1285 }
1286 return accept;
1287}
1288
1289class LLFindWearables : public LLInventoryCollectFunctor
1290{
1291public:
1292 LLFindWearables() {}
1293 virtual ~LLFindWearables() {}
1294 virtual bool operator()(LLInventoryCategory* cat,
1295 LLInventoryItem* item);
1296};
1297
1298bool LLFindWearables::operator()(LLInventoryCategory* cat,
1299 LLInventoryItem* item)
1300{
1301 if(item)
1302 {
1303 if((item->getType() == LLAssetType::AT_CLOTHING)
1304 || (item->getType() == LLAssetType::AT_BODYPART))
1305 {
1306 return TRUE;
1307 }
1308 }
1309 return FALSE;
1310}
1311
1312//Used by LLFolderBridge as callback for directory recursion.
1313class LLRightClickInventoryFetchObserver : public LLInventoryFetchObserver
1314{
1315public:
1316 LLRightClickInventoryFetchObserver() {};
1317 LLRightClickInventoryFetchObserver(const LLUUID& cat_id, bool copy_items) :
1318 mCatID(cat_id),
1319 mCopyItems(copy_items)
1320 { };
1321 virtual void done()
1322 {
1323 // we've downloaded all the items, so repaint the dialog
1324 LLFolderBridge::staticFolderOptionsMenu();
1325
1326 gInventory.removeObserver(this);
1327 delete this;
1328 }
1329
1330
1331protected:
1332 LLUUID mCatID;
1333 bool mCopyItems;
1334
1335};
1336
1337//Used by LLFolderBridge as callback for directory recursion.
1338class LLRightClickInventoryFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver
1339{
1340public:
1341 LLRightClickInventoryFetchDescendentsObserver(bool copy_items) : mCopyItems(copy_items) {}
1342 ~LLRightClickInventoryFetchDescendentsObserver() {}
1343 virtual void done();
1344protected:
1345 bool mCopyItems;
1346};
1347
1348void LLRightClickInventoryFetchDescendentsObserver::done()
1349{
1350 // What we do here is get the complete information on the items in
1351 // the library, and set up an observer that will wait for that to
1352 // happen.
1353 LLInventoryModel::cat_array_t cat_array;
1354 LLInventoryModel::item_array_t item_array;
1355 gInventory.collectDescendents(mCompleteFolders.front(),
1356 cat_array,
1357 item_array,
1358 LLInventoryModel::EXCLUDE_TRASH);
1359 S32 count = item_array.count();
1360#if 0
1361 // This early causes a giant menu to get produced, and doesn't seem to be needed.
1362 if(!count)
1363 {
1364 llwarns << "Nothing fetched in category " << mCompleteFolders.front()
1365 << llendl;
1366 dec_busy_count();
1367 gInventory.removeObserver(this);
1368 delete this;
1369 return;
1370 }
1371#endif
1372
1373 LLRightClickInventoryFetchObserver* outfit;
1374 outfit = new LLRightClickInventoryFetchObserver(mCompleteFolders.front(), mCopyItems);
1375 LLInventoryFetchObserver::item_ref_t ids;
1376 for(S32 i = 0; i < count; ++i)
1377 {
1378 ids.push_back(item_array.get(i)->getUUID());
1379 }
1380
1381 // clean up, and remove this as an observer since the call to the
1382 // outfit could notify observers and throw us into an infinite
1383 // loop.
1384 dec_busy_count();
1385 gInventory.removeObserver(this);
1386 delete this;
1387
1388 // increment busy count and either tell the inventory to check &
1389 // call done, or add this object to the inventory for observation.
1390 inc_busy_count();
1391
1392 // do the fetch
1393 outfit->fetchItems(ids);
1394 outfit->done(); //Not interested in waiting and this will be right 99% of the time.
1395//Uncomment the following code for laggy Inventory UI.
1396/* if(outfit->isEverythingComplete())
1397 {
1398 // everything is already here - call done.
1399 outfit->done();
1400 }
1401 else
1402 {
1403 // it's all on it's way - add an observer, and the inventory
1404 // will call done for us when everything is here.
1405 gInventory.addObserver(outfit);
1406 }*/
1407}
1408
1409
1410//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1411// Class LLInventoryWearObserver
1412//
1413// Observer for "copy and wear" operation to support knowing
1414// when the all of the contents have been added to inventory.
1415//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1416class LLInventoryCopyAndWearObserver : public LLInventoryObserver
1417{
1418public:
1419 LLInventoryCopyAndWearObserver(const LLUUID& cat_id, int count) :mCatID(cat_id), mContentsCount(count), mFolderAdded(FALSE) {}
1420 virtual ~LLInventoryCopyAndWearObserver() {}
1421 virtual void changed(U32 mask);
1422
1423protected:
1424 LLUUID mCatID;
1425 int mContentsCount;
1426 BOOL mFolderAdded;
1427};
1428
1429
1430
1431void LLInventoryCopyAndWearObserver::changed(U32 mask)
1432{
1433 if((mask & (LLInventoryObserver::ADD)) != 0)
1434 {
1435 if (!mFolderAdded)
1436 {
1437 const std::set<LLUUID>& changed_items = gInventory.getChangedIDs();
1438
1439 std::set<LLUUID>::const_iterator id_it = changed_items.begin();
1440 std::set<LLUUID>::const_iterator id_end = changed_items.end();
1441 for (;id_it != id_end; ++id_it)
1442 {
1443 if ((*id_it) == mCatID)
1444 {
1445 mFolderAdded = TRUE;
1446 break;
1447 }
1448 }
1449 }
1450
1451 if (mFolderAdded)
1452 {
1453 LLViewerInventoryCategory* category = gInventory.getCategory(mCatID);
1454
1455 if (category->getDescendentCount() == mContentsCount)
1456 {
1457 gInventory.removeObserver(this);
1458 wear_inventory_category(category, FALSE, TRUE);
1459 delete this;
1460 }
1461 }
1462
1463 }
1464}
1465
1466
1467
1468void LLFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model, LLString action)
1469{
1470 if ("open" == action)
1471 {
1472 openItem();
1473 }
1474 else if ("paste" == action)
1475 {
1476 pasteFromClipboard();
1477 }
1478 else if ("properties" == action)
1479 {
1480 showProperties();
1481 }
1482 else if ("replaceoutfit" == action)
1483 {
1484 modifyOutfit(FALSE);
1485 }
1486 else if ("addtooutfit" == action)
1487 {
1488 modifyOutfit(TRUE);
1489 }
1490 else if ("removefromoutfit" == action)
1491 {
1492 LLInventoryModel* model = mInventoryPanel->getModel();
1493 if(!model) return;
1494 LLViewerInventoryCategory* cat = getCategory();
1495 if(!cat) return;
1496
1497 remove_inventory_category_from_avatar ( cat );
1498 }
1499 else if ("purge" == action)
1500 {
1501 LLViewerInventoryCategory* cat;
1502 cat = (LLViewerInventoryCategory*)getCategory();
1503
1504 if(cat)
1505 {
1506 model->purgeDescendentsOf(mUUID);
1507 }
1508 LLInventoryObject* obj = model->getObject(mUUID);
1509 if(!obj) return;
1510 obj->removeFromServer();
1511 model->deleteObject(mUUID);
1512 model->notifyObservers();
1513 }
1514 else if ("restore" == action)
1515 {
1516 restoreItem();
1517 }
1518}
1519
1520void LLFolderBridge::openItem()
1521{
1522 lldebugs << "LLFolderBridge::openItem()" << llendl;
1523 LLInventoryModel* model = mInventoryPanel->getModel();
1524 if(!model) return;
1525 model->fetchDescendentsOf(mUUID);
1526}
1527
1528BOOL LLFolderBridge::isItemRenameable() const
1529{
1530 LLViewerInventoryCategory* cat = (LLViewerInventoryCategory*)getCategory();
1531 if(cat && (cat->getPreferredType() == LLAssetType::AT_NONE)
1532 && (cat->getOwnerID() == gAgent.getID()))
1533 {
1534 return TRUE;
1535 }
1536 return FALSE;
1537}
1538
1539void LLFolderBridge::restoreItem()
1540{
1541 LLViewerInventoryCategory* cat;
1542 cat = (LLViewerInventoryCategory*)getCategory();
1543 if(cat)
1544 {
1545 LLInventoryModel* model = mInventoryPanel->getModel();
1546 LLUUID new_parent = model->findCategoryUUIDForType(cat->getType());
1547 // do not restamp children on restore
1548 LLInvFVBridge::changeCategoryParent(model, cat, new_parent, FALSE);
1549 }
1550}
1551
1552// Icons for folders are based on the preferred type
1553LLViewerImage* LLFolderBridge::getIcon() const
1554{
1555 const char* control = NULL;
1556 LLAssetType::EType preferred_type = LLAssetType::AT_NONE;
1557 LLViewerInventoryCategory* cat = getCategory();
1558 if(cat)
1559 {
1560 preferred_type = cat->getPreferredType();
1561 }
1562 switch(preferred_type)
1563 {
1564 case LLAssetType::AT_TEXTURE:
1565 control = "inv_folder_texture.tga";
1566 break;
1567 case LLAssetType::AT_SOUND:
1568 control = "inv_folder_sound.tga";
1569 break;
1570 case LLAssetType::AT_CALLINGCARD:
1571 control = "inv_folder_callingcard.tga";
1572 break;
1573 case LLAssetType::AT_LANDMARK:
1574 control = "inv_folder_landmark.tga";
1575 break;
1576 case LLAssetType::AT_SCRIPT:
1577 case LLAssetType::AT_LSL_TEXT:
1578 control = "inv_folder_script.tga";
1579 break;
1580 case LLAssetType::AT_OBJECT:
1581 control = "inv_folder_object.tga";
1582 break;
1583 case LLAssetType::AT_NOTECARD:
1584 control = "inv_folder_notecard.tga";
1585 break;
1586 case LLAssetType::AT_CATEGORY:
1587 control = "inv_folder_plain_closed.tga";
1588 break;
1589 case LLAssetType::AT_CLOTHING:
1590 control = "inv_folder_clothing.tga";
1591 break;
1592 case LLAssetType::AT_BODYPART:
1593 control = "inv_folder_bodypart.tga";
1594 break;
1595 case LLAssetType::AT_TRASH:
1596 control = "inv_folder_trash.tga";
1597 break;
1598 case LLAssetType::AT_SNAPSHOT_CATEGORY:
1599 control = "inv_folder_snapshot.tga";
1600 break;
1601 case LLAssetType::AT_LOST_AND_FOUND:
1602 control = "inv_folder_lostandfound.tga";
1603 break;
1604 case LLAssetType::AT_ANIMATION:
1605 control = "inv_folder_animation.tga";
1606 break;
1607 case LLAssetType::AT_GESTURE:
1608 control = "inv_folder_gesture.tga";
1609 break;
1610 default:
1611 control = "inv_folder_plain_closed.tga";
1612 break;
1613 }
1614 LLString uuid_string = gViewerArt.getString(control);
1615 return gImageList.getImage(LLUUID(uuid_string), MIPMAP_FALSE, TRUE);
1616}
1617
1618BOOL LLFolderBridge::renameItem(const LLString& new_name)
1619{
1620 if(!isItemRenameable()) return FALSE;
1621 LLInventoryModel* model = mInventoryPanel->getModel();
1622 if(!model) return FALSE;
1623 LLViewerInventoryCategory* cat = getCategory();
1624 if(cat && (cat->getName() != new_name))
1625 {
1626 LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat);
1627 new_cat->rename(new_name);
1628 new_cat->updateServer(FALSE);
1629 model->updateCategory(new_cat);
1630 model->notifyObservers();
1631 }
1632 // return FALSE because we either notified observers (& therefore
1633 // rebuilt) or we didn't update.
1634 return FALSE;
1635}
1636
1637BOOL LLFolderBridge::removeItem()
1638{
1639 if(!isItemRemovable())
1640 {
1641 return FALSE;
1642 }
1643 // move it to the trash
1644 LLPreview::hide(mUUID);
1645 LLInventoryModel* model = mInventoryPanel->getModel();
1646 if(!model) return FALSE;
1647
1648 LLUUID trash_id;
1649 trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
1650
1651 // Look for any gestures and deactivate them
1652 LLInventoryModel::cat_array_t descendent_categories;
1653 LLInventoryModel::item_array_t descendent_items;
1654 gInventory.collectDescendents( mUUID, descendent_categories, descendent_items, FALSE );
1655
1656 S32 i;
1657 for (i = 0; i < descendent_items.count(); i++)
1658 {
1659 LLInventoryItem* item = descendent_items[i];
1660 if (item->getType() == LLAssetType::AT_GESTURE
1661 && gGestureManager.isGestureActive(item->getUUID()))
1662 {
1663 gGestureManager.deactivateGesture(item->getUUID());
1664 }
1665 }
1666
1667 // go ahead and do the normal remove if no 'last calling
1668 // cards' are being removed.
1669 LLViewerInventoryCategory* cat = getCategory();
1670 if(cat)
1671 {
1672 LLInvFVBridge::changeCategoryParent(model, cat, trash_id, TRUE);
1673 }
1674
1675 // return false anyway, so that if it's called from the folder
1676 // view, it doesn't remove the view - it's just being moved to the
1677 // trash.
1678 return FALSE;
1679
1680}
1681
1682BOOL LLFolderBridge::isClipboardPasteable() const
1683{
1684 if(LLInventoryClipboard::instance().hasContents() && isAgentInventory())
1685 {
1686 return TRUE;
1687 }
1688 return FALSE;
1689}
1690
1691void LLFolderBridge::pasteFromClipboard()
1692{
1693 LLInventoryModel* model = mInventoryPanel->getModel();
1694 if(model && isClipboardPasteable())
1695 {
1696 LLInventoryItem* item = NULL;
1697 LLDynamicArray<LLUUID> objects;
1698 LLInventoryClipboard::instance().retrieve(objects);
1699 S32 count = objects.count();
1700 LLUUID parent_id(mUUID);
1701 for(S32 i = 0; i < count; i++)
1702 {
1703 item = model->getItem(objects.get(i));
1704 if (item)
1705 {
1706 copy_inventory_item(
1707 gAgent.getID(),
1708 item->getPermissions().getOwner(),
1709 item->getUUID(),
1710 parent_id,
1711 std::string(),
1712 LLPointer<LLInventoryCallback>(NULL));
1713 }
1714 }
1715 }
1716}
1717
1718void LLFolderBridge::staticFolderOptionsMenu()
1719{
1720 if (!sSelf) return;
1721 sSelf->folderOptionsMenu();
1722}
1723
1724void LLFolderBridge::folderOptionsMenu()
1725{
1726 std::vector<LLString> disabled_items;
1727
1728 LLInventoryModel* model = mInventoryPanel->getModel();
1729 if(!model) return;
1730
1731 // calling card related functionality for folders.
1732
1733 LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD);
1734 if (mCallingCards || checkFolderForContentsOfType(model, is_callingcard))
1735 {
1736 mItems.push_back("Calling Card Separator");
1737 mItems.push_back("IM Contacts In Folder");
1738 mItems.push_back("IM All Contacts In Folder");
1739 }
1740
1741 // wearables related functionality for folders.
1742 //is_wearable
1743 LLFindWearables is_wearable;
1744 LLIsType is_object( LLAssetType::AT_OBJECT );
1745 LLIsType is_gesture( LLAssetType::AT_GESTURE );
1746
1747 if (mWearables ||
1748 checkFolderForContentsOfType(model, is_wearable) ||
1749 checkFolderForContentsOfType(model, is_object) ||
1750 checkFolderForContentsOfType(model, is_gesture) )
1751 {
1752 mItems.push_back("Folder Wearables Separator");
1753 mItems.push_back("Add To Outfit");
1754 mItems.push_back("Replace Outfit");
1755 mItems.push_back("Take Off Items");
1756 }
1757 hideContextEntries(*mMenu, mItems, disabled_items);
1758}
1759
1760BOOL LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& is_type)
1761{
1762 LLInventoryModel::cat_array_t cat_array;
1763 LLInventoryModel::item_array_t item_array;
1764 model->collectDescendentsIf(mUUID,
1765 cat_array,
1766 item_array,
1767 LLInventoryModel::EXCLUDE_TRASH,
1768 is_type);
1769 return ((item_array.count() > 0) ? TRUE : FALSE );
1770}
1771
1772// Flags unused
1773void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
1774{
1775 lldebugs << "LLFolderBridge::buildContextMenu()" << llendl;
1776// std::vector<LLString> disabled_items;
1777 LLInventoryModel* model = mInventoryPanel->getModel();
1778 if(!model) return;
1779 LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
1780 if(trash_id == mUUID)
1781 {
1782 // This is the trash.
1783 mItems.push_back("Empty Trash");
1784 }
1785 else if(model->isObjectDescendentOf(mUUID, trash_id))
1786 {
1787 // This is a folder in the trash.
1788 mItems.clear(); // clear any items that used to exist
1789 mItems.push_back("Purge Item");
1790 if (!isItemRemovable())
1791 {
1792 mDisabledItems.push_back("Purge Item");
1793 }
1794
1795 mItems.push_back("Restore Item");
1796 }
1797 else if(isAgentInventory()) // do not allow creating in library
1798 {
1799 // only mature accounts can create undershirts/underwear
1800 /*if (gAgent.mAccess >= SIM_ACCESS_MATURE)
1801 {
1802 sub_menu->append(new LLMenuItemCallGL("New Undershirt",
1803 &createNewUndershirt,
1804 NULL,
1805 (void*)this));
1806 sub_menu->append(new LLMenuItemCallGL("New Underpants",
1807 &createNewUnderpants,
1808 NULL,
1809 (void*)this));
1810 }*/
1811
1812/* BOOL contains_calling_cards = FALSE;
1813 LLInventoryModel::cat_array_t cat_array;
1814 LLInventoryModel::item_array_t item_array;
1815
1816 LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD);
1817 model->collectDescendentsIf(mUUID,
1818 cat_array,
1819 item_array,
1820 LLInventoryModel::EXCLUDE_TRASH,
1821 is_callingcard);
1822 if(item_array.count() > 0) contains_calling_cards = TRUE;
1823*/
1824 mItems.push_back("New Folder");
1825 mItems.push_back("New Script");
1826 mItems.push_back("New Note");
1827 mItems.push_back("New Gesture");
1828 mItems.push_back("New Clothes");
1829 mItems.push_back("New Body Parts");
1830
1831 getClipboardEntries(false, mItems, mDisabledItems, flags);
1832
1833 //Added by spatters to force inventory pull on right-click to display folder options correctly. 07-17-06
1834 mCallingCards = mWearables = FALSE;
1835
1836 LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD);
1837 if (checkFolderForContentsOfType(model, is_callingcard))
1838 {
1839 mCallingCards=TRUE;
1840 }
1841
1842 LLFindWearables is_wearable;
1843 LLIsType is_object( LLAssetType::AT_OBJECT );
1844 LLIsType is_gesture( LLAssetType::AT_GESTURE );
1845
1846 if (checkFolderForContentsOfType(model, is_wearable) ||
1847 checkFolderForContentsOfType(model, is_object) ||
1848 checkFolderForContentsOfType(model, is_gesture) )
1849 {
1850 mWearables=TRUE;
1851 }
1852
1853 mMenu = &menu;
1854 sSelf = this;
1855 LLRightClickInventoryFetchDescendentsObserver* fetch = new LLRightClickInventoryFetchDescendentsObserver(FALSE);
1856
1857 LLInventoryFetchDescendentsObserver::folder_ref_t folders;
1858 LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID);
1859 folders.push_back(category->getUUID());
1860 fetch->fetchDescendents(folders);
1861 inc_busy_count();
1862 if(fetch->isEverythingComplete())
1863 {
1864 // everything is already here - call done.
1865 fetch->done();
1866 }
1867 else
1868 {
1869 // it's all on it's way - add an observer, and the inventory
1870 // will call done for us when everything is here.
1871 gInventory.addObserver(fetch);
1872 }
1873 }
1874 else
1875 {
1876 mItems.push_back("--no options--");
1877 mDisabledItems.push_back("--no options--");
1878 }
1879 hideContextEntries(menu, mItems, mDisabledItems);
1880}
1881
1882BOOL LLFolderBridge::hasChildren() const
1883{
1884 LLInventoryModel* model = mInventoryPanel->getModel();
1885 if(!model) return FALSE;
1886 LLInventoryModel::EHasChildren has_children;
1887 has_children = gInventory.categoryHasChildren(mUUID);
1888 return has_children != LLInventoryModel::CHILDREN_NO;
1889}
1890
1891BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop,
1892 EDragAndDropType cargo_type,
1893 void* cargo_data)
1894{
1895 //llinfos << "LLFolderBridge::dragOrDrop()" << llendl;
1896 BOOL accept = FALSE;
1897 switch(cargo_type)
1898 {
1899 case DAD_TEXTURE:
1900 case DAD_SOUND:
1901 case DAD_CALLINGCARD:
1902 case DAD_LANDMARK:
1903 case DAD_SCRIPT:
1904 case DAD_OBJECT:
1905 case DAD_NOTECARD:
1906 case DAD_CLOTHING:
1907 case DAD_BODYPART:
1908 case DAD_ANIMATION:
1909 case DAD_GESTURE:
1910 accept = dragItemIntoFolder((LLInventoryItem*)cargo_data,
1911 drop);
1912 break;
1913 case DAD_CATEGORY:
1914 accept = dragCategoryIntoFolder((LLInventoryCategory*)cargo_data,
1915 drop);
1916 break;
1917 default:
1918 break;
1919 }
1920 return accept;
1921}
1922
1923LLViewerInventoryCategory* LLFolderBridge::getCategory() const
1924{
1925 LLViewerInventoryCategory* cat = NULL;
1926 LLInventoryModel* model = mInventoryPanel->getModel();
1927 if(model)
1928 {
1929 cat = (LLViewerInventoryCategory*)model->getCategory(mUUID);
1930 }
1931 return cat;
1932}
1933
1934
1935// static
1936void LLFolderBridge::pasteClipboard(void* user_data)
1937{
1938 LLFolderBridge* self = (LLFolderBridge*)user_data;
1939 if(self) self->pasteFromClipboard();
1940}
1941
1942void LLFolderBridge::createNewCategory(void* user_data)
1943{
1944 LLFolderBridge* bridge = (LLFolderBridge*)user_data;
1945 if(!bridge) return;
1946 LLInventoryPanel* panel = bridge->mInventoryPanel;
1947 LLInventoryModel* model = panel->getModel();
1948 if(!model) return;
1949 LLUUID id;
1950 id = model->createNewCategory(bridge->getUUID(),
1951 LLAssetType::AT_NONE,
1952 NULL);
1953 model->notifyObservers();
1954
1955 // At this point, the bridge has probably been deleted, but the
1956 // view is still there.
1957 panel->setSelection(id, TAKE_FOCUS_YES);
1958}
1959
1960void LLFolderBridge::createNewShirt(void* user_data)
1961{
1962 LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SHIRT);
1963}
1964
1965void LLFolderBridge::createNewPants(void* user_data)
1966{
1967 LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_PANTS);
1968}
1969
1970void LLFolderBridge::createNewShoes(void* user_data)
1971{
1972 LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SHOES);
1973}
1974
1975void LLFolderBridge::createNewSocks(void* user_data)
1976{
1977 LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SOCKS);
1978}
1979
1980void LLFolderBridge::createNewJacket(void* user_data)
1981{
1982 LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_JACKET);
1983}
1984
1985void LLFolderBridge::createNewSkirt(void* user_data)
1986{
1987 LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SKIRT);
1988}
1989
1990void LLFolderBridge::createNewGloves(void* user_data)
1991{
1992 LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_GLOVES);
1993}
1994
1995void LLFolderBridge::createNewUndershirt(void* user_data)
1996{
1997 LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_UNDERSHIRT);
1998}
1999
2000void LLFolderBridge::createNewUnderpants(void* user_data)
2001{
2002 LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_UNDERPANTS);
2003}
2004
2005void LLFolderBridge::createNewShape(void* user_data)
2006{
2007 LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SHAPE);
2008}
2009
2010void LLFolderBridge::createNewSkin(void* user_data)
2011{
2012 LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SKIN);
2013}
2014
2015void LLFolderBridge::createNewHair(void* user_data)
2016{
2017 LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_HAIR);
2018}
2019
2020void LLFolderBridge::createNewEyes(void* user_data)
2021{
2022 LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_EYES);
2023}
2024
2025// static
2026void LLFolderBridge::createWearable(LLFolderBridge* bridge, EWearableType type)
2027{
2028 if(!bridge) return;
2029 LLUUID parent_id = bridge->getUUID();
2030 createWearable(parent_id, type);
2031}
2032
2033// Separate function so can be called by global menu as well as right-click
2034// menu.
2035// static
2036void LLFolderBridge::createWearable(LLUUID parent_id, EWearableType type)
2037{
2038 LLWearable* wearable = gWearableList.createNewWearable(type);
2039 LLAssetType::EType asset_type = wearable->getAssetType();
2040 LLInventoryType::EType inv_type = LLInventoryType::IT_WEARABLE;
2041 create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
2042 parent_id, wearable->getTransactionID(), wearable->getName(),
2043 wearable->getDescription(), asset_type, inv_type, wearable->getType(),
2044 wearable->getPermissions().getMaskNextOwner(),
2045 LLPointer<LLInventoryCallback>(NULL));
2046}
2047
2048void LLFolderBridge::beginIMSession(BOOL only_online)
2049{
2050 LLInventoryModel* model = mInventoryPanel->getModel();
2051 if(!model) return;
2052 LLViewerInventoryCategory* cat = getCategory();
2053 if(!cat) return;
2054 LLUniqueBuddyCollector is_buddy;
2055 LLInventoryModel::cat_array_t cat_array;
2056 LLInventoryModel::item_array_t item_array;
2057 model->collectDescendentsIf(mUUID,
2058 cat_array,
2059 item_array,
2060 LLInventoryModel::EXCLUDE_TRASH,
2061 is_buddy);
2062 S32 count = item_array.count();
2063 if(count > 0)
2064 {
2065 // create the session
2066 gIMView->setFloaterOpen(TRUE);
2067 LLDynamicArray<LLUUID> members;
2068 //members.put(gAgent.getID());
2069 S32 i;
2070 EInstantMessage type = IM_SESSION_ADD;
2071 if(only_online)
2072 {
2073 LLAvatarTracker& at = LLAvatarTracker::instance();
2074 LLUUID id;
2075 for(i = 0; i < count; ++i)
2076 {
2077 id = item_array.get(i)->getCreatorUUID();
2078 if(at.isBuddyOnline(id))
2079 {
2080 members.put(id);
2081 }
2082 }
2083 }
2084 else
2085 {
2086 type = IM_SESSION_OFFLINE_ADD;
2087 for(i = 0; i < count; ++i)
2088 {
2089 members.put(item_array.get(i)->getCreatorUUID());
2090 }
2091 }
2092 // the session_id is always the item_id of the inventory folder
2093 gIMView->addSession(cat->getName(),
2094 type,
2095 mUUID,
2096 members);
2097 }
2098}
2099
2100void LLFolderBridge::modifyOutfit(BOOL append)
2101{
2102 LLInventoryModel* model = mInventoryPanel->getModel();
2103 if(!model) return;
2104 LLViewerInventoryCategory* cat = getCategory();
2105 if(!cat) return;
2106
2107 wear_inventory_category_on_avatar( cat, append );
2108}
2109
2110// helper stuff
2111void move_task_inventory_callback(S32 option, void* user_data)
2112{
2113 LLMoveInv* move_inv = (LLMoveInv*)user_data;
2114 LLFloaterOpenObject::LLCatAndWear* cat_and_wear = (LLFloaterOpenObject::LLCatAndWear* )move_inv->mUserData;
2115 LLViewerObject* object = gObjectList.findObject(move_inv->mObjectID);
2116
2117 if(option == 0 && object)
2118 {
2119 if (cat_and_wear && cat_and_wear->mWear)
2120 {
2121 InventoryObjectList inventory_objects;
2122 object->getInventoryContents(inventory_objects);
2123 int contents_count = inventory_objects.size()-1; //subtract one for containing folder
2124
2125 LLInventoryCopyAndWearObserver* inventoryObserver = new LLInventoryCopyAndWearObserver(cat_and_wear->mCatID, contents_count);
2126 gInventory.addObserver(inventoryObserver);
2127 }
2128
2129 two_uuids_list_t::iterator move_it;
2130 for (move_it = move_inv->mMoveList.begin();
2131 move_it != move_inv->mMoveList.end();
2132 ++move_it)
2133 {
2134 object->moveInventory(move_it->first, move_it->second);
2135 }
2136
2137 // update the UI.
2138 dialog_refresh_all();
2139 }
2140
2141 if (move_inv->mCallback)
2142 {
2143 move_inv->mCallback(option, move_inv->mUserData);
2144 }
2145
2146 delete move_inv;
2147}
2148
2149BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
2150 BOOL drop)
2151{
2152 LLInventoryModel* model = mInventoryPanel->getModel();
2153 if(!model) return FALSE;
2154
2155 // cannot drag into library
2156 if(!isAgentInventory())
2157 {
2158 return FALSE;
2159 }
2160
2161 LLVOAvatar* avatar = gAgent.getAvatarObject();
2162 if(!avatar) return FALSE;
2163
2164 LLToolDragAndDrop::ESource source = gToolDragAndDrop->getSource();
2165 BOOL accept = FALSE;
2166 LLViewerObject* object = NULL;
2167 if(LLToolDragAndDrop::SOURCE_AGENT == source)
2168 {
2169
2170 BOOL is_movable = TRUE;
2171 switch( inv_item->getType() )
2172 {
2173 case LLAssetType::AT_ROOT_CATEGORY:
2174 is_movable = FALSE;
2175 break;
2176
2177 case LLAssetType::AT_CATEGORY:
2178 is_movable = ( LLAssetType::AT_NONE == ((LLInventoryCategory*)inv_item)->getPreferredType() );
2179 break;
2180 }
2181
2182 LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
2183 BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id);
2184 if(is_movable && move_is_into_trash)
2185 {
2186 switch(inv_item->getType())
2187 {
2188 case LLAssetType::AT_CLOTHING:
2189 case LLAssetType::AT_BODYPART:
2190 is_movable = !gAgent.isWearingItem(inv_item->getUUID());
2191 break;
2192
2193 case LLAssetType::AT_OBJECT:
2194 is_movable = !avatar->isWearingAttachment(inv_item->getUUID());
2195 break;
2196 }
2197 }
2198
2199 accept = is_movable && (mUUID != inv_item->getParentUUID());
2200 if(accept && drop)
2201 {
2202 if (inv_item->getType() == LLAssetType::AT_GESTURE
2203 && gGestureManager.isGestureActive(inv_item->getUUID()))
2204 {
2205 gGestureManager.deactivateGesture(inv_item->getUUID());
2206 }
2207 // If an item is being dragged between windows, unselect
2208 // everything in the active window so that we don't follow
2209 // the selection to its new location (which is very
2210 // annoying).
2211 LLInventoryPanel* active_panel = LLInventoryView::getActiveInventory()->getPanel();
2212 if (mInventoryPanel != active_panel)
2213 {
2214 active_panel->unSelectAll();
2215 }
2216
2217 // restamp if the move is into the trash.
2218 LLInvFVBridge::changeItemParent(
2219 model,
2220 (LLViewerInventoryItem*)inv_item,
2221 mUUID,
2222 move_is_into_trash);
2223 }
2224 }
2225 else if(LLToolDragAndDrop::SOURCE_WORLD == source)
2226 {
2227 // Make sure the object exists. If we allowed dragging from
2228 // anonymous objects, it would be possible to bypass
2229 // permissions.
2230 object = gObjectList.findObject(inv_item->getParentUUID());
2231 if(!object)
2232 {
2233 llinfos << "Object not found for drop." << llendl;
2234 return FALSE;
2235 }
2236
2237 // coming from a task. Need to figure out if the person can
2238 // move/copy this item.
2239 LLPermissions perm(inv_item->getPermissions());
2240 BOOL is_move = FALSE;
2241 if((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID())
2242 && perm.allowTransferTo(gAgent.getID())))
2243// || gAgent.isGodlike())
2244
2245 {
2246 accept = TRUE;
2247 }
2248 else if(object->permYouOwner())
2249 {
2250 // If the object cannot be copied, but the object the
2251 // inventory is owned by the agent, then the item can be
2252 // moved from the task to agent inventory.
2253 is_move = TRUE;
2254 accept = TRUE;
2255 }
2256 if(drop && accept)
2257 {
2258 LLMoveInv* move_inv = new LLMoveInv;
2259 move_inv->mObjectID = inv_item->getParentUUID();
2260 two_uuids_t item_pair(mUUID, inv_item->getUUID());
2261 move_inv->mMoveList.push_back(item_pair);
2262 move_inv->mCallback = NULL;
2263 move_inv->mUserData = NULL;
2264 if(is_move)
2265 {
2266 warn_move_inventory(object, move_inv);
2267 }
2268 else
2269 {
2270 move_task_inventory_callback(0, (void*)(move_inv));
2271 }
2272 }
2273
2274 }
2275 else if(LLToolDragAndDrop::SOURCE_NOTECARD == source)
2276 {
2277 accept = TRUE;
2278 if(drop)
2279 {
2280 copy_inventory_from_notecard(gToolDragAndDrop->getObjectID(),
2281 gToolDragAndDrop->getSourceID(), inv_item);
2282 }
2283 }
2284 else if(LLToolDragAndDrop::SOURCE_LIBRARY == source)
2285 {
2286 LLViewerInventoryItem* item = (LLViewerInventoryItem*)inv_item;
2287 if(item && item->isComplete())
2288 {
2289 accept = TRUE;
2290 if(drop)
2291 {
2292 copy_inventory_item(
2293 gAgent.getID(),
2294 inv_item->getPermissions().getOwner(),
2295 inv_item->getUUID(),
2296 mUUID,
2297 std::string(),
2298 LLPointer<LLInventoryCallback>(NULL));
2299 }
2300 }
2301 }
2302 else
2303 {
2304 llwarns << "unhandled drag source" << llendl;
2305 }
2306 return accept;
2307}
2308
2309// +=================================================+
2310// | LLScriptBridge (DEPRECTED) |
2311// +=================================================+
2312
2313LLViewerImage* LLScriptBridge::getIcon() const
2314{
2315 return get_item_icon(LLAssetType::AT_SCRIPT, LLInventoryType::IT_LSL, 0);
2316}
2317
2318// +=================================================+
2319// | LLTextureBridge |
2320// +=================================================+
2321
2322LLString LLTextureBridge::sPrefix("Texture: ");
2323
2324
2325LLViewerImage* LLTextureBridge::getIcon() const
2326{
2327 return get_item_icon(LLAssetType::AT_TEXTURE, mInvType, 0);
2328}
2329
2330void open_texture(const LLUUID& item_id,
2331 const LLString& title,
2332 BOOL show_keep_discard,
2333 const LLUUID& source_id,
2334 BOOL take_focus)
2335{
2336 // See if we can bring an exiting preview to the front
2337 if( !LLPreview::show( item_id, take_focus ) )
2338 {
2339 // There isn't one, so make a new preview
2340 S32 left, top;
2341 gFloaterView->getNewFloaterPosition(&left, &top);
2342 LLRect rect = gSavedSettings.getRect("PreviewTextureRect");
2343 rect.translate( left - rect.mLeft, top - rect.mTop );
2344
2345 LLPreviewTexture* preview;
2346 preview = new LLPreviewTexture("preview texture",
2347 rect,
2348 title,
2349 item_id,
2350 LLUUID::null,
2351 show_keep_discard);
2352 preview->setSourceID(source_id);
2353 if(take_focus) preview->setFocus(TRUE);
2354
2355 gFloaterView->adjustToFitScreen(preview, FALSE);
2356 }
2357}
2358
2359void LLTextureBridge::openItem()
2360{
2361 LLViewerInventoryItem* item = getItem();
2362 if(item)
2363 {
2364 open_texture(mUUID, getPrefix() + item->getName(), FALSE);
2365 }
2366}
2367
2368// +=================================================+
2369// | LLSoundBridge |
2370// +=================================================+
2371
2372LLString LLSoundBridge::sPrefix("Sound: ");
2373
2374
2375LLViewerImage* LLSoundBridge::getIcon() const
2376{
2377 return get_item_icon(LLAssetType::AT_SOUND, LLInventoryType::IT_SOUND, 0);
2378}
2379
2380void LLSoundBridge::openItem()
2381{
2382// Changed this back to the way it USED to work:
2383// only open the preview dialog through the contextual right-click menu
2384// double-click just plays the sound
2385
2386 LLViewerInventoryItem* item = getItem();
2387 if(item)
2388 {
2389 openSoundPreview((void*)this);
2390 //send_uuid_sound_trigger(item->getAssetUUID(), 1.0);
2391 }
2392
2393// if(!LLPreview::show(mUUID))
2394// {
2395// S32 left, top;
2396// gFloaterView->getNewFloaterPosition(&left, &top);
2397// LLRect rect = gSavedSettings.getRect("PreviewSoundRect");
2398// rect.translate(left - rect.mLeft, top - rect.mTop);
2399// new LLPreviewSound("preview sound",
2400// rect,
2401// getPrefix() + getName(),
2402// mUUID));
2403// }
2404}
2405
2406void LLSoundBridge::previewItem()
2407{
2408 LLViewerInventoryItem* item = getItem();
2409 if(item)
2410 {
2411 send_sound_trigger(item->getAssetUUID(), 1.0);
2412 }
2413}
2414
2415void LLSoundBridge::openSoundPreview(void* which)
2416{
2417 LLSoundBridge *me = (LLSoundBridge *)which;
2418 if(!LLPreview::show(me->mUUID))
2419 {
2420 S32 left, top;
2421 gFloaterView->getNewFloaterPosition(&left, &top);
2422 LLRect rect = gSavedSettings.getRect("PreviewSoundRect");
2423 rect.translate(left - rect.mLeft, top - rect.mTop);
2424 LLPreviewSound* preview = new LLPreviewSound("preview sound",
2425 rect,
2426 me->getPrefix() + me->getName(),
2427 me->mUUID);
2428 preview->setFocus(TRUE);
2429 // Keep entirely onscreen.
2430 gFloaterView->adjustToFitScreen(preview, FALSE);
2431 }
2432}
2433
2434void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
2435{
2436 lldebugs << "LLTextureBridge::buildContextMenu()" << llendl;
2437 std::vector<LLString> items;
2438 std::vector<LLString> disabled_items;
2439
2440 if(isInTrash())
2441 {
2442 items.push_back("Purge Item");
2443 if (!isItemRemovable())
2444 {
2445 disabled_items.push_back("Purge Item");
2446 }
2447
2448 items.push_back("Restore Item");
2449 }
2450 else
2451 {
2452 items.push_back("Sound Open");
2453 items.push_back("Properties");
2454
2455 getClipboardEntries(true, items, disabled_items, flags);
2456 }
2457
2458 items.push_back("Sound Separator");
2459 items.push_back("Sound Play");
2460
2461 hideContextEntries(menu, items, disabled_items);
2462}
2463
2464// +=================================================+
2465// | LLLandmarkBridge |
2466// +=================================================+
2467
2468LLString LLLandmarkBridge::sPrefix("Landmark: ");
2469
2470LLViewerImage* LLLandmarkBridge::getIcon() const
2471{
2472 return get_item_icon(LLAssetType::AT_LANDMARK, LLInventoryType::IT_LANDMARK, mVisited);
2473}
2474
2475void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
2476{
2477 std::vector<LLString> items;
2478 std::vector<LLString> disabled_items;
2479
2480 lldebugs << "LLLandmarkBridge::buildContextMenu()" << llendl;
2481 if(isInTrash())
2482 {
2483 items.push_back("Purge Item");
2484 if (!isItemRemovable())
2485 {
2486 disabled_items.push_back("Purge Item");
2487 }
2488
2489 items.push_back("Restore Item");
2490 }
2491 else
2492 {
2493 items.push_back("Landmark Open");
2494 items.push_back("Properties");
2495
2496 getClipboardEntries(true, items, disabled_items, flags);
2497 }
2498
2499 items.push_back("Landmark Separator");
2500 items.push_back("Teleport To Landmark");
2501
2502 hideContextEntries(menu, items, disabled_items);
2503
2504}
2505
2506// virtual
2507void LLLandmarkBridge::performAction(LLFolderView* folder, LLInventoryModel* model, LLString action)
2508{
2509 if ("teleport" == action)
2510 {
2511 LLViewerInventoryItem* item = getItem();
2512 if(item)
2513 {
2514 gAgent.teleportViaLandmark(item->getAssetUUID());
2515
2516 // we now automatically track the landmark you're teleporting to
2517 // because you'll probably arrive at a telehub instead
2518 if( gFloaterWorldMap )
2519 {
2520 gFloaterWorldMap->trackLandmark( item->getAssetUUID() );
2521 }
2522 }
2523 }
2524 else LLItemBridge::performAction(folder, model, action);
2525}
2526
2527void open_landmark(const LLUUID& item_id,
2528 const LLString& title,
2529 BOOL show_keep_discard,
2530 const LLUUID& source_id,
2531 BOOL take_focus)
2532{
2533 // See if we can bring an exiting preview to the front
2534 if( !LLPreview::show( item_id, take_focus ) )
2535 {
2536 // There isn't one, so make a new preview
2537 S32 left, top;
2538 gFloaterView->getNewFloaterPosition(&left, &top);
2539 LLRect rect = gSavedSettings.getRect("PreviewLandmarkRect");
2540 rect.translate( left - rect.mLeft, top - rect.mTop );
2541
2542 LLPreviewLandmark* preview = new LLPreviewLandmark("preview landmark",
2543 rect,
2544 title,
2545 item_id,
2546 show_keep_discard);
2547 preview->setSourceID(source_id);
2548 if(take_focus) preview->setFocus(TRUE);
2549 // keep onscreen
2550 gFloaterView->adjustToFitScreen(preview, FALSE);
2551 }
2552}
2553
2554void LLLandmarkBridge::openItem()
2555{
2556 LLViewerInventoryItem* item = getItem();
2557 if( item )
2558 {
2559 open_landmark(mUUID, LLString(" ") + getPrefix() + item->getName(), FALSE);
2560 }
2561}
2562
2563
2564// +=================================================+
2565// | LLCallingCardObserver |
2566// +=================================================+
2567void LLCallingCardObserver::changed(U32 mask)
2568{
2569 mBridgep->refreshFolderViewItem();
2570}
2571
2572// +=================================================+
2573// | LLCallingCardBridge |
2574// +=================================================+
2575
2576LLString LLCallingCardBridge::sPrefix("Calling Card: ");
2577
2578LLCallingCardBridge::LLCallingCardBridge( LLInventoryPanel* inventory, const LLUUID& uuid ) :
2579 LLItemBridge(inventory, uuid)
2580{
2581 mObserver = new LLCallingCardObserver(this);
2582 LLAvatarTracker::instance().addObserver(mObserver);
2583}
2584
2585LLCallingCardBridge::~LLCallingCardBridge()
2586{
2587 LLAvatarTracker::instance().removeObserver(mObserver);
2588 delete mObserver;
2589}
2590
2591void LLCallingCardBridge::refreshFolderViewItem()
2592{
2593 LLFolderViewItem* itemp = mInventoryPanel->getRootFolder()->getItemByID(mUUID);
2594 if (itemp)
2595 {
2596 itemp->refresh();
2597 }
2598}
2599
2600// virtual
2601void LLCallingCardBridge::performAction(LLFolderView* folder, LLInventoryModel* model, LLString action)
2602{
2603 if ("begin_im" == action)
2604 {
2605 LLViewerInventoryItem *item = getItem();
2606 if (item && (item->getCreatorUUID() != gAgent.getID()) &&
2607 (!item->getCreatorUUID().isNull()))
2608 {
2609 gIMView->setFloaterOpen(TRUE);
2610 gIMView->addSession(item->getName(), IM_NOTHING_SPECIAL, item->getCreatorUUID());
2611 }
2612 }
2613 else if ("lure" == action)
2614 {
2615 LLViewerInventoryItem *item = getItem();
2616 if (item && (item->getCreatorUUID() != gAgent.getID()) &&
2617 (!item->getCreatorUUID().isNull()))
2618 {
2619 handle_lure(item->getCreatorUUID());
2620 }
2621 }
2622 else LLItemBridge::performAction(folder, model, action);
2623}
2624
2625LLViewerImage* LLCallingCardBridge::getIcon() const
2626{
2627 BOOL online = FALSE;
2628 LLViewerInventoryItem* item = getItem();
2629 if(item)
2630 {
2631 online = LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID());
2632 }
2633 return get_item_icon(LLAssetType::AT_CALLINGCARD, LLInventoryType::IT_CALLINGCARD, online);
2634}
2635
2636LLString LLCallingCardBridge::getLabelSuffix() const
2637{
2638 LLViewerInventoryItem* item = getItem();
2639 if( item && LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID()) )
2640 {
2641 return LLItemBridge::getLabelSuffix() + " (online)";
2642 }
2643 else
2644 {
2645 return LLItemBridge::getLabelSuffix();
2646 }
2647}
2648
2649void LLCallingCardBridge::openItem()
2650{
2651 LLViewerInventoryItem* item = getItem();
2652 if(item && !item->getCreatorUUID().isNull())
2653 {
2654 BOOL online;
2655 online = LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID());
2656 LLFloaterAvatarInfo::showFromFriend(item->getCreatorUUID(), online);
2657 }
2658}
2659
2660void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
2661{
2662 lldebugs << "LLCallingCardBridge::buildContextMenu()" << llendl;
2663 std::vector<LLString> items;
2664 std::vector<LLString> disabled_items;
2665
2666 if(isInTrash())
2667 {
2668 items.push_back("Purge Item");
2669 if (!isItemRemovable())
2670 {
2671 disabled_items.push_back("Purge Item");
2672 }
2673
2674 items.push_back("Restore Item");
2675 }
2676 else
2677 {
2678 items.push_back("Open");
2679 items.push_back("Properties");
2680
2681 getClipboardEntries(true, items, disabled_items, flags);
2682
2683 LLInventoryItem* item = getItem();
2684 BOOL good_card = (item
2685 && (LLUUID::null != item->getCreatorUUID())
2686 && (item->getCreatorUUID() != gAgent.getID()));
2687
2688 items.push_back("Send Instant Message");
2689 items.push_back("Offer Teleport...");
2690
2691 if (!good_card)
2692 {
2693 disabled_items.push_back("Send Instant Message");
2694 disabled_items.push_back("Offer Teleport...");
2695 }
2696 }
2697 hideContextEntries(menu, items, disabled_items);
2698}
2699
2700BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop,
2701 EDragAndDropType cargo_type,
2702 void* cargo_data)
2703{
2704 LLViewerInventoryItem* item = getItem();
2705 BOOL rv = FALSE;
2706 if(item)
2707 {
2708 // check the type
2709 switch(cargo_type)
2710 {
2711 case DAD_TEXTURE:
2712 case DAD_SOUND:
2713 case DAD_LANDMARK:
2714 case DAD_SCRIPT:
2715 case DAD_CLOTHING:
2716 case DAD_OBJECT:
2717 case DAD_NOTECARD:
2718 case DAD_BODYPART:
2719 case DAD_ANIMATION:
2720 case DAD_GESTURE:
2721 {
2722 LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data;
2723 const LLPermissions& perm = inv_item->getPermissions();
2724 if(gInventory.getItem(inv_item->getUUID())
2725 && perm.allowOperationBy(PERM_TRANSFER, gAgent.getID()))
2726 {
2727 rv = TRUE;
2728 if(drop)
2729 {
2730 LLToolDragAndDrop::giveInventory(item->getCreatorUUID(),
2731 (LLInventoryItem*)cargo_data);
2732 }
2733 }
2734 else
2735 {
2736 // It's not in the user's inventory (it's probably in
2737 // an object's contents), so disallow dragging it here.
2738 // You can't give something you don't yet have.
2739 rv = FALSE;
2740 }
2741 break;
2742 }
2743 case DAD_CATEGORY:
2744 {
2745 LLInventoryCategory* inv_cat = (LLInventoryCategory*)cargo_data;
2746 if( gInventory.getCategory( inv_cat->getUUID() ) )
2747 {
2748 rv = TRUE;
2749 if(drop)
2750 {
2751 LLToolDragAndDrop::giveInventoryCategory(
2752 item->getCreatorUUID(),
2753 inv_cat);
2754 }
2755 }
2756 else
2757 {
2758 // It's not in the user's inventory (it's probably in
2759 // an object's contents), so disallow dragging it here.
2760 // You can't give something you don't yet have.
2761 rv = FALSE;
2762 }
2763 break;
2764 }
2765 }
2766 }
2767 return rv;
2768}
2769
2770// +=================================================+
2771// | LLNotecardBridge |
2772// +=================================================+
2773
2774LLString LLNotecardBridge::sPrefix("Note: ");
2775
2776
2777LLViewerImage* LLNotecardBridge::getIcon() const
2778{
2779 return get_item_icon(LLAssetType::AT_NOTECARD, LLInventoryType::IT_NOTECARD, 0);
2780}
2781
2782void open_notecard(const LLUUID& item_id,
2783 const LLString& title,
2784 BOOL show_keep_discard,
2785 const LLUUID& source_id,
2786 BOOL take_focus)
2787{
2788 // See if we can bring an existing preview to the front
2789 if(!LLPreview::show(item_id, take_focus))
2790 {
2791 // There isn't one, so make a new preview
2792 S32 left, top;
2793 gFloaterView->getNewFloaterPosition(&left, &top);
2794 LLRect rect = gSavedSettings.getRect("NotecardEditorRect");
2795 rect.translate(left - rect.mLeft, top - rect.mTop);
2796 LLPreviewNotecard* preview;
2797 preview = new LLPreviewNotecard("preview notecard",
2798 rect,
2799 title,
2800 item_id,
2801 LLUUID::null,
2802 LLUUID::null,
2803 show_keep_discard);
2804 preview->setSourceID(source_id);
2805 if(take_focus) preview->setFocus(TRUE);
2806 // Force to be entirely onscreen.
2807 gFloaterView->adjustToFitScreen(preview, FALSE);
2808
2809 //if (source_id.notNull())
2810 //{
2811 // // look for existing tabbed view for content from same source
2812 // LLPreview* existing_preview = LLPreview::getPreviewForSource(source_id);
2813 // if (existing_preview)
2814 // {
2815 // // found existing preview from this source
2816 // // is it already hosted in a multi-preview window?
2817 // LLMultiPreview* preview_hostp = (LLMultiPreview*)existing_preview->getHost();
2818 // if (!preview_hostp)
2819 // {
2820 // // create new multipreview if it doesn't exist
2821 // LLMultiPreview* preview_hostp = new LLMultiPreview(existing_preview->getRect());
2822
2823 // preview_hostp->addFloater(existing_preview);
2824 // }
2825 // // add this preview to existing host
2826 // preview_hostp->addFloater(preview);
2827 // }
2828 //}
2829
2830 }
2831}
2832
2833void LLNotecardBridge::openItem()
2834{
2835 LLViewerInventoryItem* item = getItem();
2836 if (item)
2837 {
2838 open_notecard(mUUID, getPrefix() + item->getName(), FALSE);
2839 }
2840}
2841
2842
2843// +=================================================+
2844// | LLGestureBridge |
2845// +=================================================+
2846
2847LLString LLGestureBridge::sPrefix("Gesture: ");
2848
2849LLViewerImage* LLGestureBridge::getIcon() const
2850{
2851 return get_item_icon(LLAssetType::AT_GESTURE, LLInventoryType::IT_GESTURE, 0);
2852}
2853
2854LLFontGL::StyleFlags LLGestureBridge::getLabelStyle() const
2855{
2856 if( gGestureManager.isGestureActive(mUUID) )
2857 {
2858 return LLFontGL::BOLD;
2859 }
2860 else
2861 {
2862 return LLFontGL::NORMAL;
2863 }
2864}
2865
2866LLString LLGestureBridge::getLabelSuffix() const
2867{
2868 if( gGestureManager.isGestureActive(mUUID) )
2869 {
2870 return LLItemBridge::getLabelSuffix() + " (active)";
2871 }
2872 else
2873 {
2874 return LLItemBridge::getLabelSuffix();
2875 }
2876}
2877
2878// virtual
2879void LLGestureBridge::performAction(LLFolderView* folder, LLInventoryModel* model, LLString action)
2880{
2881 if ("activate" == action)
2882 {
2883 gGestureManager.activateGesture(mUUID);
2884
2885 LLViewerInventoryItem* item = gInventory.getItem(mUUID);
2886 if (!item) return;
2887
2888 // Since we just changed the suffix to indicate (active)
2889 // the server doesn't need to know, just the viewer.
2890 gInventory.updateItem(item);
2891 gInventory.notifyObservers();
2892 }
2893 else if ("deactivate" == action)
2894 {
2895 gGestureManager.deactivateGesture(mUUID);
2896
2897 LLViewerInventoryItem* item = gInventory.getItem(mUUID);
2898 if (!item) return;
2899
2900 // Since we just changed the suffix to indicate (active)
2901 // the server doesn't need to know, just the viewer.
2902 gInventory.updateItem(item);
2903 gInventory.notifyObservers();
2904 }
2905 else LLItemBridge::performAction(folder, model, action);
2906}
2907
2908void LLGestureBridge::openItem()
2909{
2910 LLViewerInventoryItem* item = getItem();
2911 if (!item) return;
2912
2913 // See if we can bring an existing preview to the front
2914 if(!LLPreview::show(mUUID))
2915 {
2916 LLUUID item_id = mUUID;
2917 LLString title = getPrefix() + item->getName();
2918 LLUUID object_id = LLUUID::null;
2919
2920 // TODO: save the rectangle
2921 LLPreviewGesture* preview = LLPreviewGesture::show(title, item_id, object_id);
2922 preview->setFocus(TRUE);
2923
2924 // Force to be entirely onscreen.
2925 gFloaterView->adjustToFitScreen(preview, FALSE);
2926 }
2927}
2928
2929BOOL LLGestureBridge::removeItem()
2930{
2931 // Force close the preview window, if it exists
2932 LLPreview::hide(mUUID);
2933 gGestureManager.deactivateGesture(mUUID);
2934 return LLItemBridge::removeItem();
2935}
2936
2937void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
2938{
2939 lldebugs << "LLGestureBridge::buildContextMenu()" << llendl;
2940 std::vector<LLString> items;
2941 std::vector<LLString> disabled_items;
2942 if(isInTrash())
2943 {
2944 items.push_back("Purge Item");
2945 if (!isItemRemovable())
2946 {
2947 disabled_items.push_back("Purge Item");
2948 }
2949
2950 items.push_back("Restore Item");
2951 }
2952 else
2953 {
2954 items.push_back("Open");
2955 items.push_back("Properties");
2956
2957 getClipboardEntries(true, items, disabled_items, flags);
2958
2959 items.push_back("Gesture Separator");
2960 items.push_back("Activate");
2961 items.push_back("Deactivate");
2962
2963 /*menu.append(new LLMenuItemCallGL("Activate",
2964 handleActivateGesture,
2965 enableActivateGesture,
2966 (void*)this));
2967 menu.append(new LLMenuItemCallGL("Deactivate",
2968 handleDeactivateGesture,
2969 enableDeactivateGesture,
2970 (void*)this));*/
2971 }
2972 hideContextEntries(menu, items, disabled_items);
2973}
2974
2975// +=================================================+
2976// | LLAnimationBridge |
2977// +=================================================+
2978
2979LLString LLAnimationBridge::sPrefix("Animation: ");
2980
2981
2982LLViewerImage* LLAnimationBridge::getIcon() const
2983{
2984 return get_item_icon(LLAssetType::AT_ANIMATION, LLInventoryType::IT_ANIMATION, 0);
2985}
2986
2987void LLAnimationBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
2988{
2989 std::vector<LLString> items;
2990 std::vector<LLString> disabled_items;
2991
2992 lldebugs << "LLAnimationBridge::buildContextMenu()" << llendl;
2993 if(isInTrash())
2994 {
2995 items.push_back("Purge Item");
2996 if (!isItemRemovable())
2997 {
2998 disabled_items.push_back("Purge Item");
2999 }
3000
3001 items.push_back("Restore Item");
3002 }
3003 else
3004 {
3005 items.push_back("Animation Open");
3006 items.push_back("Properties");
3007
3008 getClipboardEntries(true, items, disabled_items, flags);
3009 }
3010
3011 items.push_back("Animation Separator");
3012 items.push_back("Animation Play");
3013 items.push_back("Animation Audition");
3014
3015 hideContextEntries(menu, items, disabled_items);
3016
3017}
3018
3019// virtual
3020void LLAnimationBridge::performAction(LLFolderView* folder, LLInventoryModel* model, LLString action)
3021{
3022 S32 activate = 0;
3023
3024 if ((action == "playworld") || (action == "playlocal"))
3025 {
3026
3027 if ("playworld" == action) activate = 1;
3028 if ("playlocal" == action) activate = 2;
3029
3030 // See if we can bring an existing preview to the front
3031 if( !LLPreview::show( mUUID ) )
3032 {
3033 // There isn't one, so make a new preview
3034 LLViewerInventoryItem* item = getItem();
3035 if( item )
3036 {
3037 S32 left, top;
3038 gFloaterView->getNewFloaterPosition(&left, &top);
3039 LLRect rect = gSavedSettings.getRect("PreviewAnimRect");
3040 rect.translate( left - rect.mLeft, top - rect.mTop );
3041 LLPreviewAnim* preview = new LLPreviewAnim("preview anim",
3042 rect,
3043 getPrefix() + item->getName(),
3044 mUUID,
3045 activate);
3046 // Force to be entirely onscreen.
3047 gFloaterView->adjustToFitScreen(preview, FALSE);
3048 }
3049 }
3050 }
3051 else
3052 {
3053 LLItemBridge::performAction(folder, model, action);
3054 }
3055}
3056
3057void LLAnimationBridge::openItem()
3058{
3059 // See if we can bring an existing preview to the front
3060 if( !LLPreview::show( mUUID ) )
3061 {
3062 // There isn't one, so make a new preview
3063 LLViewerInventoryItem* item = getItem();
3064 if( item )
3065 {
3066 S32 left, top;
3067 gFloaterView->getNewFloaterPosition(&left, &top);
3068 LLRect rect = gSavedSettings.getRect("PreviewAnimRect");
3069 rect.translate( left - rect.mLeft, top - rect.mTop );
3070 LLPreviewAnim* preview = new LLPreviewAnim("preview anim",
3071 rect,
3072 getPrefix() + item->getName(),
3073 mUUID,
3074 0);
3075 preview->setFocus(TRUE);
3076 // Force to be entirely onscreen.
3077 gFloaterView->adjustToFitScreen(preview, FALSE);
3078 }
3079 }
3080}
3081
3082// +=================================================+
3083// | LLObjectBridge |
3084// +=================================================+
3085
3086// static
3087LLString LLObjectBridge::sPrefix("Object: ");
3088
3089// static
3090LLUUID LLObjectBridge::sContextMenuItemID;
3091
3092BOOL LLObjectBridge::isItemRemovable()
3093{
3094 LLVOAvatar* avatar = gAgent.getAvatarObject();
3095 if(!avatar) return FALSE;
3096 if(avatar->isWearingAttachment(mUUID)) return FALSE;
3097 return LLInvFVBridge::isItemRemovable();
3098}
3099
3100LLViewerImage* LLObjectBridge::getIcon() const
3101{
3102 return get_item_icon(LLAssetType::AT_OBJECT, mInvType, mAttachPt);
3103}
3104
3105void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment);
3106
3107// virtual
3108void LLObjectBridge::performAction(LLFolderView* folder, LLInventoryModel* model, LLString action)
3109{
3110 if ("attach" == action)
3111 {
3112 LLUUID object_id = mUUID;
3113 LLViewerInventoryItem* item;
3114 item = (LLViewerInventoryItem*)gInventory.getItem(object_id);
3115 if(item && gInventory.isObjectDescendentOf(object_id, gAgent.getInventoryRootID()))
3116 {
3117 rez_attachment(item, NULL);
3118 }
3119 else if(item && item->isComplete())
3120 {
3121 // must be in library. copy it to our inventory and put it on.
3122 LLPointer<LLInventoryCallback> cb = new RezAttachmentCallback(0);
3123 copy_inventory_item(
3124 gAgent.getID(),
3125 item->getPermissions().getOwner(),
3126 item->getUUID(),
3127 LLUUID::null,
3128 std::string(),
3129 cb);
3130 }
3131 gFocusMgr.setKeyboardFocus(NULL, NULL);
3132 }
3133 else if ("detach" == action)
3134 {
3135 LLInventoryItem* item = gInventory.getItem(mUUID);
3136 if( item )
3137 {
3138 gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv);
3139 gMessageSystem->nextBlockFast(_PREHASH_ObjectData );
3140 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
3141 gMessageSystem->addUUIDFast(_PREHASH_ItemID, item->getUUID() );
3142
3143 gMessageSystem->sendReliable( gAgent.getRegion()->getHost() );
3144 }
3145 // this object might have been selected, so let the selection manager know it's gone now
3146 gSelectMgr->remove(gObjectList.findObject(item->getUUID()));
3147 }
3148 else LLItemBridge::performAction(folder, model, action);
3149}
3150
3151void LLObjectBridge::openItem()
3152{
3153 /* Disabled -- this preview isn't useful. JC */
3154 // CP: actually, this code is required - made changes to match LLAnimationBridge::openItem() idiom
3155 // The properties preview is useful, converting to show object properties. - DaveP
3156 LLShowProps::showProperties(mUUID);
3157}
3158
3159LLFontGL::StyleFlags LLObjectBridge::getLabelStyle() const
3160{
3161 LLVOAvatar* avatar = gAgent.getAvatarObject();
3162 if( avatar && avatar->isWearingAttachment( mUUID ) )
3163 {
3164 return LLFontGL::BOLD;
3165 }
3166 else
3167 {
3168 return LLFontGL::NORMAL;
3169 }
3170}
3171
3172LLString LLObjectBridge::getLabelSuffix() const
3173{
3174 LLVOAvatar* avatar = gAgent.getAvatarObject();
3175 if( avatar && avatar->isWearingAttachment( mUUID ) )
3176 {
3177 LLString attachment_point_name = avatar->getAttachedPointName(mUUID);
3178 LLString::toLower(attachment_point_name);
3179 return LLItemBridge::getLabelSuffix() + LLString(" (worn on ") + attachment_point_name + LLString(")");
3180 }
3181 else
3182 {
3183 return LLItemBridge::getLabelSuffix();
3184 }
3185}
3186
3187void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment)
3188{
3189 LLAttachmentRezAction* rez_action = new LLAttachmentRezAction;
3190 rez_action->mItemID = item->getUUID();
3191 rez_action->mAttachPt = gAgent.getAvatarObject()->mAttachmentPoints.reverseLookup(attachment);
3192
3193 if (attachment && attachment->getObject(0))
3194 {
3195 gViewerWindow->alertXml("ReplaceAttachment", confirm_replace_attachment_rez, (void*)rez_action);
3196 }
3197 else
3198 {
3199 confirm_replace_attachment_rez(0/*YES*/, (void*)rez_action);
3200 }
3201}
3202
3203void confirm_replace_attachment_rez(S32 option, void* user_data)
3204{
3205 LLAttachmentRezAction* rez_action = (LLAttachmentRezAction*)user_data;
3206 if (option == 0/*YES*/)
3207 {
3208 if (rez_action)
3209 {
3210 LLViewerInventoryItem* itemp = gInventory.getItem(rez_action->mItemID);
3211
3212 if (itemp)
3213 {
3214 LLMessageSystem* msg = gMessageSystem;
3215 msg->newMessageFast(_PREHASH_RezSingleAttachmentFromInv);
3216 msg->nextBlockFast(_PREHASH_AgentData);
3217 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
3218 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
3219 msg->nextBlockFast(_PREHASH_ObjectData);
3220 msg->addUUIDFast(_PREHASH_ItemID, itemp->getUUID());
3221 msg->addUUIDFast(_PREHASH_OwnerID, itemp->getPermissions().getOwner());
3222 msg->addU8Fast(_PREHASH_AttachmentPt, rez_action->mAttachPt);
3223 pack_permissions_slam(msg, itemp->getFlags(), itemp->getPermissions());
3224 msg->addStringFast(_PREHASH_Name, itemp->getName());
3225 msg->addStringFast(_PREHASH_Description, itemp->getDescription());
3226 msg->sendReliable(gAgent.getRegion()->getHost());
3227 }
3228 }
3229 }
3230 delete rez_action;
3231}
3232
3233void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
3234{
3235 std::vector<LLString> items;
3236 std::vector<LLString> disabled_items;
3237 if(isInTrash())
3238 {
3239 items.push_back("Purge Item");
3240 if (!isItemRemovable())
3241 {
3242 disabled_items.push_back("Purge Item");
3243 }
3244
3245 items.push_back("Restore Item");
3246 }
3247 else
3248 {
3249 items.push_back("Properties");
3250
3251 getClipboardEntries(true, items, disabled_items, flags);
3252
3253 LLObjectBridge::sContextMenuItemID = mUUID;
3254
3255 LLInventoryItem* item = getItem();
3256 if(item)
3257 {
3258 LLVOAvatar *avatarp = gAgent.getAvatarObject();
3259 if( !avatarp )
3260 {
3261 return;
3262 }
3263
3264 if( avatarp->isWearingAttachment( mUUID ) )
3265 {
3266 items.push_back("Detach From Yourself");
3267 }
3268 else
3269 if( !isInTrash() )
3270 {
3271 items.push_back("Attach Separator");
3272 items.push_back("Object Wear");
3273 items.push_back("Attach To");
3274 items.push_back("Attach To HUD");
3275
3276 LLMenuGL* attach_menu = menu.getChildMenuByName("Attach To", TRUE);
3277 LLMenuGL* attach_hud_menu = menu.getChildMenuByName("Attach To HUD", TRUE);
3278 LLVOAvatar *avatarp = gAgent.getAvatarObject();
3279 if (attach_menu && (attach_menu->getChildCount() == 0) &&
3280 attach_hud_menu && (attach_hud_menu->getChildCount() == 0) &&
3281 avatarp)
3282 {
3283 for (LLViewerJointAttachment* attachment = avatarp->mAttachmentPoints.getFirstData();
3284 attachment;
3285 attachment = gAgent.getAvatarObject()->mAttachmentPoints.getNextData())
3286 {
3287 LLMenuItemCallGL *new_item;
3288 if (attachment->getIsHUDAttachment())
3289 {
3290 attach_hud_menu->append(new_item = new LLMenuItemCallGL(attachment->getName(),
3291 NULL, //&LLObjectBridge::attachToAvatar,
3292 NULL, &attach_label, (void*)attachment));
3293 }
3294 else
3295 {
3296 attach_menu->append(new_item = new LLMenuItemCallGL(attachment->getName(),
3297 NULL, //&LLObjectBridge::attachToAvatar,
3298 NULL, &attach_label, (void*)attachment));
3299 }
3300
3301 LLSimpleListener* callback = mInventoryPanel->getListenerByName("Inventory.AttachObject");
3302
3303 if (callback)
3304 {
3305 new_item->addListener(callback, "on_click", LLSD(attachment->getName()));
3306 }
3307 }
3308 }
3309 }
3310 }
3311 }
3312 hideContextEntries(menu, items, disabled_items);
3313}
3314
3315BOOL LLObjectBridge::renameItem(const LLString& new_name)
3316{
3317 if(!isItemRenameable()) return FALSE;
3318 LLPreview::rename(mUUID, getPrefix() + new_name);
3319 LLInventoryModel* model = mInventoryPanel->getModel();
3320 if(!model) return FALSE;
3321 LLViewerInventoryItem* item = getItem();
3322 if(item && (item->getName() != new_name))
3323 {
3324 LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
3325 new_item->rename(new_name);
3326 buildDisplayName(new_item, mDisplayName);
3327 new_item->updateServer(FALSE);
3328 model->updateItem(new_item);
3329 model->notifyObservers();
3330
3331 LLVOAvatar* avatar = gAgent.getAvatarObject();
3332 if( avatar )
3333 {
3334 LLViewerObject* obj = avatar->getWornAttachment( item->getUUID() );
3335 if( obj )
3336 {
3337 gSelectMgr->deselectAll();
3338 gSelectMgr->addAsIndividual( obj, SELECT_ALL_TES, FALSE );
3339 gSelectMgr->setObjectName( new_name );
3340 gSelectMgr->deselectAll();
3341 }
3342 }
3343 }
3344 // return FALSE because we either notified observers (& therefore
3345 // rebuilt) or we didn't update.
3346 return FALSE;
3347}
3348
3349// +=================================================+
3350// | LLLSLTextBridge |
3351// +=================================================+
3352
3353LLString LLLSLTextBridge::sPrefix("Script: ");
3354
3355LLViewerImage* LLLSLTextBridge::getIcon() const
3356{
3357 return get_item_icon(LLAssetType::AT_SCRIPT, LLInventoryType::IT_LSL, 0);
3358}
3359
3360void LLLSLTextBridge::openItem()
3361{
3362 // See if we can bring an exiting preview to the front
3363 if(!LLPreview::show(mUUID))
3364 {
3365 LLViewerInventoryItem* item = getItem();
3366 if (item)
3367 {
3368 // There isn't one, so make a new preview
3369 S32 left, top;
3370 gFloaterView->getNewFloaterPosition(&left, &top);
3371 LLRect rect = gSavedSettings.getRect("PreviewScriptRect");
3372 rect.translate(left - rect.mLeft, top - rect.mTop);
3373
3374 LLPreviewLSL* preview = new LLPreviewLSL("preview lsl text",
3375 rect,
3376 getPrefix() + item->getName(),
3377 mUUID);
3378 preview->setFocus(TRUE);
3379 // keep onscreen
3380 gFloaterView->adjustToFitScreen(preview, FALSE);
3381 }
3382 }
3383}
3384
3385// +=================================================+
3386// | LLWearableBridge |
3387// +=================================================+
3388
3389// *NOTE: hack to get from avatar inventory to avatar
3390void wear_inventory_item_on_avatar( LLInventoryItem* item )
3391{
3392 if(item)
3393 {
3394 lldebugs << "wear_inventory_item_on_avatar( " << item->getName()
3395 << " )" << llendl;
3396
3397 gWearableList.getAsset(item->getAssetUUID(),
3398 item->getName(),
3399 item->getType(),
3400 LLWearableBridge::onWearOnAvatarArrived,
3401 new LLUUID(item->getUUID()));
3402 }
3403}
3404
3405struct LLFoundData
3406{
3407 LLFoundData(const LLUUID& item_id,
3408 const LLUUID& asset_id,
3409 const LLString& name,
3410 LLAssetType::EType asset_type) :
3411 mItemID(item_id),
3412 mAssetID(asset_id),
3413 mAssetType(asset_type),
3414 mName(name),
3415 mWearable( NULL ) {}
3416
3417 LLUUID mItemID;
3418 LLUUID mAssetID;
3419 LLString mName;
3420 LLAssetType::EType mAssetType;
3421 LLWearable* mWearable;
3422};
3423
3424struct LLWearableHoldingPattern
3425{
3426 LLWearableHoldingPattern() : mResolved(0) {}
3427 ~LLWearableHoldingPattern() { mFoundList.deleteAllData(); }
3428 LLDoubleLinkedList<LLFoundData> mFoundList;
3429 S32 mResolved;
3430};
3431
3432
3433class LLOutfitObserver : public LLInventoryFetchObserver
3434{
3435public:
3436 LLOutfitObserver(const LLUUID& cat_id, bool copy_items, bool append) :
3437 mCatID(cat_id),
3438 mCopyItems(copy_items),
3439 mAppend(append)
3440 {}
3441 ~LLOutfitObserver() {}
3442 virtual void done(); //public
3443
3444protected:
3445 LLUUID mCatID;
3446 bool mCopyItems;
3447 bool mAppend;
3448};
3449
3450class LLWearInventoryCategoryCallback : public LLInventoryCallback
3451{
3452public:
3453 LLWearInventoryCategoryCallback(const LLUUID& cat_id, bool append)
3454 {
3455 mCatID = cat_id;
3456 mAppend = append;
3457 }
3458 void fire(const LLUUID& item_id)
3459 {
3460 /*
3461 * Do nothing. We only care about the destructor
3462 */
3463 }
3464 ~LLWearInventoryCategoryCallback()
3465 {
3466 wear_inventory_category_on_avatar(gInventory.getCategory(mCatID), mAppend);
3467 }
3468private:
3469 LLUUID mCatID;
3470 bool mAppend;
3471};
3472
3473void LLOutfitObserver::done()
3474{
3475 // We now have an outfit ready to be copied to agent inventory. Do
3476 // it, and wear that outfit normally.
3477 if(mCopyItems)
3478 {
3479 LLInventoryCategory* cat = gInventory.getCategory(mCatID);
3480 LLString name;
3481 if(!cat)
3482 {
3483 // should never happen.
3484 name = "New Outfit";
3485 }
3486 else
3487 {
3488 name = cat->getName();
3489 }
3490 LLViewerInventoryItem* item = NULL;
3491 item_ref_t::iterator it = mComplete.begin();
3492 item_ref_t::iterator end = mComplete.end();
3493 LLUUID pid;
3494 for(; it < end; ++it)
3495 {
3496 item = (LLViewerInventoryItem*)gInventory.getItem(*it);
3497 if(item)
3498 {
3499 if(LLInventoryType::IT_GESTURE == item->getInventoryType())
3500 {
3501 pid = gInventory.findCategoryUUIDForType(LLAssetType::AT_GESTURE);
3502 }
3503 else
3504 {
3505 pid = gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING);
3506 }
3507 break;
3508 }
3509 }
3510 if(pid.isNull())
3511 {
3512 pid = gAgent.getInventoryRootID();
3513 }
3514
3515 LLUUID cat_id = gInventory.createNewCategory(
3516 pid,
3517 LLAssetType::AT_NONE,
3518 name);
3519 mCatID = cat_id;
3520 LLPointer<LLInventoryCallback> cb = new LLWearInventoryCategoryCallback(mCatID, mAppend);
3521 it = mComplete.begin();
3522 for(; it < end; ++it)
3523 {
3524 item = (LLViewerInventoryItem*)gInventory.getItem(*it);
3525 if(item)
3526 {
3527 copy_inventory_item(
3528 gAgent.getID(),
3529 item->getPermissions().getOwner(),
3530 item->getUUID(),
3531 cat_id,
3532 std::string(),
3533 cb);
3534 }
3535 }
3536 }
3537 else
3538 {
3539 // Wear the inventory category.
3540 wear_inventory_category_on_avatar(gInventory.getCategory(mCatID), mAppend);
3541 }
3542}
3543
3544class LLOutfitFetch : public LLInventoryFetchDescendentsObserver
3545{
3546public:
3547 LLOutfitFetch(bool copy_items, bool append) : mCopyItems(copy_items), mAppend(append) {}
3548 ~LLOutfitFetch() {}
3549 virtual void done();
3550protected:
3551 bool mCopyItems;
3552 bool mAppend;
3553};
3554
3555void LLOutfitFetch::done()
3556{
3557 // What we do here is get the complete information on the items in
3558 // the library, and set up an observer that will wait for that to
3559 // happen.
3560 LLInventoryModel::cat_array_t cat_array;
3561 LLInventoryModel::item_array_t item_array;
3562 gInventory.collectDescendents(mCompleteFolders.front(),
3563 cat_array,
3564 item_array,
3565 LLInventoryModel::EXCLUDE_TRASH);
3566 S32 count = item_array.count();
3567 if(!count)
3568 {
3569 llwarns << "Nothing fetched in category " << mCompleteFolders.front()
3570 << llendl;
3571 dec_busy_count();
3572 gInventory.removeObserver(this);
3573 delete this;
3574 return;
3575 }
3576
3577 LLOutfitObserver* outfit;
3578 outfit = new LLOutfitObserver(mCompleteFolders.front(), mCopyItems, mAppend);
3579 LLInventoryFetchObserver::item_ref_t ids;
3580 for(S32 i = 0; i < count; ++i)
3581 {
3582 ids.push_back(item_array.get(i)->getUUID());
3583 }
3584
3585 // clean up, and remove this as an observer since the call to the
3586 // outfit could notify observers and throw us into an infinite
3587 // loop.
3588 dec_busy_count();
3589 gInventory.removeObserver(this);
3590 delete this;
3591
3592 // increment busy count and either tell the inventory to check &
3593 // call done, or add this object to the inventory for observation.
3594 inc_busy_count();
3595
3596 // do the fetch
3597 outfit->fetchItems(ids);
3598 if(outfit->isEverythingComplete())
3599 {
3600 // everything is already here - call done.
3601 outfit->done();
3602 }
3603 else
3604 {
3605 // it's all on it's way - add an observer, and the inventory
3606 // will call done for us when everything is here.
3607 gInventory.addObserver(outfit);
3608 }
3609}
3610
3611void wear_outfit_by_name(const char* name)
3612{
3613 llinfos << "Wearing category " << name << llendl;
3614 inc_busy_count();
3615
3616 LLInventoryModel::cat_array_t cat_array;
3617 LLInventoryModel::item_array_t item_array;
3618 LLNameCategoryCollector has_name(name);
3619 gInventory.collectDescendentsIf(gAgent.getInventoryRootID(),
3620 cat_array,
3621 item_array,
3622 LLInventoryModel::EXCLUDE_TRASH,
3623 has_name);
3624 bool copy_items = false;
3625 LLInventoryCategory* cat = NULL;
3626 if (cat_array.count() > 0)
3627 {
3628 // Just wear the first one that matches
3629 cat = cat_array.get(0);
3630 }
3631 else
3632 {
3633 gInventory.collectDescendentsIf(LLUUID::null,
3634 cat_array,
3635 item_array,
3636 LLInventoryModel::EXCLUDE_TRASH,
3637 has_name);
3638 if(cat_array.count() > 0)
3639 {
3640 cat = cat_array.get(0);
3641 copy_items = true;
3642 }
3643 }
3644
3645 if(cat)
3646 {
3647 wear_inventory_category(cat, copy_items, false);
3648 }
3649 else
3650 {
3651 llwarns << "Couldn't find outfit " <<name<< " in wear_outfit_by_name()"
3652 << llendl;
3653 }
3654
3655 dec_busy_count();
3656}
3657
3658void wear_inventory_category(LLInventoryCategory* category, bool copy, bool append)
3659{
3660 if(!category) return;
3661
3662 lldebugs << "wear_inventory_category( " << category->getName()
3663 << " )" << llendl;
3664 // What we do here is get the complete information on the items in
3665 // the inventory, and set up an observer that will wait for that to
3666 // happen.
3667 LLOutfitFetch* outfit;
3668 outfit = new LLOutfitFetch(copy, append);
3669 LLInventoryFetchDescendentsObserver::folder_ref_t folders;
3670 folders.push_back(category->getUUID());
3671 outfit->fetchDescendents(folders);
3672 inc_busy_count();
3673 if(outfit->isEverythingComplete())
3674 {
3675 // everything is already here - call done.
3676 outfit->done();
3677 }
3678 else
3679 {
3680 // it's all on it's way - add an observer, and the inventory
3681 // will call done for us when everything is here.
3682 gInventory.addObserver(outfit);
3683 }
3684}
3685
3686// *NOTE: hack to get from avatar inventory to avatar
3687void wear_inventory_category_on_avatar( LLInventoryCategory* category, BOOL append )
3688{
3689 // Avoid unintentionally overwriting old wearables. We have to do
3690 // this up front to avoid having to deal with the case of multiple
3691 // wearables being dirty.
3692 if(!category) return;
3693 lldebugs << "wear_inventory_category_on_avatar( " << category->getName()
3694 << " )" << llendl;
3695
3696 LLWearInfo* userdata = new LLWearInfo;
3697 userdata->mAppend = append;
3698 userdata->mCategoryID = category->getUUID();
3699
3700 if( gFloaterCustomize )
3701 {
3702 gFloaterCustomize->askToSaveAllIfDirty(
3703 wear_inventory_category_on_avatar_step2,
3704 userdata);
3705 }
3706 else
3707 {
3708 wear_inventory_category_on_avatar_step2(
3709 TRUE,
3710 userdata );
3711 }
3712}
3713
3714
3715void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata )
3716{
3717 LLWearInfo* wear_info = (LLWearInfo*)userdata;
3718 if (!wear_info) return;
3719
3720 // Find all the wearables that are in the category's subtree.
3721 lldebugs << "wear_inventory_category_on_avatar_step2()" << llendl;
3722 if(proceed)
3723 {
3724 LLInventoryModel::cat_array_t cat_array;
3725 LLInventoryModel::item_array_t item_array;
3726 LLFindWearables is_wearable;
3727 gInventory.collectDescendentsIf(wear_info->mCategoryID,
3728 cat_array,
3729 item_array,
3730 LLInventoryModel::EXCLUDE_TRASH,
3731 is_wearable);
3732 S32 i;
3733 S32 wearable_count = item_array.count();
3734
3735 LLInventoryModel::cat_array_t obj_cat_array;
3736 LLInventoryModel::item_array_t obj_item_array;
3737 LLIsType is_object( LLAssetType::AT_OBJECT );
3738 gInventory.collectDescendentsIf(wear_info->mCategoryID,
3739 obj_cat_array,
3740 obj_item_array,
3741 LLInventoryModel::EXCLUDE_TRASH,
3742 is_object);
3743 S32 obj_count = obj_item_array.count();
3744
3745 // Find all gestures in this folder
3746 LLInventoryModel::cat_array_t gest_cat_array;
3747 LLInventoryModel::item_array_t gest_item_array;
3748 LLIsType is_gesture( LLAssetType::AT_GESTURE );
3749 gInventory.collectDescendentsIf(wear_info->mCategoryID,
3750 gest_cat_array,
3751 gest_item_array,
3752 LLInventoryModel::EXCLUDE_TRASH,
3753 is_gesture);
3754 S32 gest_count = gest_item_array.count();
3755
3756 if( !wearable_count && !obj_count && !gest_count)
3757 {
3758 gViewerWindow->alertXml("CouldNotPutOnOutfit");
3759 delete wear_info;
3760 return;
3761 }
3762
3763 // Processes that take time should show the busy cursor
3764 if (wearable_count > 0 || obj_count > 0)
3765 {
3766 inc_busy_count();
3767 }
3768
3769 // Activate all gestures in this folder
3770 if (gest_count > 0)
3771 {
3772 llinfos << "Activating " << gest_count << " gestures" << llendl;
3773
3774 gGestureManager.activateGestures(gest_item_array);
3775
3776 // Update the inventory item labels to reflect the fact
3777 // they are active.
3778 LLViewerInventoryCategory* catp = gInventory.getCategory(wear_info->mCategoryID);
3779 if (catp)
3780 {
3781 gInventory.updateCategory(catp);
3782 gInventory.notifyObservers();
3783 }
3784 }
3785
3786 if(wearable_count > 0)
3787 {
3788 // Note: can't do normal iteration, because if all the
3789 // wearables can be resolved immediately, then the
3790 // callback will be called (and this object deleted)
3791 // before the final getNextData().
3792 LLWearableHoldingPattern* holder = new LLWearableHoldingPattern;
3793 LLFoundData* found;
3794 LLDynamicArray<LLFoundData*> found_container;
3795 for(i = 0; i < wearable_count; ++i)
3796 {
3797 found = new LLFoundData(item_array.get(i)->getUUID(),
3798 item_array.get(i)->getAssetUUID(),
3799 item_array.get(i)->getName(),
3800 item_array.get(i)->getType());
3801 holder->mFoundList.addData(found);
3802 found_container.put(found);
3803 }
3804 for(i = 0; i < wearable_count; ++i)
3805 {
3806 gAddToOutfit = wear_info->mAppend;
3807
3808 found = found_container.get(i);
3809 gWearableList.getAsset(found->mAssetID,
3810 found->mName,
3811 found->mAssetType,
3812 wear_inventory_category_on_avatar_loop,
3813 (void*)holder);
3814 }
3815 }
3816
3817
3818 //If not appending and the folder doesn't contain only gestures, take off all attachments.
3819 if (!wear_info->mAppend
3820 && !(wearable_count == 0 && obj_count == 0 && gest_count > 0) )
3821 {
3822 LLAgent::userRemoveAllAttachments(NULL);
3823 }
3824
3825 if( obj_count > 0 )
3826 {
3827 // We've found some attachements. Add these.
3828
3829 LLVOAvatar* avatar = gAgent.getAvatarObject();
3830 if( avatar )
3831 {
3832 // Build a compound message to send all the objects that need to be rezzed.
3833
3834 // Limit number of packets to send
3835 const S32 MAX_PACKETS_TO_SEND = 10;
3836 const S32 OBJECTS_PER_PACKET = 4;
3837 const S32 MAX_OBJECTS_TO_SEND = MAX_PACKETS_TO_SEND * OBJECTS_PER_PACKET;
3838 if( obj_count > MAX_OBJECTS_TO_SEND )
3839 {
3840 obj_count = MAX_OBJECTS_TO_SEND;
3841 }
3842
3843 // Create an id to keep the parts of the compound message together
3844 LLUUID compound_msg_id;
3845 compound_msg_id.generate();
3846 LLMessageSystem* msg = gMessageSystem;
3847
3848 for(i = 0; i < obj_count; ++i)
3849 {
3850 if( 0 == (i % OBJECTS_PER_PACKET) )
3851 {
3852 // Start a new message chunk
3853 msg->newMessageFast(_PREHASH_RezMultipleAttachmentsFromInv);
3854 msg->nextBlockFast(_PREHASH_AgentData);
3855 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
3856 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
3857 msg->nextBlockFast(_PREHASH_HeaderData);
3858 msg->addUUIDFast(_PREHASH_CompoundMsgID, compound_msg_id );
3859 msg->addU8Fast(_PREHASH_TotalObjects, obj_count );
3860 msg->addBOOLFast(_PREHASH_FirstDetachAll, !wear_info->mAppend );
3861 }
3862
3863 LLInventoryItem* item = obj_item_array.get(i);
3864 msg->nextBlockFast(_PREHASH_ObjectData );
3865 msg->addUUIDFast(_PREHASH_ItemID, item->getUUID() );
3866 msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner());
3867 msg->addU8Fast(_PREHASH_AttachmentPt, 0 ); // Wear at the previous or default attachment point
3868 pack_permissions_slam(msg, item->getFlags(), item->getPermissions());
3869 msg->addStringFast(_PREHASH_Name, item->getName());
3870 msg->addStringFast(_PREHASH_Description, item->getDescription());
3871
3872 if( (i+1 == obj_count) || ((OBJECTS_PER_PACKET-1) == (i % OBJECTS_PER_PACKET)) )
3873 {
3874 // End of message chunk
3875 msg->sendReliable( gAgent.getRegion()->getHost() );
3876 }
3877 }
3878 }
3879 }
3880 }
3881 delete wear_info;
3882 wear_info = NULL;
3883}
3884
3885void wear_inventory_category_on_avatar_loop(LLWearable* wearable, void* data)
3886{
3887 LLWearableHoldingPattern* holder = (LLWearableHoldingPattern*)data;
3888 BOOL append= gAddToOutfit;
3889
3890 if(wearable)
3891 {
3892 for(LLFoundData* data = holder->mFoundList.getFirstData();
3893 data;
3894 data = holder->mFoundList.getNextData() )
3895 {
3896 if(wearable->getID() == data->mAssetID)
3897 {
3898 data->mWearable = wearable;
3899 break;
3900 }
3901 }
3902 }
3903 holder->mResolved += 1;
3904 if(holder->mResolved >= holder->mFoundList.getLength())
3905 {
3906 wear_inventory_category_on_avatar_step3(holder, append);
3907 }
3908}
3909
3910void wear_inventory_category_on_avatar_step3(LLWearableHoldingPattern* holder, BOOL append)
3911{
3912 lldebugs << "wear_inventory_category_on_avatar_step3()" << llendl;
3913 LLInventoryItem::item_array_t items;
3914 LLDynamicArray< LLWearable* > wearables;
3915
3916 // For each wearable type, find the first instance in the category
3917 // that we recursed through.
3918 for( S32 i = 0; i < WT_COUNT; i++ )
3919 {
3920 for(LLFoundData* data = holder->mFoundList.getFirstData();
3921 data;
3922 data = holder->mFoundList.getNextData())
3923 {
3924 LLWearable* wearable = data->mWearable;
3925 if( wearable && ((S32)wearable->getType() == i) )
3926 {
3927 LLViewerInventoryItem* item;
3928 item = (LLViewerInventoryItem*)gInventory.getItem(data->mItemID);
3929 if( item && (item->getAssetUUID() == wearable->getID()) )
3930 {
3931 //RN: after discussing with Brashears, I disabled this code
3932 //Metadata should reside in the item, not the asset
3933 //And this code does not handle failed asset uploads properly
3934// if(!wearable->isMatchedToInventoryItem(item ))
3935// {
3936// wearable = gWearableList.createWearableMatchedToInventoryItem( wearable, item );
3937// // Now that we have an asset that matches the
3938// // item, update the item to point to the new
3939// // asset.
3940// item->setAssetUUID(wearable->getID());
3941// item->updateAssetOnServer();
3942// }
3943 items.put(item);
3944 wearables.put(wearable);
3945 }
3946 break;
3947 }
3948 }
3949 }
3950
3951 if(wearables.count() > 0)
3952 {
3953 gAgent.setWearableOutfit(items, wearables, !append);
3954 gInventory.notifyObservers();
3955 }
3956
3957 delete holder;
3958
3959 dec_busy_count();
3960}
3961
3962void remove_inventory_category_from_avatar( LLInventoryCategory* category )
3963{
3964 if(!category) return;
3965 lldebugs << "remove_inventory_category_from_avatar( " << category->getName()
3966 << " )" << llendl;
3967
3968
3969 LLUUID* uuid = new LLUUID(category->getUUID());
3970
3971 if( gFloaterCustomize )
3972 {
3973 gFloaterCustomize->askToSaveAllIfDirty(
3974 remove_inventory_category_from_avatar_step2,
3975 uuid);
3976 }
3977 else
3978 {
3979 remove_inventory_category_from_avatar_step2(
3980 TRUE,
3981 uuid );
3982 }
3983}
3984
3985
3986void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata)
3987{
3988
3989 // Find all the wearables that are in the category's subtree.
3990 LLUUID* category_id = (LLUUID *)userdata;
3991
3992 lldebugs << "remove_inventory_category_from_avatar_step2()" << llendl;
3993 if(proceed)
3994 {
3995 LLInventoryModel::cat_array_t cat_array;
3996 LLInventoryModel::item_array_t item_array;
3997 LLFindWearables is_wearable;
3998 gInventory.collectDescendentsIf(*category_id,
3999 cat_array,
4000 item_array,
4001 LLInventoryModel::EXCLUDE_TRASH,
4002 is_wearable);
4003 S32 i;
4004 S32 wearable_count = item_array.count();
4005
4006 LLInventoryModel::cat_array_t obj_cat_array;
4007 LLInventoryModel::item_array_t obj_item_array;
4008 LLIsType is_object( LLAssetType::AT_OBJECT );
4009 gInventory.collectDescendentsIf(*category_id,
4010 obj_cat_array,
4011 obj_item_array,
4012 LLInventoryModel::EXCLUDE_TRASH,
4013 is_object);
4014 S32 obj_count = obj_item_array.count();
4015
4016 // Find all gestures in this folder
4017 LLInventoryModel::cat_array_t gest_cat_array;
4018 LLInventoryModel::item_array_t gest_item_array;
4019 LLIsType is_gesture( LLAssetType::AT_GESTURE );
4020 gInventory.collectDescendentsIf(*category_id,
4021 gest_cat_array,
4022 gest_item_array,
4023 LLInventoryModel::EXCLUDE_TRASH,
4024 is_gesture);
4025 S32 gest_count = gest_item_array.count();
4026
4027 if (wearable_count > 0) //Loop through wearables. If worn, remove.
4028 {
4029 for(i = 0; i < wearable_count; ++i)
4030 {
4031 if( gAgent.isWearingItem (item_array.get(i)->getUUID()) )
4032 {
4033 gWearableList.getAsset(item_array.get(i)->getAssetUUID(),
4034 item_array.get(i)->getName(),
4035 item_array.get(i)->getType(),
4036 LLWearableBridge::onRemoveFromAvatarArrived,
4037 new LLUUID(item_array.get(i)->getUUID()));
4038
4039 }
4040 }
4041 }
4042
4043
4044 if (obj_count > 0)
4045 {
4046 for(i = 0; i < obj_count; ++i)
4047 {
4048 gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv);
4049 gMessageSystem->nextBlockFast(_PREHASH_ObjectData );
4050 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
4051 gMessageSystem->addUUIDFast(_PREHASH_ItemID, obj_item_array.get(i)->getUUID() );
4052
4053 gMessageSystem->sendReliable( gAgent.getRegion()->getHost() );
4054
4055 // this object might have been selected, so let the selection manager know it's gone now
4056 gSelectMgr->remove(gObjectList.findObject( obj_item_array.get(i)->getUUID()) );
4057 }
4058 }
4059
4060 if (gest_count > 0)
4061 {
4062 for(i = 0; i < gest_count; ++i)
4063 {
4064 if ( gGestureManager.isGestureActive( gest_item_array.get(i)->getUUID()) )
4065 {
4066 gGestureManager.deactivateGesture( gest_item_array.get(i)->getUUID() );
4067 gInventory.updateItem( gest_item_array.get(i) );
4068 gInventory.notifyObservers();
4069 }
4070
4071 }
4072 }
4073 }
4074 delete category_id;
4075 category_id = NULL;
4076}
4077
4078BOOL LLWearableBridge::renameItem(const LLString& new_name)
4079{
4080 if( gAgent.isWearingItem( mUUID ) )
4081 {
4082 gAgent.setWearableName( mUUID, new_name );
4083 }
4084 return LLItemBridge::renameItem(new_name);
4085}
4086
4087BOOL LLWearableBridge::isItemRemovable()
4088{
4089 if(gAgent.isWearingItem(mUUID)) return FALSE;
4090 return LLInvFVBridge::isItemRemovable();
4091}
4092
4093LLFontGL::StyleFlags LLWearableBridge::getLabelStyle() const
4094{
4095 if( gAgent.isWearingItem( mUUID ) )
4096 {
4097 // llinfos << "BOLD" << llendl;
4098 return LLFontGL::BOLD;
4099 }
4100 else
4101 {
4102 return LLFontGL::NORMAL;
4103 }
4104}
4105
4106LLString LLWearableBridge::getLabelSuffix() const
4107{
4108 if( gAgent.isWearingItem( mUUID ) )
4109 {
4110 return LLItemBridge::getLabelSuffix() + " (worn)";
4111 }
4112 else
4113 {
4114 return LLItemBridge::getLabelSuffix();
4115 }
4116}
4117
4118LLViewerImage* LLWearableBridge::getIcon() const
4119{
4120 return get_item_icon(mAssetType, mInvType, mWearableType);
4121}
4122
4123// virtual
4124void LLWearableBridge::performAction(LLFolderView* folder, LLInventoryModel* model, LLString action)
4125{
4126 if ("wear" == action)
4127 {
4128 wearOnAvatar();
4129 }
4130 else if ("edit" == action)
4131 {
4132 editOnAvatar();
4133 return;
4134 }
4135 else if ("take_off" == action)
4136 {
4137 if(gAgent.isWearingItem(mUUID))
4138 {
4139 LLViewerInventoryItem* item = getItem();
4140 if (item)
4141 {
4142 gWearableList.getAsset(item->getAssetUUID(),
4143 item->getName(),
4144 item->getType(),
4145 LLWearableBridge::onRemoveFromAvatarArrived,
4146 new LLUUID(mUUID));
4147 }
4148 }
4149 }
4150 else LLItemBridge::performAction(folder, model, action);
4151}
4152
4153void LLWearableBridge::openItem()
4154{
4155 if( isInTrash() )
4156 {
4157 gViewerWindow->alertXml("CannotWearTrash");
4158 }
4159 else if(isAgentInventory())
4160 {
4161 if( !gAgent.isWearingItem( mUUID ) )
4162 {
4163 wearOnAvatar();
4164 }
4165 }
4166 else
4167 {
4168 // must be in the inventory library. copy it to our inventory
4169 // and put it on right away.
4170 LLViewerInventoryItem* item = getItem();
4171 if(item && item->isComplete())
4172 {
4173 LLPointer<LLInventoryCallback> cb = new WearOnAvatarCallback();
4174 copy_inventory_item(
4175 gAgent.getID(),
4176 item->getPermissions().getOwner(),
4177 item->getUUID(),
4178 LLUUID::null,
4179 std::string(),
4180 cb);
4181 }
4182 else if(item)
4183 {
4184 // *TODO: We should fetch the item details, and then do
4185 // the operation above.
4186 gViewerWindow->alertXml("CannotWearInfoNotComplete");
4187 }
4188 }
4189}
4190
4191void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
4192{
4193 lldebugs << "LLWearableBridge::buildContextMenu()" << llendl;
4194 std::vector<LLString> items;
4195 std::vector<LLString> disabled_items;
4196 if(isInTrash())
4197 {
4198 items.push_back("Purge Item");
4199 if (!isItemRemovable())
4200 {
4201 disabled_items.push_back("Purge Item");
4202 }
4203
4204 items.push_back("Restore Item");
4205 }
4206 else
4207 {
4208 BOOL no_open = ((flags & SUPPRESS_OPEN_ITEM) == SUPPRESS_OPEN_ITEM);
4209 if (!no_open)
4210 {
4211 items.push_back("Open");
4212 }
4213
4214 items.push_back("Properties");
4215
4216 getClipboardEntries(true, items, disabled_items, flags);
4217
4218 items.push_back("Wearable Separator");
4219 items.push_back("Wearable Wear");
4220 items.push_back("Wearable Edit");
4221 if ((flags & FIRST_SELECTED_ITEM) == 0)
4222 {
4223 disabled_items.push_back("Wearable Edit");
4224 }
4225 /*menu.appendSeparator();
4226 menu.append(new LLMenuItemCallGL("Wear",
4227 LLWearableBridge::onWearOnAvatar,
4228 LLWearableBridge::canWearOnAvatar,
4229 (void*)this));
4230 menu.append(new LLMenuItemCallGL("Edit",
4231 LLWearableBridge::onEditOnAvatar,
4232 LLWearableBridge::canEditOnAvatar,
4233 (void*)this));*/
4234
4235 LLViewerInventoryItem* item = getItem();
4236 if( item && (item->getType() == LLAssetType::AT_CLOTHING) )
4237 {
4238 items.push_back("Take Off");
4239 /*menu.append(new LLMenuItemCallGL("Take Off",
4240 LLWearableBridge::onRemoveFromAvatar,
4241 LLWearableBridge::canRemoveFromAvatar,
4242 (void*)this));*/
4243 }
4244 }
4245 hideContextEntries(menu, items, disabled_items);
4246}
4247
4248// Called from menus
4249// static
4250BOOL LLWearableBridge::canWearOnAvatar(void* user_data)
4251{
4252 LLWearableBridge* self = (LLWearableBridge*)user_data;
4253 if(!self) return FALSE;
4254 if(!self->isAgentInventory())
4255 {
4256 LLViewerInventoryItem* item = (LLViewerInventoryItem*)self->getItem();
4257 if(!item || !item->isComplete()) return FALSE;
4258 }
4259 return (!gAgent.isWearingItem(self->mUUID));
4260}
4261
4262// Called from menus
4263// static
4264void LLWearableBridge::onWearOnAvatar(void* user_data)
4265{
4266 LLWearableBridge* self = (LLWearableBridge*)user_data;
4267 if(!self) return;
4268 self->wearOnAvatar();
4269}
4270
4271void LLWearableBridge::wearOnAvatar()
4272{
4273 // Don't wear anything until initial wearables are loaded, can
4274 // destroy clothing items.
4275 if (!gAgent.areWearablesLoaded())
4276 {
4277 gViewerWindow->alertXml("CanNotChangeAppearanceUntilLoaded");
4278 return;
4279 }
4280
4281 LLViewerInventoryItem* item = getItem();
4282 if(item)
4283 {
4284 if(!isAgentInventory())
4285 {
4286 LLPointer<LLInventoryCallback> cb = new WearOnAvatarCallback();
4287 copy_inventory_item(
4288 gAgent.getID(),
4289 item->getPermissions().getOwner(),
4290 item->getUUID(),
4291 LLUUID::null,
4292 std::string(),
4293 cb);
4294 }
4295 else
4296 {
4297 wear_inventory_item_on_avatar(item);
4298 }
4299 }
4300}
4301
4302// static
4303void LLWearableBridge::onWearOnAvatarArrived( LLWearable* wearable, void* userdata )
4304{
4305 LLUUID* item_id = (LLUUID*) userdata;
4306 if(wearable)
4307 {
4308 LLViewerInventoryItem* item = NULL;
4309 item = (LLViewerInventoryItem*)gInventory.getItem(*item_id);
4310 if(item)
4311 {
4312 if(item->getAssetUUID() == wearable->getID())
4313 {
4314 //RN: after discussing with Brashears, I disabled this code
4315 //Metadata should reside in the item, not the asset
4316 //And this code does not handle failed asset uploads properly
4317
4318// if(!wearable->isMatchedToInventoryItem(item))
4319// {
4320// LLWearable* new_wearable = gWearableList.createWearableMatchedToInventoryItem( wearable, item );
4321//
4322// // Now that we have an asset that matches the
4323// // item, update the item to point to the new
4324// // asset.
4325// item->setAssetUUID(new_wearable->getID());
4326// item->updateAssetOnServer();
4327// wearable = new_wearable;
4328// }
4329 gAgent.setWearable(item, wearable);
4330 gInventory.notifyObservers();
4331 //self->getFolderItem()->refreshFromRoot();
4332 }
4333 else
4334 {
4335 llinfos << "By the time wearable asset arrived, its inv item already pointed to a different asset." << llendl;
4336 }
4337 }
4338 }
4339 delete item_id;
4340}
4341
4342// static
4343BOOL LLWearableBridge::canEditOnAvatar(void* user_data)
4344{
4345 LLWearableBridge* self = (LLWearableBridge*)user_data;
4346 if(!self) return FALSE;
4347
4348 return (gAgent.isWearingItem(self->mUUID));
4349}
4350
4351// static
4352void LLWearableBridge::onEditOnAvatar(void* user_data)
4353{
4354 LLWearableBridge* self = (LLWearableBridge*)user_data;
4355 if(self)
4356 {
4357 self->editOnAvatar();
4358 }
4359}
4360
4361void LLWearableBridge::editOnAvatar()
4362{
4363 LLWearable* wearable = gAgent.getWearableFromWearableItem(mUUID);
4364 if( wearable )
4365 {
4366 // Set the tab to the right wearable.
4367 LLFloaterCustomize::setCurrentWearableType( wearable->getType() );
4368
4369 if( CAMERA_MODE_CUSTOMIZE_AVATAR != gAgent.getCameraMode() )
4370 {
4371 // Start Avatar Customization
4372 gAgent.changeCameraToCustomizeAvatar();
4373 }
4374 }
4375}
4376
4377// static
4378BOOL LLWearableBridge::canRemoveFromAvatar(void* user_data)
4379{
4380 LLWearableBridge* self = (LLWearableBridge*)user_data;
4381 if( self && (LLAssetType::AT_BODYPART != self->mAssetType) )
4382 {
4383 return gAgent.isWearingItem( self->mUUID );
4384 }
4385 return FALSE;
4386}
4387
4388// static
4389void LLWearableBridge::onRemoveFromAvatar(void* user_data)
4390{
4391 LLWearableBridge* self = (LLWearableBridge*)user_data;
4392 if(!self) return;
4393 if(gAgent.isWearingItem(self->mUUID))
4394 {
4395 LLViewerInventoryItem* item = self->getItem();
4396 if (item)
4397 {
4398 gWearableList.getAsset(item->getAssetUUID(),
4399 item->getName(),
4400 item->getType(),
4401 onRemoveFromAvatarArrived,
4402 new LLUUID(self->mUUID));
4403 }
4404 }
4405}
4406
4407// static
4408void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable,
4409 void* userdata)
4410{
4411 LLUUID* item_id = (LLUUID*) userdata;
4412 if(wearable)
4413 {
4414 if( gAgent.isWearingItem( *item_id ) )
4415 {
4416 EWearableType type = wearable->getType();
4417
4418 if( !(type==WT_SHAPE || type==WT_SKIN || type==WT_HAIR ) ) //&&
4419 //!((gAgent.mAccess >= SIM_ACCESS_MATURE) && ( type==WT_UNDERPANTS || type==WT_UNDERSHIRT )) )
4420 {
4421 gAgent.removeWearable( type );
4422 }
4423 }
4424 }
4425 delete item_id;
4426}