diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llinventorybridge.cpp | |
parent | README.txt (diff) | |
download | meta-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.cpp | 4426 |
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? | ||
87 | void inc_busy_count() | ||
88 | { | ||
89 | // gViewerWindow->getWindow()->incBusyCount(); | ||
90 | } | ||
91 | void dec_busy_count() | ||
92 | { | ||
93 | // gViewerWindow->getWindow()->decBusyCount(); | ||
94 | } | ||
95 | |||
96 | // Function declarations | ||
97 | struct LLWearableHoldingPattern; | ||
98 | void wear_inventory_category_on_avatar(LLInventoryCategory* category, BOOL append); | ||
99 | void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata); | ||
100 | void wear_inventory_category_on_avatar_loop(LLWearable* wearable, void*); | ||
101 | void wear_inventory_category_on_avatar_step3(LLWearableHoldingPattern* holder, BOOL append); | ||
102 | void remove_inventory_category_from_avatar(LLInventoryCategory* category); | ||
103 | void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata); | ||
104 | void move_task_inventory_callback(S32 option, void* user_data); | ||
105 | void confirm_replace_attachment_rez(S32 option, void* user_data); | ||
106 | |||
107 | // TomY XUI: translate | ||
108 | const char* FIND_HINT = "Start typing to select an item by name"; | ||
109 | const char* NAME_SEARCH_DESC = "Find items whose name contains (leave blank for all):"; | ||
110 | const char* NEW_LSL_NAME = "New Script"; | ||
111 | const char* NEW_NOTECARD_NAME = "New Note"; | ||
112 | const char* NEW_GESTURE_NAME = "New Gesture"; | ||
113 | |||
114 | const 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 | |||
147 | struct LLWearInfo | ||
148 | { | ||
149 | LLUUID mCategoryID; | ||
150 | BOOL mAppend; | ||
151 | }; | ||
152 | |||
153 | BOOL gAddToOutfit = FALSE; | ||
154 | |||
155 | // +=================================================+ | ||
156 | // | LLInvFVBridge | | ||
157 | // +=================================================+ | ||
158 | |||
159 | const LLString& LLInvFVBridge::getName() const | ||
160 | { | ||
161 | LLInventoryObject* obj = getInventoryObject(); | ||
162 | if(obj) | ||
163 | { | ||
164 | return obj->getName(); | ||
165 | } | ||
166 | return LLString::null; | ||
167 | } | ||
168 | |||
169 | const LLString& LLInvFVBridge::getDisplayName() const | ||
170 | { | ||
171 | return getName(); | ||
172 | } | ||
173 | |||
174 | // Folders have full perms | ||
175 | PermissionMask LLInvFVBridge::getPermissionMask() const | ||
176 | { | ||
177 | |||
178 | return PERM_ALL; | ||
179 | } | ||
180 | |||
181 | // Folders don't have creation dates. | ||
182 | U32 LLInvFVBridge::getCreationDate() const | ||
183 | { | ||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | // Can be destoryed (or moved to trash) | ||
188 | BOOL 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 | ||
200 | BOOL LLInvFVBridge::isItemMovable() | ||
201 | { | ||
202 | return TRUE; | ||
203 | } | ||
204 | |||
205 | // *TODO: make sure this does the right thing | ||
206 | void LLInvFVBridge::showProperties() | ||
207 | { | ||
208 | LLShowProps::showProperties(mUUID); | ||
209 | } | ||
210 | |||
211 | void LLInvFVBridge::removeBatch(LLDynamicArray<LLFolderViewEventListener*>& batch) | ||
212 | { | ||
213 | removeBatchNoCheck(batch); | ||
214 | } | ||
215 | |||
216 | void 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 | |||
326 | BOOL 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 | |||
339 | void 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 | ||
376 | void 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 | |||
418 | void 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 | ||
443 | BOOL 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 | |||
471 | LLInventoryObject* 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 | |||
482 | BOOL 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 | |||
490 | BOOL 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 | |||
498 | BOOL LLInvFVBridge::isItemPermissive() const | ||
499 | { | ||
500 | return FALSE; | ||
501 | } | ||
502 | |||
503 | // static | ||
504 | void 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 | ||
527 | void 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 | |||
550 | const 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 | |||
561 | LLInvFVBridge* 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 | |||
678 | void 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 | |||
737 | void LLItemBridge::selectItem() | ||
738 | { | ||
739 | LLViewerInventoryItem* item = (LLViewerInventoryItem*)getItem(); | ||
740 | if(item && !item->isComplete()) | ||
741 | { | ||
742 | item->fetchFromServer(); | ||
743 | } | ||
744 | } | ||
745 | |||
746 | void 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 | |||
758 | LLViewerImage* 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 | |||
764 | PermissionMask 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 | |||
783 | const LLString& LLItemBridge::getDisplayName() const | ||
784 | { | ||
785 | if(mDisplayName.empty()) | ||
786 | { | ||
787 | buildDisplayName(getItem(), mDisplayName); | ||
788 | } | ||
789 | return mDisplayName; | ||
790 | } | ||
791 | |||
792 | void 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 | |||
804 | LLString 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 | |||
845 | U32 LLItemBridge::getCreationDate() const | ||
846 | { | ||
847 | LLViewerInventoryItem* item = getItem(); | ||
848 | if (item) | ||
849 | { | ||
850 | return item->getCreationDate(); | ||
851 | } | ||
852 | return 0; | ||
853 | } | ||
854 | |||
855 | |||
856 | BOOL 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 | |||
866 | BOOL 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 | |||
888 | BOOL 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 | |||
912 | BOOL LLItemBridge::isItemCopyable() const | ||
913 | { | ||
914 | LLViewerInventoryItem* item = getItem(); | ||
915 | if (item) | ||
916 | { | ||
917 | return (item->getPermissions().allowCopyBy(gAgent.getID())); | ||
918 | } | ||
919 | return FALSE; | ||
920 | } | ||
921 | BOOL LLItemBridge::copyToClipboard() const | ||
922 | { | ||
923 | if(isItemCopyable()) | ||
924 | { | ||
925 | LLInventoryClipboard::instance().add(mUUID); | ||
926 | return TRUE; | ||
927 | } | ||
928 | return FALSE; | ||
929 | } | ||
930 | |||
931 | LLViewerInventoryItem* 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 | |||
942 | BOOL 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 | |||
960 | LLFolderBridge* LLFolderBridge::sSelf=NULL; | ||
961 | |||
962 | // Can be moved to another folder | ||
963 | BOOL 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 | |||
973 | void LLFolderBridge::selectItem() | ||
974 | { | ||
975 | } | ||
976 | |||
977 | |||
978 | // Can be destroyed (or moved to trash) | ||
979 | BOOL 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 | |||
1047 | BOOL 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 | |||
1060 | BOOL 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 | |||
1183 | void 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. | ||
1199 | BOOL 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 | |||
1289 | class LLFindWearables : public LLInventoryCollectFunctor | ||
1290 | { | ||
1291 | public: | ||
1292 | LLFindWearables() {} | ||
1293 | virtual ~LLFindWearables() {} | ||
1294 | virtual bool operator()(LLInventoryCategory* cat, | ||
1295 | LLInventoryItem* item); | ||
1296 | }; | ||
1297 | |||
1298 | bool 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. | ||
1313 | class LLRightClickInventoryFetchObserver : public LLInventoryFetchObserver | ||
1314 | { | ||
1315 | public: | ||
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 | |||
1331 | protected: | ||
1332 | LLUUID mCatID; | ||
1333 | bool mCopyItems; | ||
1334 | |||
1335 | }; | ||
1336 | |||
1337 | //Used by LLFolderBridge as callback for directory recursion. | ||
1338 | class LLRightClickInventoryFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver | ||
1339 | { | ||
1340 | public: | ||
1341 | LLRightClickInventoryFetchDescendentsObserver(bool copy_items) : mCopyItems(copy_items) {} | ||
1342 | ~LLRightClickInventoryFetchDescendentsObserver() {} | ||
1343 | virtual void done(); | ||
1344 | protected: | ||
1345 | bool mCopyItems; | ||
1346 | }; | ||
1347 | |||
1348 | void 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 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
1416 | class LLInventoryCopyAndWearObserver : public LLInventoryObserver | ||
1417 | { | ||
1418 | public: | ||
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 | |||
1423 | protected: | ||
1424 | LLUUID mCatID; | ||
1425 | int mContentsCount; | ||
1426 | BOOL mFolderAdded; | ||
1427 | }; | ||
1428 | |||
1429 | |||
1430 | |||
1431 | void 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 | |||
1468 | void 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 | |||
1520 | void LLFolderBridge::openItem() | ||
1521 | { | ||
1522 | lldebugs << "LLFolderBridge::openItem()" << llendl; | ||
1523 | LLInventoryModel* model = mInventoryPanel->getModel(); | ||
1524 | if(!model) return; | ||
1525 | model->fetchDescendentsOf(mUUID); | ||
1526 | } | ||
1527 | |||
1528 | BOOL 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 | |||
1539 | void 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 | ||
1553 | LLViewerImage* 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 | |||
1618 | BOOL 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 | |||
1637 | BOOL 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 | |||
1682 | BOOL LLFolderBridge::isClipboardPasteable() const | ||
1683 | { | ||
1684 | if(LLInventoryClipboard::instance().hasContents() && isAgentInventory()) | ||
1685 | { | ||
1686 | return TRUE; | ||
1687 | } | ||
1688 | return FALSE; | ||
1689 | } | ||
1690 | |||
1691 | void 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 | |||
1718 | void LLFolderBridge::staticFolderOptionsMenu() | ||
1719 | { | ||
1720 | if (!sSelf) return; | ||
1721 | sSelf->folderOptionsMenu(); | ||
1722 | } | ||
1723 | |||
1724 | void 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 | |||
1760 | BOOL 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 | ||
1773 | void 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 | |||
1882 | BOOL 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 | |||
1891 | BOOL 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 | |||
1923 | LLViewerInventoryCategory* 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 | ||
1936 | void LLFolderBridge::pasteClipboard(void* user_data) | ||
1937 | { | ||
1938 | LLFolderBridge* self = (LLFolderBridge*)user_data; | ||
1939 | if(self) self->pasteFromClipboard(); | ||
1940 | } | ||
1941 | |||
1942 | void 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 | |||
1960 | void LLFolderBridge::createNewShirt(void* user_data) | ||
1961 | { | ||
1962 | LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SHIRT); | ||
1963 | } | ||
1964 | |||
1965 | void LLFolderBridge::createNewPants(void* user_data) | ||
1966 | { | ||
1967 | LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_PANTS); | ||
1968 | } | ||
1969 | |||
1970 | void LLFolderBridge::createNewShoes(void* user_data) | ||
1971 | { | ||
1972 | LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SHOES); | ||
1973 | } | ||
1974 | |||
1975 | void LLFolderBridge::createNewSocks(void* user_data) | ||
1976 | { | ||
1977 | LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SOCKS); | ||
1978 | } | ||
1979 | |||
1980 | void LLFolderBridge::createNewJacket(void* user_data) | ||
1981 | { | ||
1982 | LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_JACKET); | ||
1983 | } | ||
1984 | |||
1985 | void LLFolderBridge::createNewSkirt(void* user_data) | ||
1986 | { | ||
1987 | LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SKIRT); | ||
1988 | } | ||
1989 | |||
1990 | void LLFolderBridge::createNewGloves(void* user_data) | ||
1991 | { | ||
1992 | LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_GLOVES); | ||
1993 | } | ||
1994 | |||
1995 | void LLFolderBridge::createNewUndershirt(void* user_data) | ||
1996 | { | ||
1997 | LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_UNDERSHIRT); | ||
1998 | } | ||
1999 | |||
2000 | void LLFolderBridge::createNewUnderpants(void* user_data) | ||
2001 | { | ||
2002 | LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_UNDERPANTS); | ||
2003 | } | ||
2004 | |||
2005 | void LLFolderBridge::createNewShape(void* user_data) | ||
2006 | { | ||
2007 | LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SHAPE); | ||
2008 | } | ||
2009 | |||
2010 | void LLFolderBridge::createNewSkin(void* user_data) | ||
2011 | { | ||
2012 | LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SKIN); | ||
2013 | } | ||
2014 | |||
2015 | void LLFolderBridge::createNewHair(void* user_data) | ||
2016 | { | ||
2017 | LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_HAIR); | ||
2018 | } | ||
2019 | |||
2020 | void LLFolderBridge::createNewEyes(void* user_data) | ||
2021 | { | ||
2022 | LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_EYES); | ||
2023 | } | ||
2024 | |||
2025 | // static | ||
2026 | void 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 | ||
2036 | void 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 | |||
2048 | void 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 | |||
2100 | void 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 | ||
2111 | void 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 | |||
2149 | BOOL 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 | |||
2313 | LLViewerImage* LLScriptBridge::getIcon() const | ||
2314 | { | ||
2315 | return get_item_icon(LLAssetType::AT_SCRIPT, LLInventoryType::IT_LSL, 0); | ||
2316 | } | ||
2317 | |||
2318 | // +=================================================+ | ||
2319 | // | LLTextureBridge | | ||
2320 | // +=================================================+ | ||
2321 | |||
2322 | LLString LLTextureBridge::sPrefix("Texture: "); | ||
2323 | |||
2324 | |||
2325 | LLViewerImage* LLTextureBridge::getIcon() const | ||
2326 | { | ||
2327 | return get_item_icon(LLAssetType::AT_TEXTURE, mInvType, 0); | ||
2328 | } | ||
2329 | |||
2330 | void 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 | |||
2359 | void 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 | |||
2372 | LLString LLSoundBridge::sPrefix("Sound: "); | ||
2373 | |||
2374 | |||
2375 | LLViewerImage* LLSoundBridge::getIcon() const | ||
2376 | { | ||
2377 | return get_item_icon(LLAssetType::AT_SOUND, LLInventoryType::IT_SOUND, 0); | ||
2378 | } | ||
2379 | |||
2380 | void 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 | |||
2406 | void LLSoundBridge::previewItem() | ||
2407 | { | ||
2408 | LLViewerInventoryItem* item = getItem(); | ||
2409 | if(item) | ||
2410 | { | ||
2411 | send_sound_trigger(item->getAssetUUID(), 1.0); | ||
2412 | } | ||
2413 | } | ||
2414 | |||
2415 | void 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 | |||
2434 | void 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 | |||
2468 | LLString LLLandmarkBridge::sPrefix("Landmark: "); | ||
2469 | |||
2470 | LLViewerImage* LLLandmarkBridge::getIcon() const | ||
2471 | { | ||
2472 | return get_item_icon(LLAssetType::AT_LANDMARK, LLInventoryType::IT_LANDMARK, mVisited); | ||
2473 | } | ||
2474 | |||
2475 | void 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 | ||
2507 | void 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 | |||
2527 | void 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 | |||
2554 | void 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 | // +=================================================+ | ||
2567 | void LLCallingCardObserver::changed(U32 mask) | ||
2568 | { | ||
2569 | mBridgep->refreshFolderViewItem(); | ||
2570 | } | ||
2571 | |||
2572 | // +=================================================+ | ||
2573 | // | LLCallingCardBridge | | ||
2574 | // +=================================================+ | ||
2575 | |||
2576 | LLString LLCallingCardBridge::sPrefix("Calling Card: "); | ||
2577 | |||
2578 | LLCallingCardBridge::LLCallingCardBridge( LLInventoryPanel* inventory, const LLUUID& uuid ) : | ||
2579 | LLItemBridge(inventory, uuid) | ||
2580 | { | ||
2581 | mObserver = new LLCallingCardObserver(this); | ||
2582 | LLAvatarTracker::instance().addObserver(mObserver); | ||
2583 | } | ||
2584 | |||
2585 | LLCallingCardBridge::~LLCallingCardBridge() | ||
2586 | { | ||
2587 | LLAvatarTracker::instance().removeObserver(mObserver); | ||
2588 | delete mObserver; | ||
2589 | } | ||
2590 | |||
2591 | void LLCallingCardBridge::refreshFolderViewItem() | ||
2592 | { | ||
2593 | LLFolderViewItem* itemp = mInventoryPanel->getRootFolder()->getItemByID(mUUID); | ||
2594 | if (itemp) | ||
2595 | { | ||
2596 | itemp->refresh(); | ||
2597 | } | ||
2598 | } | ||
2599 | |||
2600 | // virtual | ||
2601 | void 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 | |||
2625 | LLViewerImage* 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 | |||
2636 | LLString 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 | |||
2649 | void 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 | |||
2660 | void 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 | |||
2700 | BOOL 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 | |||
2774 | LLString LLNotecardBridge::sPrefix("Note: "); | ||
2775 | |||
2776 | |||
2777 | LLViewerImage* LLNotecardBridge::getIcon() const | ||
2778 | { | ||
2779 | return get_item_icon(LLAssetType::AT_NOTECARD, LLInventoryType::IT_NOTECARD, 0); | ||
2780 | } | ||
2781 | |||
2782 | void 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 | |||
2833 | void 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 | |||
2847 | LLString LLGestureBridge::sPrefix("Gesture: "); | ||
2848 | |||
2849 | LLViewerImage* LLGestureBridge::getIcon() const | ||
2850 | { | ||
2851 | return get_item_icon(LLAssetType::AT_GESTURE, LLInventoryType::IT_GESTURE, 0); | ||
2852 | } | ||
2853 | |||
2854 | LLFontGL::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 | |||
2866 | LLString 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 | ||
2879 | void 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 | |||
2908 | void 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 | |||
2929 | BOOL 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 | |||
2937 | void 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 | |||
2979 | LLString LLAnimationBridge::sPrefix("Animation: "); | ||
2980 | |||
2981 | |||
2982 | LLViewerImage* LLAnimationBridge::getIcon() const | ||
2983 | { | ||
2984 | return get_item_icon(LLAssetType::AT_ANIMATION, LLInventoryType::IT_ANIMATION, 0); | ||
2985 | } | ||
2986 | |||
2987 | void 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 | ||
3020 | void 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 | |||
3057 | void 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 | ||
3087 | LLString LLObjectBridge::sPrefix("Object: "); | ||
3088 | |||
3089 | // static | ||
3090 | LLUUID LLObjectBridge::sContextMenuItemID; | ||
3091 | |||
3092 | BOOL 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 | |||
3100 | LLViewerImage* LLObjectBridge::getIcon() const | ||
3101 | { | ||
3102 | return get_item_icon(LLAssetType::AT_OBJECT, mInvType, mAttachPt); | ||
3103 | } | ||
3104 | |||
3105 | void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment); | ||
3106 | |||
3107 | // virtual | ||
3108 | void 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 | |||
3151 | void 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 | |||
3159 | LLFontGL::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 | |||
3172 | LLString 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 | |||
3187 | void 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 | |||
3203 | void 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 | |||
3233 | void 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 | |||
3315 | BOOL 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 | |||
3353 | LLString LLLSLTextBridge::sPrefix("Script: "); | ||
3354 | |||
3355 | LLViewerImage* LLLSLTextBridge::getIcon() const | ||
3356 | { | ||
3357 | return get_item_icon(LLAssetType::AT_SCRIPT, LLInventoryType::IT_LSL, 0); | ||
3358 | } | ||
3359 | |||
3360 | void 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 | ||
3390 | void 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 | |||
3405 | struct 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 | |||
3424 | struct LLWearableHoldingPattern | ||
3425 | { | ||
3426 | LLWearableHoldingPattern() : mResolved(0) {} | ||
3427 | ~LLWearableHoldingPattern() { mFoundList.deleteAllData(); } | ||
3428 | LLDoubleLinkedList<LLFoundData> mFoundList; | ||
3429 | S32 mResolved; | ||
3430 | }; | ||
3431 | |||
3432 | |||
3433 | class LLOutfitObserver : public LLInventoryFetchObserver | ||
3434 | { | ||
3435 | public: | ||
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 | |||
3444 | protected: | ||
3445 | LLUUID mCatID; | ||
3446 | bool mCopyItems; | ||
3447 | bool mAppend; | ||
3448 | }; | ||
3449 | |||
3450 | class LLWearInventoryCategoryCallback : public LLInventoryCallback | ||
3451 | { | ||
3452 | public: | ||
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 | } | ||
3468 | private: | ||
3469 | LLUUID mCatID; | ||
3470 | bool mAppend; | ||
3471 | }; | ||
3472 | |||
3473 | void 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 | |||
3544 | class LLOutfitFetch : public LLInventoryFetchDescendentsObserver | ||
3545 | { | ||
3546 | public: | ||
3547 | LLOutfitFetch(bool copy_items, bool append) : mCopyItems(copy_items), mAppend(append) {} | ||
3548 | ~LLOutfitFetch() {} | ||
3549 | virtual void done(); | ||
3550 | protected: | ||
3551 | bool mCopyItems; | ||
3552 | bool mAppend; | ||
3553 | }; | ||
3554 | |||
3555 | void 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 | |||
3611 | void 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 | |||
3658 | void 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 | ||
3687 | void 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 | |||
3715 | void 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 | |||
3885 | void 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 | |||
3910 | void 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 | |||
3962 | void 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 | |||
3986 | void 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 | |||
4078 | BOOL 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 | |||
4087 | BOOL LLWearableBridge::isItemRemovable() | ||
4088 | { | ||
4089 | if(gAgent.isWearingItem(mUUID)) return FALSE; | ||
4090 | return LLInvFVBridge::isItemRemovable(); | ||
4091 | } | ||
4092 | |||
4093 | LLFontGL::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 | |||
4106 | LLString 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 | |||
4118 | LLViewerImage* LLWearableBridge::getIcon() const | ||
4119 | { | ||
4120 | return get_item_icon(mAssetType, mInvType, mWearableType); | ||
4121 | } | ||
4122 | |||
4123 | // virtual | ||
4124 | void 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 | |||
4153 | void 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 | |||
4191 | void 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 | ||
4250 | BOOL 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 | ||
4264 | void LLWearableBridge::onWearOnAvatar(void* user_data) | ||
4265 | { | ||
4266 | LLWearableBridge* self = (LLWearableBridge*)user_data; | ||
4267 | if(!self) return; | ||
4268 | self->wearOnAvatar(); | ||
4269 | } | ||
4270 | |||
4271 | void 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 | ||
4303 | void 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 | ||
4343 | BOOL 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 | ||
4352 | void LLWearableBridge::onEditOnAvatar(void* user_data) | ||
4353 | { | ||
4354 | LLWearableBridge* self = (LLWearableBridge*)user_data; | ||
4355 | if(self) | ||
4356 | { | ||
4357 | self->editOnAvatar(); | ||
4358 | } | ||
4359 | } | ||
4360 | |||
4361 | void 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 | ||
4378 | BOOL 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 | ||
4389 | void 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 | ||
4408 | void 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 | } | ||