2 // Radegast Metaverse Client
3 // Copyright (c) 2009-2014, Radegast Development Team
4 // All rights reserved.
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
9 // * Redistributions of source code must retain the above copyright notice,
10 // this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 // * Neither the name of the application "Radegast", nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 using System.Collections;
33 using System.Collections.Generic;
34 using System.ComponentModel;
37 using System.Windows.Forms;
38 #if (COGBOT_LIBOMV || USE_STHREADS)
40 using Thread = ThreadPoolUtil.Thread;
41 using ThreadPool = ThreadPoolUtil.ThreadPool;
42 using Monitor = ThreadPoolUtil.Monitor;
44 using System.Threading;
47 using OpenMetaverse.StructuredData;
52 public partial class InventoryConsole : UserControl
54 RadegastInstance instance;
55 GridClient client { get { return instance.Client; } }
56 Dictionary<UUID, TreeNode> FolderNodes = new Dictionary<UUID, TreeNode>();
58 private InventoryManager Manager;
59 private OpenMetaverse.Inventory Inventory;
60 private TreeNode invRootNode;
61 private string newItemName = string.Empty;
62 private List<UUID> fetchedFolders = new List<UUID>();
63 private System.Threading.Timer _EditTimer;
64 private TreeNode _EditNode;
65 private Dictionary<UUID, AttachmentInfo> attachments = new Dictionary<UUID, AttachmentInfo>();
66 private System.Timers.Timer TreeUpdateTimer;
67 private Queue<InventoryBase> ItemsToAdd = new Queue<InventoryBase>();
68 private Queue<InventoryBase> ItemsToUpdate = new Queue<InventoryBase>();
69 private bool TreeUpdateInProgress = false;
70 private Dictionary<UUID, TreeNode> UUID2NodeCache = new Dictionary<UUID, TreeNode>();
71 private int updateInterval = 1000;
72 private Thread InventoryUpdate;
73 private List<UUID> WornItems = new List<UUID>();
74 private bool appearnceWasBusy;
75 private InvNodeSorter sorter;
76 private List<UUID> QueuedFolders = new List<UUID>();
77 private Dictionary<UUID, int> FolderFetchRetries = new Dictionary<UUID, int>();
78 AutoResetEvent trashCreated = new AutoResetEvent(false);
80 #region Construction and disposal
81 public InventoryConsole(RadegastInstance instance)
83 InitializeComponent();
84 Disposed += new EventHandler(InventoryConsole_Disposed);
86 TreeUpdateTimer = new System.Timers.Timer()
88 Interval = updateInterval,
90 SynchronizingObject = invTree
92 TreeUpdateTimer.Elapsed += TreeUpdateTimerTick;
94 this.instance = instance;
95 Manager = client.Inventory;
96 Inventory = Manager.Store;
97 Inventory.RootFolder.OwnerID = client.Self.AgentID;
98 invTree.ImageList = frmMain.ResourceImages;
99 invRootNode = AddDir(null, Inventory.RootFolder);
100 UpdateStatus("Reading cache");
106 WorkPool.QueueUserWorkItem(sync =>
108 Logger.Log("Reading inventory cache from " + instance.InventoryCacheFileName, Helpers.LogLevel.Debug, client);
109 Inventory.RestoreFromDisk(instance.InventoryCacheFileName);
116 if (instance.MainForm.InvokeRequired)
118 instance.MainForm.BeginInvoke(new MethodInvoker(() => Init2()));
122 AddFolderFromStore(invRootNode, Inventory.RootFolder);
124 sorter = new InvNodeSorter();
126 if (!instance.GlobalSettings.ContainsKey("inv_sort_bydate"))
127 instance.GlobalSettings["inv_sort_bydate"] = OSD.FromBoolean(true);
128 if (!instance.GlobalSettings.ContainsKey("inv_sort_sysfirst"))
129 instance.GlobalSettings["inv_sort_sysfirst"] = OSD.FromBoolean(true);
131 sorter.ByDate = instance.GlobalSettings["inv_sort_bydate"].AsBoolean();
132 sorter.SystemFoldersFirst = instance.GlobalSettings["inv_sort_sysfirst"].AsBoolean();
134 tbtnSortByDate.Checked = sorter.ByDate;
135 tbtbSortByName.Checked = !sorter.ByDate;
136 tbtnSystemFoldersFirst.Checked = sorter.SystemFoldersFirst;
138 invTree.TreeViewNodeSorter = sorter;
140 if (instance.MonoRuntime)
142 invTree.BackColor = Color.FromKnownColor(KnownColor.Window);
143 invTree.ForeColor = invTree.LineColor = Color.FromKnownColor(KnownColor.WindowText);
144 InventoryFolder f = new InventoryFolder(UUID.Random());
146 f.ParentUUID = UUID.Zero;
147 f.PreferredType = AssetType.Unknown;
148 TreeNode dirNode = new TreeNode();
149 dirNode.Name = f.UUID.ToString();
150 dirNode.Text = f.Name;
152 dirNode.ImageIndex = GetDirImageIndex(f.PreferredType.ToString().ToLower());
153 dirNode.SelectedImageIndex = dirNode.ImageIndex;
154 invTree.Nodes.Add(dirNode);
158 saveAllTToolStripMenuItem.Enabled = false;
159 InventoryUpdate = new Thread(new ThreadStart(StartTraverseNodes));
160 InventoryUpdate.Name = "InventoryUpdate";
161 InventoryUpdate.IsBackground = true;
162 InventoryUpdate.Start();
164 invRootNode.Expand();
166 invTree.AfterExpand += new TreeViewEventHandler(TreeView_AfterExpand);
167 invTree.NodeMouseClick += new TreeNodeMouseClickEventHandler(invTree_MouseClick);
168 invTree.NodeMouseDoubleClick += new TreeNodeMouseClickEventHandler(invTree_NodeMouseDoubleClick);
170 _EditTimer = new System.Threading.Timer(OnLabelEditTimer, null, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
173 Inventory.InventoryObjectAdded += new EventHandler<InventoryObjectAddedEventArgs>(Inventory_InventoryObjectAdded);
174 Inventory.InventoryObjectUpdated += new EventHandler<InventoryObjectUpdatedEventArgs>(Inventory_InventoryObjectUpdated);
175 Inventory.InventoryObjectRemoved += new EventHandler<InventoryObjectRemovedEventArgs>(Inventory_InventoryObjectRemoved);
177 client.Objects.ObjectUpdate += new EventHandler<PrimEventArgs>(Objects_AttachmentUpdate);
178 client.Objects.KillObject += new EventHandler<KillObjectEventArgs>(Objects_KillObject);
179 client.Appearance.AppearanceSet += new EventHandler<AppearanceSetEventArgs>(Appearance_AppearanceSet);
182 void InventoryConsole_Disposed(object sender, EventArgs e)
184 if (TreeUpdateTimer != null)
186 TreeUpdateTimer.Stop();
187 TreeUpdateTimer.Dispose();
188 TreeUpdateTimer = null;
190 if (InventoryUpdate != null)
192 if (InventoryUpdate.IsAlive)
193 InventoryUpdate.Abort();
194 InventoryUpdate = null;
197 Inventory.InventoryObjectAdded -= new EventHandler<InventoryObjectAddedEventArgs>(Inventory_InventoryObjectAdded);
198 Inventory.InventoryObjectUpdated -= new EventHandler<InventoryObjectUpdatedEventArgs>(Inventory_InventoryObjectUpdated);
199 Inventory.InventoryObjectRemoved -= new EventHandler<InventoryObjectRemovedEventArgs>(Inventory_InventoryObjectRemoved);
201 client.Objects.ObjectUpdate -= new EventHandler<PrimEventArgs>(Objects_AttachmentUpdate);
202 client.Objects.KillObject -= new EventHandler<KillObjectEventArgs>(Objects_KillObject);
203 client.Appearance.AppearanceSet -= new EventHandler<AppearanceSetEventArgs>(Appearance_AppearanceSet);
207 #region Network callbacks
208 void Appearance_AppearanceSet(object sender, AppearanceSetEventArgs e)
211 if (appearnceWasBusy)
213 appearnceWasBusy = false;
214 client.Appearance.RequestSetAppearance(true);
218 void Objects_KillObject(object sender, KillObjectEventArgs e)
220 AttachmentInfo attachment = null;
223 foreach (AttachmentInfo att in attachments.Values)
225 if (att.Prim != null && att.Prim.LocalID == e.ObjectLocalID)
232 if (attachment != null)
234 attachments.Remove(attachment.InventoryID);
235 UpdateNodeLabel(attachment.InventoryID);
240 void Objects_AttachmentUpdate(object sender, PrimEventArgs e)
242 Primitive prim = e.Prim;
244 if (client.Self.LocalID == 0 ||
245 prim.ParentID != client.Self.LocalID ||
246 prim.NameValues == null) return;
248 for (int i = 0; i < prim.NameValues.Length; i++)
250 if (prim.NameValues[i].Name == "AttachItemID")
252 AttachmentInfo attachment = new AttachmentInfo();
253 attachment.Prim = prim;
254 attachment.InventoryID = new UUID(prim.NameValues[i].Value.ToString());
255 attachment.PrimID = prim.ID;
259 // Add new attachment info
260 if (!attachments.ContainsKey(attachment.InventoryID))
262 attachments.Add(attachment.InventoryID, attachment);
267 attachment = attachments[attachment.InventoryID];
268 if (attachment.Prim == null)
270 attachment.Prim = prim;
274 // Don't update the tree yet if we're still updating invetory tree from server
275 if (!TreeUpdateInProgress)
277 if (Inventory.Contains(attachment.InventoryID))
279 if (attachment.Item == null)
281 InventoryItem item = (InventoryItem)Inventory[attachment.InventoryID];
282 attachment.Item = item;
284 if (!attachment.MarkedAttached)
286 attachment.MarkedAttached = true;
287 UpdateNodeLabel(attachment.InventoryID);
292 client.Inventory.RequestFetchInventory(attachment.InventoryID, client.Self.AgentID);
301 void Inventory_InventoryObjectAdded(object sender, InventoryObjectAddedEventArgs e)
303 if (e.Obj is InventoryFolder && ((InventoryFolder)e.Obj).PreferredType == AssetType.TrashFolder)
308 if (TreeUpdateInProgress)
312 ItemsToAdd.Enqueue(e.Obj);
317 Exec_OnInventoryObjectAdded(e.Obj);
321 void Exec_OnInventoryObjectAdded(InventoryBase obj)
325 Invoke(new MethodInvoker(delegate()
327 Exec_OnInventoryObjectAdded(obj);
335 if (attachments.ContainsKey(obj.UUID))
337 attachments[obj.UUID].Item = (InventoryItem)obj;
341 TreeNode parent = findNodeForItem(obj.ParentUUID);
345 TreeNode newNode = AddBase(parent, obj);
346 if (obj.Name == newItemName)
348 if (newNode.Parent.IsExpanded)
354 newNode.Parent.Expand();
358 newItemName = string.Empty;
361 void Inventory_InventoryObjectRemoved(object sender, InventoryObjectRemovedEventArgs e)
365 BeginInvoke(new MethodInvoker(() => Inventory_InventoryObjectRemoved(sender, e)));
371 if (attachments.ContainsKey(e.Obj.UUID))
373 attachments.Remove(e.Obj.UUID);
377 TreeNode currentNode = findNodeForItem(e.Obj.UUID);
378 if (currentNode != null)
380 removeNode(currentNode);
384 void Inventory_InventoryObjectUpdated(object sender, InventoryObjectUpdatedEventArgs e)
386 if (TreeUpdateInProgress)
390 if (e.NewObject is InventoryFolder)
392 TreeNode currentNode = findNodeForItem(e.NewObject.UUID);
393 if (currentNode != null && currentNode.Text == e.NewObject.Name) return;
396 if (!ItemsToUpdate.Contains(e.NewObject))
398 ItemsToUpdate.Enqueue(e.NewObject);
404 Exec_OnInventoryObjectUpdated(e.OldObject, e.NewObject);
408 void Exec_OnInventoryObjectUpdated(InventoryBase oldObject, InventoryBase newObject)
410 if (newObject == null) return;
414 BeginInvoke(new MethodInvoker(() => Exec_OnInventoryObjectUpdated(oldObject, newObject)));
420 if (attachments.ContainsKey(newObject.UUID))
422 attachments[newObject.UUID].Item = (InventoryItem)newObject;
426 // Find our current node in the tree
427 TreeNode currentNode = findNodeForItem(newObject.UUID);
429 // Find which node should be our parrent
430 TreeNode parent = findNodeForItem(newObject.ParentUUID);
432 if (parent == null) return;
434 if (currentNode != null)
436 // Did we move to a different folder
437 if (currentNode.Parent != parent)
439 TreeNode movedNode = (TreeNode)currentNode.Clone();
440 movedNode.Tag = newObject;
441 parent.Nodes.Add(movedNode);
442 removeNode(currentNode);
443 cacheNode(movedNode);
447 currentNode.Tag = newObject;
448 currentNode.Text = ItemLabel(newObject, false);
449 currentNode.Name = newObject.Name;
452 else // We are not in the tree already, add
454 AddBase(parent, newObject);
459 #region Node manipulation
460 public static int GetDirImageIndex(string t)
462 t = System.Text.RegularExpressions.Regex.Replace(t, @"folder$", "");
463 int res = frmMain.ImageNames.IndexOf("inv_folder_" + t);
468 case "currentoutfit":
470 return frmMain.ImageNames.IndexOf("inv_folder_outfit");
472 return frmMain.ImageNames.IndexOf("inv_folder_script");
474 return frmMain.ImageNames.IndexOf("inv_folder_plain_closed");
479 public static int GetItemImageIndex(string t)
481 int res = frmMain.ImageNames.IndexOf("inv_item_" + t);
486 return frmMain.ImageNames.IndexOf("inv_item_script");
488 else if (t == "callingcard")
490 return frmMain.ImageNames.IndexOf("inv_item_callingcard_offline");
496 TreeNode AddBase(TreeNode parent, InventoryBase obj)
498 if (obj is InventoryItem)
500 return AddItem(parent, (InventoryItem)obj);
504 return AddDir(parent, (InventoryFolder)obj);
508 TreeNode AddDir(TreeNode parentNode, InventoryFolder f)
510 TreeNode dirNode = new TreeNode();
511 dirNode.Name = f.UUID.ToString();
512 dirNode.Text = f.Name;
514 dirNode.ImageIndex = GetDirImageIndex(f.PreferredType.ToString().ToLower());
515 dirNode.SelectedImageIndex = dirNode.ImageIndex;
516 if (parentNode == null)
518 invTree.Nodes.Add(dirNode);
522 parentNode.Nodes.Add(dirNode);
524 lock (UUID2NodeCache)
526 UUID2NodeCache[f.UUID] = dirNode;
532 TreeNode AddItem(TreeNode parent, InventoryItem item)
534 TreeNode itemNode = new TreeNode();
535 itemNode.Name = item.UUID.ToString();
536 itemNode.Text = ItemLabel(item, false);
539 InventoryItem linkedItem = null;
541 if (item.IsLink() && Inventory.Contains(item.AssetUUID) && Inventory[item.AssetUUID] is InventoryItem)
543 linkedItem = (InventoryItem)Inventory[item.AssetUUID];
550 if (linkedItem is InventoryWearable)
552 InventoryWearable w = linkedItem as InventoryWearable;
553 img = GetItemImageIndex(w.WearableType.ToString().ToLower());
557 img = GetItemImageIndex(linkedItem.AssetType.ToString().ToLower());
560 itemNode.ImageIndex = img;
561 itemNode.SelectedImageIndex = img;
562 parent.Nodes.Add(itemNode);
563 lock (UUID2NodeCache)
565 UUID2NodeCache[item.UUID] = itemNode;
570 TreeNode findNodeForItem(UUID itemID)
572 lock (UUID2NodeCache)
574 if (UUID2NodeCache.ContainsKey(itemID))
576 return UUID2NodeCache[itemID];
582 void cacheNode(TreeNode node)
584 InventoryBase item = (InventoryBase)node.Tag;
587 foreach (TreeNode child in node.Nodes)
591 lock (UUID2NodeCache)
593 UUID2NodeCache[item.UUID] = node;
598 void removeNode(TreeNode node)
600 InventoryBase item = (InventoryBase)node.Tag;
603 foreach (TreeNode child in node.Nodes)
608 lock (UUID2NodeCache)
610 UUID2NodeCache.Remove(item.UUID);
618 #region Private methods
619 private void UpdateStatus(string text)
623 Invoke(new MethodInvoker(delegate() { UpdateStatus(text); }));
629 saveAllTToolStripMenuItem.Enabled = true;
632 tlabelStatus.Text = text;
635 private void UpdateNodeLabel(UUID itemID)
637 if (instance.MainForm.InvokeRequired)
639 instance.MainForm.BeginInvoke(new MethodInvoker(() => UpdateNodeLabel(itemID)));
643 TreeNode node = findNodeForItem(itemID);
646 node.Text = ItemLabel((InventoryBase)node.Tag, false);
650 private void AddFolderFromStore(TreeNode parent, InventoryFolder f)
652 List<InventoryBase> contents = Inventory.GetContents(f);
653 foreach (InventoryBase item in contents)
655 TreeNode node = AddBase(parent, item);
656 if (item is InventoryFolder)
658 AddFolderFromStore(node, (InventoryFolder)item);
663 private void TraverseAndQueueNodes(InventoryNode start)
665 bool has_items = false;
667 foreach (InventoryNode node in start.Nodes.Values)
669 if (node.Data is InventoryItem)
676 if (!has_items || start.NeedsUpdate)
680 lock (FolderFetchRetries)
683 FolderFetchRetries.TryGetValue(start.Data.UUID, out retries);
686 if (!QueuedFolders.Contains(start.Data.UUID))
688 QueuedFolders.Add(start.Data.UUID);
691 FolderFetchRetries[start.Data.UUID] = retries + 1;
696 foreach (InventoryBase item in Inventory.GetContents((InventoryFolder)start.Data))
698 if (item is InventoryFolder)
700 TraverseAndQueueNodes(Inventory.GetNodeFor(item.UUID));
705 private void TraverseNodes(InventoryNode start)
707 bool has_items = false;
709 foreach (InventoryNode node in start.Nodes.Values)
711 if (node.Data is InventoryItem)
718 if (!has_items || start.NeedsUpdate)
720 InventoryFolder f = (InventoryFolder)start.Data;
721 AutoResetEvent gotFolderEvent = new AutoResetEvent(false);
722 bool success = false;
724 EventHandler<FolderUpdatedEventArgs> callback = delegate(object sender, FolderUpdatedEventArgs ea)
726 if (f.UUID == ea.FolderID)
728 if (((InventoryFolder)Inventory.Items[ea.FolderID].Data).DescendentCount <= Inventory.Items[ea.FolderID].Nodes.Count)
731 gotFolderEvent.Set();
736 client.Inventory.FolderUpdated += callback;
737 fetchFolder(f.UUID, f.OwnerID, true);
738 gotFolderEvent.WaitOne(30 * 1000, false);
739 client.Inventory.FolderUpdated -= callback;
743 Logger.Log(string.Format("Failed fetching folder {0}, got {1} items out of {2}", f.Name, Inventory.Items[f.UUID].Nodes.Count, ((InventoryFolder)Inventory.Items[f.UUID].Data).DescendentCount), Helpers.LogLevel.Error, client);
747 foreach (InventoryBase item in Inventory.GetContents((InventoryFolder)start.Data))
749 if (item is InventoryFolder)
751 TraverseNodes(Inventory.GetNodeFor(item.UUID));
756 private void StartTraverseNodes()
758 if (!client.Network.CurrentSim.Caps.IsEventQueueRunning)
760 AutoResetEvent EQRunning = new AutoResetEvent(false);
761 EventHandler<EventQueueRunningEventArgs> handler = (sender, e) =>
765 client.Network.EventQueueRunning += handler;
766 EQRunning.WaitOne(10 * 1000, false);
767 client.Network.EventQueueRunning -= handler;
770 if (!client.Network.CurrentSim.Caps.IsEventQueueRunning)
775 UpdateStatus("Loading...");
776 TreeUpdateInProgress = true;
777 TreeUpdateTimer.Start();
779 lock (FolderFetchRetries)
781 FolderFetchRetries.Clear();
788 QueuedFolders.Clear();
790 TraverseAndQueueNodes(Inventory.RootNode);
791 if (QueuedFolders.Count == 0) break;
792 Logger.DebugLog(string.Format("Queued {0} folders for update", QueuedFolders.Count));
794 Parallel.ForEach<UUID>(Math.Min(QueuedFolders.Count, 6), QueuedFolders, folderID =>
796 bool success = false;
798 AutoResetEvent gotFolder = new AutoResetEvent(false);
799 EventHandler<FolderUpdatedEventArgs> handler = (sender, ev) =>
801 if (ev.FolderID == folderID)
803 success = ev.Success;
808 client.Inventory.FolderUpdated += handler;
809 client.Inventory.RequestFolderContents(folderID, client.Self.AgentID, true, true, InventorySortOrder.ByDate);
810 if (!gotFolder.WaitOne(15 * 1000, false))
814 client.Inventory.FolderUpdated -= handler;
817 while (QueuedFolders.Count > 0);
819 TreeUpdateTimer.Stop();
822 Invoke(new MethodInvoker(() => TreeUpdateTimerTick(null, null)));
824 TreeUpdateInProgress = false;
826 instance.TabConsole.DisplayNotificationInChat("Inventory update completed.");
828 if ((client.Network.LoginResponseData.FirstLogin) && !string.IsNullOrEmpty(client.Network.LoginResponseData.InitialOutfit))
830 client.Self.SetAgentAccess("A");
831 var initOufit = new InitialOutfit(instance);
832 initOufit.SetInitialOutfit(client.Network.LoginResponseData.InitialOutfit);
835 // Updated labels on clothes that we are wearing
838 // Update attachments now that we are done
841 foreach (AttachmentInfo a in attachments.Values)
845 if (Inventory.Contains(a.InventoryID))
847 a.MarkedAttached = true;
848 a.Item = (InventoryItem)Inventory[a.InventoryID];
849 UpdateNodeLabel(a.InventoryID);
853 client.Inventory.RequestFetchInventory(a.InventoryID, client.Self.AgentID);
860 Logger.Log("Finished updating invenory folders, saving cache...", Helpers.LogLevel.Debug, client);
861 WorkPool.QueueUserWorkItem((object state) => Inventory.SaveToDisk(instance.InventoryCacheFileName));
863 if (!instance.MonoRuntime || IsHandleCreated)
864 Invoke(new MethodInvoker(() =>
873 public void ReloadInventory()
875 if (TreeUpdateInProgress)
877 TreeUpdateTimer.Stop();
878 InventoryUpdate.Abort();
879 InventoryUpdate = null;
882 saveAllTToolStripMenuItem.Enabled = false;
884 Inventory.Items = new Dictionary<UUID, InventoryNode>();
885 Inventory.RootFolder = Inventory.RootFolder;
887 invTree.Nodes.Clear();
888 UUID2NodeCache.Clear();
889 invRootNode = AddDir(null, Inventory.RootFolder);
890 Inventory.RootNode.NeedsUpdate = true;
892 InventoryUpdate = new Thread(new ThreadStart(StartTraverseNodes));
893 InventoryUpdate.Name = "InventoryUpdate";
894 InventoryUpdate.IsBackground = true;
895 InventoryUpdate.Start();
896 invRootNode.Expand();
899 private void reloadInventoryToolStripMenuItem_Click(object sender, EventArgs e)
904 private void TreeUpdateTimerTick(Object sender, EventArgs e)
908 if (ItemsToAdd.Count > 0)
910 invTree.BeginUpdate();
911 while (ItemsToAdd.Count > 0)
913 InventoryBase item = ItemsToAdd.Dequeue();
914 TreeNode node = findNodeForItem(item.ParentUUID);
926 if (ItemsToUpdate.Count > 0)
928 invTree.BeginUpdate();
929 while (ItemsToUpdate.Count > 0)
931 InventoryBase item = ItemsToUpdate.Dequeue();
932 Exec_OnInventoryObjectUpdated(item, item);
938 UpdateStatus("Loading... " + UUID2NodeCache.Count.ToString() + " items");
943 private void btnProfile_Click(object sender, EventArgs e)
945 instance.MainForm.ShowAgentProfile(txtCreator.Text, txtCreator.AgentID);
948 void UpdateItemInfo(InventoryItem item)
950 foreach (Control c in pnlDetail.Controls)
954 pnlDetail.Controls.Clear();
955 pnlItemProperties.Tag = item;
959 pnlItemProperties.Visible = false;
963 pnlItemProperties.Visible = true;
964 btnProfile.Enabled = true;
965 txtItemName.Text = item.Name;
966 txtItemDescription.Text = item.Description;
967 txtCreator.AgentID = item.CreatorID;
968 txtCreator.Tag = item.CreatorID;
969 txtCreated.Text = item.CreationDate.ToString();
971 if (item.AssetUUID != UUID.Zero)
973 txtAssetID.Text = item.AssetUUID.ToString();
977 txtAssetID.Text = String.Empty;
980 txtInvID.Text = item.UUID.ToString();
982 Permissions p = item.Permissions;
983 cbOwnerModify.Checked = (p.OwnerMask & PermissionMask.Modify) != 0;
984 cbOwnerCopy.Checked = (p.OwnerMask & PermissionMask.Copy) != 0;
985 cbOwnerTransfer.Checked = (p.OwnerMask & PermissionMask.Transfer) != 0;
987 cbNextOwnModify.CheckedChanged -= cbNextOwnerUpdate_CheckedChanged;
988 cbNextOwnCopy.CheckedChanged -= cbNextOwnerUpdate_CheckedChanged;
989 cbNextOwnTransfer.CheckedChanged -= cbNextOwnerUpdate_CheckedChanged;
991 cbNextOwnModify.Checked = (p.NextOwnerMask & PermissionMask.Modify) != 0;
992 cbNextOwnCopy.Checked = (p.NextOwnerMask & PermissionMask.Copy) != 0;
993 cbNextOwnTransfer.Checked = (p.NextOwnerMask & PermissionMask.Transfer) != 0;
995 cbNextOwnModify.CheckedChanged += cbNextOwnerUpdate_CheckedChanged;
996 cbNextOwnCopy.CheckedChanged += cbNextOwnerUpdate_CheckedChanged;
997 cbNextOwnTransfer.CheckedChanged += cbNextOwnerUpdate_CheckedChanged;
1000 switch (item.AssetType)
1002 case AssetType.Texture:
1003 SLImageHandler image = new SLImageHandler(instance, item.AssetUUID, item.Name, IsFullPerm(item));
1004 image.Dock = DockStyle.Fill;
1005 pnlDetail.Controls.Add(image);
1008 case AssetType.Notecard:
1009 Notecard note = new Notecard(instance, (InventoryNotecard)item);
1010 note.Dock = DockStyle.Fill;
1012 note.TabStop = true;
1013 pnlDetail.Controls.Add(note);
1014 note.rtbContent.Focus();
1017 case AssetType.Landmark:
1018 Landmark landmark = new Landmark(instance, (InventoryLandmark)item);
1019 landmark.Dock = DockStyle.Fill;
1020 pnlDetail.Controls.Add(landmark);
1023 case AssetType.LSLText:
1024 ScriptEditor script = new ScriptEditor(instance, (InventoryLSL)item);
1025 script.Dock = DockStyle.Fill;
1026 script.TabIndex = 3;
1027 script.TabStop = true;
1028 pnlDetail.Controls.Add(script);
1031 case AssetType.Gesture:
1032 Guesture gesture = new Guesture(instance, (InventoryGesture)item);
1033 gesture.Dock = DockStyle.Fill;
1034 pnlDetail.Controls.Add(gesture);
1039 tabsInventory.SelectedTab = tabDetail;
1042 void cbNextOwnerUpdate_CheckedChanged(object sender, EventArgs e)
1044 InventoryItem item = null;
1045 if (pnlItemProperties.Tag != null && pnlItemProperties.Tag is InventoryItem)
1047 item = (InventoryItem)pnlItemProperties.Tag;
1049 if (item == null) return;
1051 PermissionMask pm = PermissionMask.Move;
1052 if (cbNextOwnCopy.Checked) pm |= PermissionMask.Copy;
1053 if (cbNextOwnModify.Checked) pm |= PermissionMask.Modify;
1054 if (cbNextOwnTransfer.Checked) pm |= PermissionMask.Transfer;
1055 item.Permissions.NextOwnerMask = pm;
1057 client.Inventory.RequestUpdateItem(item);
1058 client.Inventory.RequestFetchInventory(item.UUID, item.OwnerID);
1061 private void txtItemName_Leave(object sender, EventArgs e)
1063 InventoryItem item = null;
1064 if (pnlItemProperties.Tag != null && pnlItemProperties.Tag is InventoryItem)
1066 item = (InventoryItem)pnlItemProperties.Tag;
1068 if (item == null) return;
1070 item.Name = txtItemName.Text;
1072 client.Inventory.RequestUpdateItem(item);
1073 client.Inventory.RequestFetchInventory(item.UUID, item.OwnerID);
1076 private void txtItemDescription_Leave(object sender, EventArgs e)
1078 InventoryItem item = null;
1079 if (pnlItemProperties.Tag != null && pnlItemProperties.Tag is InventoryItem)
1081 item = (InventoryItem)pnlItemProperties.Tag;
1083 if (item == null) return;
1085 item.Description = txtItemDescription.Text;
1087 client.Inventory.RequestUpdateItem(item);
1088 client.Inventory.RequestFetchInventory(item.UUID, item.OwnerID);
1091 void invTree_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
1093 if (invTree.SelectedNode.Tag is InventoryItem)
1095 InventoryItem item = invTree.SelectedNode.Tag as InventoryItem;
1096 item = instance.COF.RealInventoryItem(item);
1098 switch (item.AssetType)
1101 case AssetType.Landmark:
1102 instance.TabConsole.DisplayNotificationInChat("Teleporting to " + item.Name);
1103 client.Self.RequestTeleport(item.AssetUUID);
1106 case AssetType.Gesture:
1107 client.Self.PlayGesture(item.AssetUUID);
1110 case AssetType.Notecard:
1111 Notecard note = new Notecard(instance, (InventoryNotecard)item);
1112 note.Dock = DockStyle.Fill;
1113 note.ShowDetached();
1116 case AssetType.LSLText:
1117 ScriptEditor script = new ScriptEditor(instance, (InventoryLSL)item);
1118 script.Dock = DockStyle.Fill;
1119 script.ShowDetached();
1122 case AssetType.Object:
1123 if (IsAttached(item))
1125 instance.COF.Detach(item);
1129 instance.COF.Attach(item, AttachmentPoint.Default, true);
1133 case AssetType.Bodypart:
1134 case AssetType.Clothing:
1137 if (item.AssetType == AssetType.Clothing)
1139 instance.COF.RemoveFromOutfit(item);
1144 instance.COF.AddToOutfit(item, true);
1151 private void fetchFolder(UUID folderID, UUID ownerID, bool force)
1153 if (force || !fetchedFolders.Contains(folderID))
1155 if (!fetchedFolders.Contains(folderID))
1157 fetchedFolders.Add(folderID);
1160 client.Inventory.RequestFolderContents(folderID, ownerID, true, true, InventorySortOrder.ByDate);
1164 public bool IsWorn(InventoryItem item)
1166 bool worn = client.Appearance.IsItemWorn(item) != WearableType.Invalid;
1170 if (worn && !WornItems.Contains(item.UUID))
1171 WornItems.Add(item.UUID);
1176 public AttachmentPoint AttachedTo(InventoryItem item)
1180 if (attachments.ContainsKey(item.UUID))
1182 return attachments[item.UUID].Point;
1186 return AttachmentPoint.Default;
1189 public bool IsAttached(InventoryItem item)
1191 List<Primitive> myAtt = client.Network.CurrentSim.ObjectsPrimitives.FindAll((Primitive p) => p.ParentID == client.Self.LocalID);
1192 foreach (Primitive prim in myAtt)
1194 if (prim.NameValues == null) continue;
1195 UUID invID = UUID.Zero;
1196 for (int i = 0; i < prim.NameValues.Length; i++)
1198 if (prim.NameValues[i].Name == "AttachItemID")
1200 invID = (UUID)prim.NameValues[i].Value.ToString();
1204 if (invID == item.UUID)
1208 AttachmentInfo inf = new AttachmentInfo();
1209 inf.InventoryID = item.UUID;
1211 inf.MarkedAttached = true;
1213 inf.PrimID = prim.ID;
1214 attachments[invID] = inf;
1223 public InventoryItem AttachmentAt(AttachmentPoint point)
1227 foreach (KeyValuePair<UUID, AttachmentInfo> att in attachments)
1229 if (att.Value.Point == point)
1231 return att.Value.Item;
1239 /// Returns text of the label
1241 /// <param name="invBase">Inventory item</param>
1242 /// <param name="returnRaw">Should we return raw text, or if false decorated text with (worn) info, and (no copy) etc. permission info</param>
1243 /// <returns></returns>
1244 public string ItemLabel(InventoryBase invBase, bool returnRaw)
1246 if (returnRaw || (invBase is InventoryFolder))
1247 return invBase.Name;
1249 InventoryItem item = (InventoryItem)invBase;
1251 string raw = item.Name;
1256 item = instance.COF.RealInventoryItem(item);
1257 if (Inventory.Contains(item.AssetUUID) && Inventory[item.AssetUUID] is InventoryItem)
1259 item = (InventoryItem)Inventory[item.AssetUUID];
1263 if ((item.Permissions.OwnerMask & PermissionMask.Modify) == 0)
1264 raw += " (no modify)";
1266 if ((item.Permissions.OwnerMask & PermissionMask.Copy) == 0)
1267 raw += " (no copy)";
1269 if ((item.Permissions.OwnerMask & PermissionMask.Transfer) == 0)
1270 raw += " (no transfer)";
1275 if (IsAttached(item))
1277 raw += " (worn on " + AttachedTo(item).ToString() + ")";
1283 public static bool IsFullPerm(InventoryItem item)
1286 ((item.Permissions.OwnerMask & PermissionMask.Modify) != 0) &&
1287 ((item.Permissions.OwnerMask & PermissionMask.Copy) != 0) &&
1288 ((item.Permissions.OwnerMask & PermissionMask.Transfer) != 0)
1299 void invTree_MouseClick(object sender, TreeNodeMouseClickEventArgs e)
1301 TreeNode node = e.Node;
1303 if (e.Button == MouseButtons.Left)
1305 invTree.SelectedNode = node;
1306 if (node.Tag is InventoryItem)
1308 UpdateItemInfo(instance.COF.RealInventoryItem(node.Tag as InventoryItem));
1312 UpdateItemInfo(null);
1315 else if (e.Button == MouseButtons.Right)
1317 invTree.SelectedNode = node;
1318 ctxInv.Show(invTree, e.X, e.Y);
1322 private void ctxInv_Opening(object sender, CancelEventArgs e)
1325 TreeNode node = invTree.SelectedNode;
1332 #region Folder context menu
1333 if (node.Tag is InventoryFolder)
1335 InventoryFolder folder = (InventoryFolder)node.Tag;
1336 ctxInv.Items.Clear();
1338 ToolStripMenuItem ctxItem;
1340 if ((int)folder.PreferredType >= (int)AssetType.EnsembleStart &&
1341 (int)folder.PreferredType <= (int)AssetType.EnsembleEnd)
1343 ctxItem = new ToolStripMenuItem("Fix type", null, OnInvContextClick);
1344 ctxItem.Name = "fix_type";
1345 ctxInv.Items.Add(ctxItem);
1346 ctxInv.Items.Add(new ToolStripSeparator());
1349 ctxItem = new ToolStripMenuItem("New Folder", null, OnInvContextClick);
1350 ctxItem.Name = "new_folder";
1351 ctxInv.Items.Add(ctxItem);
1353 ctxItem = new ToolStripMenuItem("New Note", null, OnInvContextClick);
1354 ctxItem.Name = "new_notecard";
1355 ctxInv.Items.Add(ctxItem);
1357 ctxItem = new ToolStripMenuItem("New Script", null, OnInvContextClick);
1358 ctxItem.Name = "new_script";
1359 ctxInv.Items.Add(ctxItem);
1361 ctxItem = new ToolStripMenuItem("Refresh", null, OnInvContextClick);
1362 ctxItem.Name = "refresh";
1363 ctxInv.Items.Add(ctxItem);
1365 ctxItem = new ToolStripMenuItem("Backup...", null, OnInvContextClick);
1366 ctxItem.Name = "backup";
1367 ctxInv.Items.Add(ctxItem);
1369 ctxInv.Items.Add(new ToolStripSeparator());
1371 ctxItem = new ToolStripMenuItem("Expand", null, OnInvContextClick);
1372 ctxItem.Name = "expand";
1373 ctxInv.Items.Add(ctxItem);
1375 ctxItem = new ToolStripMenuItem("Expand All", null, OnInvContextClick);
1376 ctxItem.Name = "expand_all";
1377 ctxInv.Items.Add(ctxItem);
1379 ctxItem = new ToolStripMenuItem("Collapse", null, OnInvContextClick);
1380 ctxItem.Name = "collapse";
1381 ctxInv.Items.Add(ctxItem);
1383 if (folder.PreferredType == AssetType.TrashFolder)
1385 ctxItem = new ToolStripMenuItem("Empty Trash", null, OnInvContextClick);
1386 ctxItem.Name = "empty_trash";
1387 ctxInv.Items.Add(ctxItem);
1390 if (folder.PreferredType == AssetType.LostAndFoundFolder)
1392 ctxItem = new ToolStripMenuItem("Empty Lost and Found", null, OnInvContextClick);
1393 ctxItem.Name = "empty_lost_found";
1394 ctxInv.Items.Add(ctxItem);
1397 if (folder.PreferredType == AssetType.Unknown ||
1398 folder.PreferredType == AssetType.OutfitFolder)
1400 ctxItem = new ToolStripMenuItem("Rename", null, OnInvContextClick);
1401 ctxItem.Name = "rename_folder";
1402 ctxInv.Items.Add(ctxItem);
1404 ctxInv.Items.Add(new ToolStripSeparator());
1406 ctxItem = new ToolStripMenuItem("Cut", null, OnInvContextClick);
1407 ctxItem.Name = "cut_folder";
1408 ctxInv.Items.Add(ctxItem);
1410 ctxItem = new ToolStripMenuItem("Copy", null, OnInvContextClick);
1411 ctxItem.Name = "copy_folder";
1412 ctxInv.Items.Add(ctxItem);
1415 if (instance.InventoryClipboard != null)
1417 ctxItem = new ToolStripMenuItem("Paste", null, OnInvContextClick);
1418 ctxItem.Name = "paste_folder";
1419 ctxInv.Items.Add(ctxItem);
1421 if (instance.InventoryClipboard.Item is InventoryItem)
1423 ctxItem = new ToolStripMenuItem("Paste as Link", null, OnInvContextClick);
1424 ctxItem.Name = "paste_folder_link";
1425 ctxInv.Items.Add(ctxItem);
1429 if (folder.PreferredType == AssetType.Unknown ||
1430 folder.PreferredType == AssetType.OutfitFolder)
1432 ctxItem = new ToolStripMenuItem("Delete", null, OnInvContextClick);
1433 ctxItem.Name = "delete_folder";
1434 ctxInv.Items.Add(ctxItem);
1436 ctxInv.Items.Add(new ToolStripSeparator());
1439 if (folder.PreferredType == AssetType.Unknown || folder.PreferredType == AssetType.OutfitFolder)
1441 ctxItem = new ToolStripMenuItem("Take off Items", null, OnInvContextClick);
1442 ctxItem.Name = "outfit_take_off";
1443 ctxInv.Items.Add(ctxItem);
1445 ctxItem = new ToolStripMenuItem("Add to Outfit", null, OnInvContextClick);
1446 ctxItem.Name = "outfit_add";
1447 ctxInv.Items.Add(ctxItem);
1449 ctxItem = new ToolStripMenuItem("Replace Outfit", null, OnInvContextClick);
1450 ctxItem.Name = "outfit_replace";
1451 ctxInv.Items.Add(ctxItem);
1454 instance.ContextActionManager.AddContributions(ctxInv, folder);
1455 #endregion Folder context menu
1457 else if (node.Tag is InventoryItem)
1459 #region Item context menu
1460 InventoryItem item = instance.COF.RealInventoryItem((InventoryItem)node.Tag);
1461 ctxInv.Items.Clear();
1463 ToolStripMenuItem ctxItem;
1465 if (item.InventoryType == InventoryType.LSL)
1467 ctxItem = new ToolStripMenuItem("Edit script", null, OnInvContextClick);
1468 ctxItem.Name = "edit_script";
1469 ctxInv.Items.Add(ctxItem);
1472 if (item.AssetType == AssetType.Texture)
1474 ctxItem = new ToolStripMenuItem("View", null, OnInvContextClick);
1475 ctxItem.Name = "view_image";
1476 ctxInv.Items.Add(ctxItem);
1479 if (item.InventoryType == InventoryType.Landmark)
1481 ctxItem = new ToolStripMenuItem("Teleport", null, OnInvContextClick);
1482 ctxItem.Name = "lm_teleport";
1483 ctxInv.Items.Add(ctxItem);
1485 ctxItem = new ToolStripMenuItem("Info", null, OnInvContextClick);
1486 ctxItem.Name = "lm_info";
1487 ctxInv.Items.Add(ctxItem);
1490 if (item.InventoryType == InventoryType.Notecard)
1492 ctxItem = new ToolStripMenuItem("Open", null, OnInvContextClick);
1493 ctxItem.Name = "notecard_open";
1494 ctxInv.Items.Add(ctxItem);
1497 if (item.InventoryType == InventoryType.Gesture)
1499 ctxItem = new ToolStripMenuItem("Play", null, OnInvContextClick);
1500 ctxItem.Name = "gesture_play";
1501 ctxInv.Items.Add(ctxItem);
1503 ctxItem = new ToolStripMenuItem("Info", null, OnInvContextClick);
1504 ctxItem.Name = "gesture_info";
1505 ctxInv.Items.Add(ctxItem);
1508 if (item.InventoryType == InventoryType.Animation)
1510 if (!client.Self.SignaledAnimations.ContainsKey(item.AssetUUID))
1512 ctxItem = new ToolStripMenuItem("Play", null, OnInvContextClick);
1513 ctxItem.Name = "animation_play";
1514 ctxInv.Items.Add(ctxItem);
1518 ctxItem = new ToolStripMenuItem("Stop", null, OnInvContextClick);
1519 ctxItem.Name = "animation_stop";
1520 ctxInv.Items.Add(ctxItem);
1524 if (item.InventoryType == InventoryType.Object)
1526 ctxItem = new ToolStripMenuItem("Rez inworld", null, OnInvContextClick);
1527 ctxItem.Name = "rez_inworld";
1528 ctxInv.Items.Add(ctxItem);
1531 ctxItem = new ToolStripMenuItem("Rename", null, OnInvContextClick);
1532 ctxItem.Name = "rename_item";
1533 ctxInv.Items.Add(ctxItem);
1535 ctxInv.Items.Add(new ToolStripSeparator());
1537 ctxItem = new ToolStripMenuItem("Cut", null, OnInvContextClick);
1538 ctxItem.Name = "cut_item";
1539 ctxInv.Items.Add(ctxItem);
1541 ctxItem = new ToolStripMenuItem("Copy", null, OnInvContextClick);
1542 ctxItem.Name = "copy_item";
1543 ctxInv.Items.Add(ctxItem);
1545 if (instance.InventoryClipboard != null)
1547 ctxItem = new ToolStripMenuItem("Paste", null, OnInvContextClick);
1548 ctxItem.Name = "paste_item";
1549 ctxInv.Items.Add(ctxItem);
1551 if (instance.InventoryClipboard.Item is InventoryItem)
1553 ctxItem = new ToolStripMenuItem("Paste as Link", null, OnInvContextClick);
1554 ctxItem.Name = "paste_item_link";
1555 ctxInv.Items.Add(ctxItem);
1559 ctxItem = new ToolStripMenuItem("Delete", null, OnInvContextClick);
1560 ctxItem.Name = "delete_item";
1562 if (IsAttached(item) || IsWorn(item))
1564 ctxItem.Enabled = false;
1566 ctxInv.Items.Add(ctxItem);
1568 if (IsAttached(item) && instance.RLV.AllowDetach(attachments[item.UUID]))
1570 ctxItem = new ToolStripMenuItem("Detach from yourself", null, OnInvContextClick);
1571 ctxItem.Name = "detach";
1572 ctxInv.Items.Add(ctxItem);
1575 if (!IsAttached(item) && (item.InventoryType == InventoryType.Object || item.InventoryType == InventoryType.Attachment))
1577 ToolStripMenuItem ctxItemAttach = new ToolStripMenuItem("Attach to");
1578 ctxInv.Items.Add(ctxItemAttach);
1580 ToolStripMenuItem ctxItemAttachHUD = new ToolStripMenuItem("Attach to HUD");
1581 ctxInv.Items.Add(ctxItemAttachHUD);
1583 foreach (AttachmentPoint pt in Enum.GetValues(typeof(AttachmentPoint)))
1585 if (!pt.ToString().StartsWith("HUD"))
1587 string name = Utils.EnumToText(pt);
1589 InventoryItem alreadyAttached = null;
1590 if ((alreadyAttached = AttachmentAt(pt)) != null)
1592 name += " (" + alreadyAttached.Name + ")";
1595 ToolStripMenuItem ptItem = new ToolStripMenuItem(name, null, OnInvContextClick);
1596 ptItem.Name = pt.ToString();
1598 ptItem.Name = "attach_to";
1599 ctxItemAttach.DropDownItems.Add(ptItem);
1603 string name = Utils.EnumToText(pt).Substring(3);
1605 InventoryItem alreadyAttached = null;
1606 if ((alreadyAttached = AttachmentAt(pt)) != null)
1608 name += " (" + alreadyAttached.Name + ")";
1611 ToolStripMenuItem ptItem = new ToolStripMenuItem(name, null, OnInvContextClick);
1612 ptItem.Name = pt.ToString();
1614 ptItem.Name = "attach_to";
1615 ctxItemAttachHUD.DropDownItems.Add(ptItem);
1619 ctxItem = new ToolStripMenuItem("Add to Worn", null, OnInvContextClick);
1620 ctxItem.Name = "wear_attachment_add";
1621 ctxInv.Items.Add(ctxItem);
1623 ctxItem = new ToolStripMenuItem("Wear", null, OnInvContextClick);
1624 ctxItem.Name = "wear_attachment";
1625 ctxInv.Items.Add(ctxItem);
1628 if (item is InventoryWearable)
1630 ctxInv.Items.Add(new ToolStripSeparator());
1634 ctxItem = new ToolStripMenuItem("Take off", null, OnInvContextClick);
1635 ctxItem.Name = "item_take_off";
1636 ctxInv.Items.Add(ctxItem);
1640 ctxItem = new ToolStripMenuItem("Wear", null, OnInvContextClick);
1641 ctxItem.Name = "item_wear";
1642 ctxInv.Items.Add(ctxItem);
1646 instance.ContextActionManager.AddContributions(ctxInv, item);
1647 #endregion Item context menu
1652 #region Context menu folder
1653 private void OnInvContextClick(object sender, EventArgs e)
1655 if (invTree.SelectedNode == null || !(invTree.SelectedNode.Tag is InventoryBase))
1660 string cmd = ((ToolStripMenuItem)sender).Name;
1662 if (invTree.SelectedNode.Tag is InventoryFolder)
1664 #region Folder actions
1665 InventoryFolder f = (InventoryFolder)invTree.SelectedNode.Tag;
1670 foreach (TreeNode old in invTree.SelectedNode.Nodes)
1672 if (!(old.Tag is InventoryFolder))
1677 fetchFolder(f.UUID, f.OwnerID, true);
1681 (new InventoryBackup(instance, f.UUID)).Show();
1685 invTree.SelectedNode.Expand();
1689 invTree.SelectedNode.ExpandAll();
1693 invTree.SelectedNode.Collapse();
1697 newItemName = "New folder";
1698 client.Inventory.CreateFolder(f.UUID, "New folder");
1702 client.Inventory.UpdateFolderProperties(f.UUID, f.ParentUUID, f.Name, AssetType.Unknown);
1706 case "new_notecard":
1707 client.Inventory.RequestCreateItem(f.UUID, "New Note", "Radegast note: " + DateTime.Now.ToString(),
1708 AssetType.Notecard, UUID.Zero, InventoryType.Notecard, PermissionMask.All, NotecardCreated);
1712 client.Inventory.RequestCreateItem(f.UUID, "New script", "Radegast script: " + DateTime.Now.ToString(),
1713 AssetType.LSLText, UUID.Zero, InventoryType.LSL, PermissionMask.All, ScriptCreated);
1717 instance.InventoryClipboard = new InventoryClipboard(ClipboardOperation.Cut, f);
1721 instance.InventoryClipboard = new InventoryClipboard(ClipboardOperation.Copy, f);
1724 case "paste_folder":
1725 PerformClipboardOperation(invTree.SelectedNode.Tag as InventoryFolder);
1728 case "paste_folder_link":
1729 PerformLinkOperation(invTree.SelectedNode.Tag as InventoryFolder);
1733 case "delete_folder":
1734 var trash = client.Inventory.FindFolderForType(AssetType.TrashFolder);
1735 if (trash == Inventory.RootFolder.UUID)
1737 WorkPool.QueueUserWorkItem(sync =>
1739 trashCreated.Reset();
1740 trash = client.Inventory.CreateFolder(Inventory.RootFolder.UUID, "Trash", AssetType.TrashFolder);
1741 trashCreated.WaitOne(20 * 1000, false);
1743 client.Inventory.MoveFolder(f.UUID, trash, f.Name);
1748 client.Inventory.MoveFolder(f.UUID, trash, f.Name);
1753 DialogResult res = MessageBox.Show("Are you sure you want to empty your trash?", "Confirmation", MessageBoxButtons.OKCancel);
1754 if (res == DialogResult.OK)
1756 client.Inventory.EmptyTrash();
1761 case "empty_lost_found":
1763 DialogResult res = MessageBox.Show("Are you sure you want to empty your lost and found folder?", "Confirmation", MessageBoxButtons.OKCancel);
1764 if (res == DialogResult.OK)
1766 client.Inventory.EmptyLostAndFound();
1771 case "rename_folder":
1772 invTree.SelectedNode.BeginEdit();
1775 case "outfit_replace":
1776 List<InventoryItem> newOutfit = new List<InventoryItem>();
1777 foreach (InventoryBase item in Inventory.GetContents(f))
1779 if (item is InventoryItem)
1780 newOutfit.Add((InventoryItem)item);
1782 appearnceWasBusy = client.Appearance.ManagerBusy;
1783 instance.COF.ReplaceOutfit(newOutfit);
1788 List<InventoryItem> addToOutfit = new List<InventoryItem>();
1789 foreach (InventoryBase item in Inventory.GetContents(f))
1791 if (item is InventoryItem)
1792 addToOutfit.Add((InventoryItem)item);
1794 appearnceWasBusy = client.Appearance.ManagerBusy;
1795 instance.COF.AddToOutfit(addToOutfit, true);
1799 case "outfit_take_off":
1800 List<InventoryItem> removeFromOutfit = new List<InventoryItem>();
1801 foreach (InventoryBase item in Inventory.GetContents(f))
1803 if (item is InventoryItem)
1804 removeFromOutfit.Add((InventoryItem)item);
1806 appearnceWasBusy = client.Appearance.ManagerBusy;
1807 instance.COF.RemoveFromOutfit(removeFromOutfit);
1813 else if (invTree.SelectedNode.Tag is InventoryItem)
1815 #region Item actions
1816 InventoryItem item = (InventoryItem)invTree.SelectedNode.Tag;
1818 // Copy, cut, and delete works on links directly
1819 // The rest operate on the item that is pointed by the link
1820 if (cmd != "copy_item" && cmd != "cut_item" && cmd != "delete_item")
1822 item = instance.COF.RealInventoryItem(item);
1828 instance.InventoryClipboard = new InventoryClipboard(ClipboardOperation.Copy, item);
1832 instance.InventoryClipboard = new InventoryClipboard(ClipboardOperation.Cut, item);
1836 PerformClipboardOperation(invTree.SelectedNode.Parent.Tag as InventoryFolder);
1839 case "paste_item_link":
1840 PerformLinkOperation(invTree.SelectedNode.Parent.Tag as InventoryFolder);
1844 var trash = client.Inventory.FindFolderForType(AssetType.TrashFolder);
1845 if (trash == Inventory.RootFolder.UUID)
1847 WorkPool.QueueUserWorkItem(sync =>
1849 trashCreated.Reset();
1850 trash = client.Inventory.CreateFolder(Inventory.RootFolder.UUID, "Trash", AssetType.TrashFolder);
1851 trashCreated.WaitOne(20 * 1000, false);
1853 client.Inventory.MoveItem(item.UUID, trash, item.Name);
1858 client.Inventory.MoveItem(item.UUID, client.Inventory.FindFolderForType(AssetType.TrashFolder), item.Name);
1862 invTree.SelectedNode.BeginEdit();
1866 instance.COF.Detach(item);
1867 lock (attachments) attachments.Remove(item.UUID);
1868 invTree.SelectedNode.Text = ItemLabel(item, false);
1871 case "wear_attachment":
1872 instance.COF.Attach(item, AttachmentPoint.Default, true);
1875 case "wear_attachment_add":
1876 instance.COF.Attach(item, AttachmentPoint.Default, false);
1880 AttachmentPoint pt = (AttachmentPoint)((ToolStripMenuItem)sender).Tag;
1881 instance.COF.Attach(item, pt, true);
1885 ScriptEditor se = new ScriptEditor(instance, (InventoryLSL)item);
1890 UpdateItemInfo(item);
1893 case "item_take_off":
1894 appearnceWasBusy = client.Appearance.ManagerBusy;
1895 instance.COF.RemoveFromOutfit(item);
1896 invTree.SelectedNode.Text = ItemLabel(item, false);
1899 if (WornItems.Contains(item.UUID))
1901 WornItems.Remove(item.UUID);
1907 appearnceWasBusy = client.Appearance.ManagerBusy;
1908 instance.COF.AddToOutfit(item, true);
1909 invTree.SelectedNode.Text = ItemLabel(item, false);
1913 instance.TabConsole.DisplayNotificationInChat("Teleporting to " + item.Name);
1914 client.Self.RequestTeleport(item.AssetUUID);
1918 UpdateItemInfo(item);
1921 case "notecard_open":
1922 UpdateItemInfo(item);
1925 case "gesture_info":
1926 UpdateItemInfo(item);
1929 case "gesture_play":
1930 client.Self.PlayGesture(item.AssetUUID);
1933 case "animation_play":
1934 Dictionary<UUID, bool> anim = new Dictionary<UUID, bool>();
1935 anim.Add(item.AssetUUID, true);
1936 client.Self.Animate(anim, true);
1939 case "animation_stop":
1940 Dictionary<UUID, bool> animStop = new Dictionary<UUID, bool>();
1941 animStop.Add(item.AssetUUID, false);
1942 client.Self.Animate(animStop, true);
1946 instance.MediaManager.PlayUISound(UISounds.ObjectRez);
1947 Vector3 rezpos = new Vector3(2, 0, 0);
1948 rezpos = client.Self.SimPosition + rezpos * client.Self.Movement.BodyRotation;
1949 client.Inventory.RequestRezFromInventory(client.Network.CurrentSim, Quaternion.Identity, rezpos, item);
1956 void NotecardCreated(bool success, InventoryItem item)
1960 BeginInvoke(new MethodInvoker(() => NotecardCreated(success, item)));
1966 instance.TabConsole.DisplayNotificationInChat("Creation of notecard failed");
1970 instance.TabConsole.DisplayNotificationInChat("New notecard created, enter notecard name and press enter", ChatBufferTextStyle.Invisible);
1971 var node = findNodeForItem(item.ParentUUID);
1972 if (node != null) node.Expand();
1973 node = findNodeForItem(item.UUID);
1976 invTree.SelectedNode = node;
1981 void ScriptCreated(bool success, InventoryItem item)
1985 BeginInvoke(new MethodInvoker(() => ScriptCreated(success, item)));
1991 instance.TabConsole.DisplayNotificationInChat("Creation of script failed");
1995 instance.TabConsole.DisplayNotificationInChat("New script created, enter script name and press enter", ChatBufferTextStyle.Invisible);
1996 var node = findNodeForItem(item.ParentUUID);
1997 if (node != null) node.Expand();
1998 node = findNodeForItem(item.UUID);
2001 invTree.SelectedNode = node;
2006 void PerformClipboardOperation(InventoryFolder dest)
2008 if (instance.InventoryClipboard == null) return;
2010 if (dest == null) return;
2012 if (instance.InventoryClipboard.Operation == ClipboardOperation.Cut)
2014 if (instance.InventoryClipboard.Item is InventoryItem)
2016 client.Inventory.MoveItem(instance.InventoryClipboard.Item.UUID, dest.UUID, instance.InventoryClipboard.Item.Name);
2018 else if (instance.InventoryClipboard.Item is InventoryFolder)
2020 if (instance.InventoryClipboard.Item.UUID != dest.UUID)
2022 client.Inventory.MoveFolder(instance.InventoryClipboard.Item.UUID, dest.UUID, instance.InventoryClipboard.Item.Name);
2026 instance.InventoryClipboard = null;
2028 else if (instance.InventoryClipboard.Operation == ClipboardOperation.Copy)
2030 if (instance.InventoryClipboard.Item is InventoryItem)
2032 client.Inventory.RequestCopyItem(instance.InventoryClipboard.Item.UUID, dest.UUID, instance.InventoryClipboard.Item.Name, instance.InventoryClipboard.Item.OwnerID, (InventoryBase target) =>
2037 else if (instance.InventoryClipboard.Item is InventoryFolder)
2039 WorkPool.QueueUserWorkItem((object state) =>
2041 UUID newFolderID = client.Inventory.CreateFolder(dest.UUID, instance.InventoryClipboard.Item.Name, AssetType.Unknown);
2044 // FIXME: for some reason copying a bunch of items in one operation does not work
2046 //List<UUID> items = new List<UUID>();
2047 //List<UUID> folders = new List<UUID>();
2048 //List<string> names = new List<string>();
2049 //UUID oldOwner = UUID.Zero;
2051 foreach (InventoryBase oldItem in Inventory.GetContents((InventoryFolder)instance.InventoryClipboard.Item))
2053 //folders.Add(newFolderID);
2054 //names.Add(oldItem.Name);
2055 //items.Add(oldItem.UUID);
2056 //oldOwner = oldItem.OwnerID;
2057 client.Inventory.RequestCopyItem(oldItem.UUID, newFolderID, oldItem.Name, oldItem.OwnerID, (InventoryBase target) => { });
2060 //if (folders.Count > 0)
2062 // client.Inventory.RequestCopyItems(items, folders, names, oldOwner, (InventoryBase target) => { });
2070 void PerformLinkOperation(InventoryFolder dest)
2072 if (instance.InventoryClipboard == null) return;
2074 if (dest == null) return;
2076 client.Inventory.CreateLink(dest.UUID, instance.InventoryClipboard.Item, (bool success, InventoryItem item) => { });
2081 private void UpdateWornLabels()
2085 BeginInvoke(new MethodInvoker(UpdateWornLabels));
2089 invTree.BeginUpdate();
2090 foreach (UUID itemID in WornItems)
2092 TreeNode node = findNodeForItem(itemID);
2095 node.Text = ItemLabel((InventoryBase)node.Tag, false);
2099 foreach (AppearanceManager.WearableData wearable in client.Appearance.GetWearables().Values)
2101 TreeNode node = findNodeForItem(wearable.ItemID);
2104 node.Text = ItemLabel((InventoryBase)node.Tag, false);
2107 invTree.EndUpdate();
2110 void TreeView_AfterExpand(object sender, TreeViewEventArgs e)
2112 // Check if we need to go into edit mode for new items
2113 if (newItemName != string.Empty)
2115 foreach (TreeNode n in e.Node.Nodes)
2117 if (n.Name == newItemName)
2123 newItemName = string.Empty;
2127 private bool _EditingNode = false;
2129 private void OnLabelEditTimer(object sender)
2131 if (_EditNode == null || !(_EditNode.Tag is InventoryBase))
2136 BeginInvoke(new MethodInvoker(delegate()
2138 OnLabelEditTimer(sender);
2144 _EditingNode = true;
2145 _EditNode.Text = ItemLabel((InventoryBase)_EditNode.Tag, true);
2146 _EditNode.BeginEdit();
2149 private void invTree_BeforeLabelEdit(object sender, NodeLabelEditEventArgs e)
2151 if (e.Node == null ||
2152 !(e.Node.Tag is InventoryBase) ||
2153 (e.Node.Tag is InventoryFolder &&
2154 ((InventoryFolder)e.Node.Tag).PreferredType != AssetType.Unknown &&
2155 ((InventoryFolder)e.Node.Tag).PreferredType != AssetType.OutfitFolder)
2158 e.CancelEdit = true;
2164 _EditingNode = false;
2168 e.CancelEdit = true;
2170 _EditTimer.Change(20, System.Threading.Timeout.Infinite);
2174 private void invTree_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
2176 if (string.IsNullOrEmpty(e.Label))
2178 if (e.Node.Tag is InventoryBase)
2180 e.Node.Text = ItemLabel((InventoryBase)e.Node.Tag, false);
2182 e.CancelEdit = true;
2186 if (e.Node.Tag is InventoryFolder)
2188 InventoryFolder f = (InventoryFolder)e.Node.Tag;
2190 client.Inventory.MoveFolder(f.UUID, f.ParentUUID, f.Name);
2192 else if (e.Node.Tag is InventoryItem)
2194 InventoryItem item = (InventoryItem)e.Node.Tag;
2195 item.Name = e.Label;
2196 e.Node.Text = ItemLabel((InventoryBase)item, false);
2197 client.Inventory.MoveItem(item.UUID, item.ParentUUID, item.Name);
2198 UpdateItemInfo(item);
2203 private void invTree_KeyUp(object sender, KeyEventArgs e)
2205 if (e.KeyCode == Keys.F2 && invTree.SelectedNode != null)
2207 invTree.SelectedNode.BeginEdit();
2209 else if (e.KeyCode == Keys.F5 && invTree.SelectedNode != null)
2211 if (invTree.SelectedNode.Tag is InventoryFolder)
2213 InventoryFolder f = (InventoryFolder)invTree.SelectedNode.Tag;
2214 fetchFolder(f.UUID, f.OwnerID, true);
2217 else if (e.KeyCode == Keys.Delete && invTree.SelectedNode != null)
2219 var trash = client.Inventory.FindFolderForType(AssetType.TrashFolder);
2220 if (trash == Inventory.RootFolder.UUID)
2222 trash = client.Inventory.CreateFolder(Inventory.RootFolder.UUID, "Trash", AssetType.TrashFolder);
2226 if (invTree.SelectedNode.Tag is InventoryItem)
2228 InventoryItem item = invTree.SelectedNode.Tag as InventoryItem;
2229 client.Inventory.MoveItem(item.UUID, trash, item.Name);
2231 else if (invTree.SelectedNode.Tag is InventoryFolder)
2233 InventoryFolder f = invTree.SelectedNode.Tag as InventoryFolder;
2234 client.Inventory.MoveFolder(f.UUID, trash, f.Name);
2237 else if (e.KeyCode == Keys.Apps && invTree.SelectedNode != null)
2243 #region Drag and Drop
2244 private void invTree_ItemDrag(object sender, ItemDragEventArgs e)
2246 invTree.SelectedNode = e.Item as TreeNode;
2247 if (invTree.SelectedNode.Tag is InventoryFolder && ((InventoryFolder)invTree.SelectedNode.Tag).PreferredType != AssetType.Unknown)
2251 invTree.DoDragDrop(e.Item, DragDropEffects.Move);
2254 private void invTree_DragDrop(object sender, DragEventArgs e)
2256 if (highlightedNode != null)
2258 highlightedNode.BackColor = invTree.BackColor;
2259 highlightedNode = null;
2262 TreeNode sourceNode = e.Data.GetData(typeof(TreeNode)) as TreeNode;
2263 if (sourceNode == null) return;
2265 Point pt = ((TreeView)sender).PointToClient(new Point(e.X, e.Y));
2266 TreeNode destinationNode = ((TreeView)sender).GetNodeAt(pt);
2268 if (destinationNode == null) return;
2270 if (sourceNode == destinationNode) return;
2272 // If droping to item within folder drop to its folder
2273 if (destinationNode.Tag is InventoryItem)
2275 destinationNode = destinationNode.Parent;
2278 InventoryFolder dest = destinationNode.Tag as InventoryFolder;
2280 if (dest == null) return;
2282 if (sourceNode.Tag is InventoryItem)
2284 InventoryItem item = (InventoryItem)sourceNode.Tag;
2285 client.Inventory.MoveItem(item.UUID, dest.UUID, item.Name);
2287 else if (sourceNode.Tag is InventoryFolder)
2289 InventoryFolder f = (InventoryFolder)sourceNode.Tag;
2290 client.Inventory.MoveFolder(f.UUID, dest.UUID, f.Name);
2294 private void invTree_DragEnter(object sender, DragEventArgs e)
2296 TreeNode node = e.Data.GetData(typeof(TreeNode)) as TreeNode;
2299 e.Effect = DragDropEffects.None;
2303 e.Effect = DragDropEffects.Move;
2307 TreeNode highlightedNode = null;
2309 private void invTree_DragOver(object sender, DragEventArgs e)
2311 TreeNode node = e.Data.GetData(typeof(TreeNode)) as TreeNode;
2314 e.Effect = DragDropEffects.None;
2317 Point pt = ((TreeView)sender).PointToClient(new Point(e.X, e.Y));
2318 TreeNode destinationNode = ((TreeView)sender).GetNodeAt(pt);
2320 if (highlightedNode != destinationNode)
2322 if (highlightedNode != null)
2324 highlightedNode.BackColor = invTree.BackColor;
2325 highlightedNode = null;
2328 if (destinationNode != null)
2330 highlightedNode = destinationNode;
2331 highlightedNode.BackColor = Color.LightSlateGray;
2335 if (destinationNode == null)
2337 e.Effect = DragDropEffects.None;
2341 e.Effect = DragDropEffects.Move;
2346 private void saveAllTToolStripMenuItem_Click(object sender, EventArgs e)
2348 (new InventoryBackup(instance, Inventory.RootFolder.UUID)).Show();
2351 private void tbtnSystemFoldersFirst_Click(object sender, EventArgs e)
2353 sorter.SystemFoldersFirst = tbtnSystemFoldersFirst.Checked = !sorter.SystemFoldersFirst;
2354 instance.GlobalSettings["inv_sort_sysfirst"] = OSD.FromBoolean(sorter.SystemFoldersFirst);
2358 private void tbtbSortByName_Click(object sender, EventArgs e)
2360 if (tbtbSortByName.Checked) return;
2362 tbtbSortByName.Checked = true;
2363 tbtnSortByDate.Checked = sorter.ByDate = false;
2364 instance.GlobalSettings["inv_sort_bydate"] = OSD.FromBoolean(sorter.ByDate);
2369 private void tbtnSortByDate_Click(object sender, EventArgs e)
2371 if (tbtnSortByDate.Checked) return;
2373 tbtbSortByName.Checked = false;
2374 tbtnSortByDate.Checked = sorter.ByDate = true;
2375 instance.GlobalSettings["inv_sort_bydate"] = OSD.FromBoolean(sorter.ByDate);
2382 public class SearchResult
2384 public InventoryBase Inv;
2387 public SearchResult(InventoryBase inv, int level)
2394 List<SearchResult> searchRes;
2395 string searchString;
2396 Dictionary<int, ListViewItem> searchItemCache = new Dictionary<int, ListViewItem>();
2397 ListViewItem emptyItem = null;
2400 void PerformRecursiveSearch(int level, UUID folderID)
2402 var me = Inventory.Items[folderID].Data;
2403 searchRes.Add(new SearchResult(me, level));
2404 var sorted = Inventory.GetContents(folderID);
2406 sorted.Sort((InventoryBase b1, InventoryBase b2) =>
2408 if (b1 is InventoryFolder && !(b2 is InventoryFolder))
2412 else if (!(b1 is InventoryFolder) && b2 is InventoryFolder)
2418 return string.Compare(b1.Name, b2.Name);
2422 foreach (var item in sorted)
2424 if (item is InventoryFolder)
2426 PerformRecursiveSearch(level + 1, item.UUID);
2430 var it = item as InventoryItem;
2433 if (cbSrchName.Checked && it.Name.ToLower().Contains(searchString))
2437 else if (cbSrchDesc.Checked && it.Description.ToLower().Contains(searchString))
2442 if (cbSrchWorn.Checked && add &&
2444 (it.InventoryType == InventoryType.Wearable && IsWorn(it)) ||
2445 ((it.InventoryType == InventoryType.Attachment || it.InventoryType == InventoryType.Object) && IsAttached(it))
2452 if (cbSrchRecent.Checked && add && it.CreationDate < instance.StartupTimeUTC)
2460 searchRes.Add(new SearchResult(it, level + 1));
2465 if (searchRes[searchRes.Count - 1].Inv == me)
2467 searchRes.RemoveAt(searchRes.Count - 1);
2471 public void UpdateSearch()
2475 if (instance.MonoRuntime)
2477 lstInventorySearch.VirtualMode = false;
2478 lstInventorySearch.Items.Clear();
2479 lstInventorySearch.VirtualMode = true;
2482 lstInventorySearch.VirtualListSize = 0;
2483 searchString = txtSearch.Text.Trim().ToLower();
2485 //if (searchString == string.Empty && rbSrchAll.Checked)
2487 // lblSearchStatus.Text = "0 results";
2491 if (emptyItem == null)
2493 emptyItem = new ListViewItem(string.Empty);
2496 searchRes = new List<SearchResult>(Inventory.Items.Count);
2497 searchItemCache.Clear();
2498 PerformRecursiveSearch(0, Inventory.RootFolder.UUID);
2499 lstInventorySearch.VirtualListSize = searchRes.Count;
2500 lblSearchStatus.Text = string.Format("{0} results", found);
2503 private void lstInventorySearch_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
2505 if (searchItemCache.ContainsKey(e.ItemIndex))
2507 e.Item = searchItemCache[e.ItemIndex];
2509 else if (e.ItemIndex < searchRes.Count)
2511 InventoryBase inv = searchRes[e.ItemIndex].Inv;
2512 string desc = inv.Name;
2513 if (inv is InventoryItem)
2515 desc += string.Format(" - {0}", ((InventoryItem)inv).Description);
2517 ListViewItem item = new ListViewItem(desc);
2518 item.Tag = searchRes[e.ItemIndex];
2520 searchItemCache[e.ItemIndex] = item;
2528 private void btnInvSearch_Click(object sender, EventArgs e)
2533 private void cbSrchName_CheckedChanged(object sender, EventArgs e)
2535 if (!cbSrchName.Checked && !cbSrchDesc.Checked && !cbSrchCreator.Checked)
2537 cbSrchName.Checked = true;
2542 private void cbSrchWorn_CheckedChanged(object sender, EventArgs e)
2547 private void txtSearch_KeyDown(object sender, KeyEventArgs e)
2549 if (e.KeyCode == Keys.Enter)
2551 e.Handled = e.SuppressKeyPress = true;
2552 if (txtSearch.Text.Trim().Length > 0)
2559 private void lstInventorySearch_DrawItem(object sender, DrawListViewItemEventArgs e)
2561 Graphics g = e.Graphics;
2564 if (!(e.Item.Tag is SearchResult))
2567 if (e.Item.Selected)
2569 g.FillRectangle(SystemBrushes.Highlight, e.Bounds);
2572 SearchResult res = e.Item.Tag as SearchResult;
2573 int offset = 20 * (res.Level + 1);
2574 Rectangle rec = new Rectangle(e.Bounds.X + offset, e.Bounds.Y, e.Bounds.Width - offset, e.Bounds.Height);
2579 if (res.Inv is InventoryFolder)
2581 iconIx = GetDirImageIndex(((InventoryFolder)res.Inv).PreferredType.ToString().ToLower());
2583 else if (res.Inv is InventoryWearable)
2585 iconIx = GetItemImageIndex(((InventoryWearable)res.Inv).WearableType.ToString().ToLower());
2587 else if (res.Inv is InventoryItem)
2589 iconIx = GetItemImageIndex(((InventoryItem)res.Inv).AssetType.ToString().ToLower());
2599 icon = frmMain.ResourceImages.Images[iconIx];
2600 g.DrawImageUnscaled(icon, e.Bounds.X + offset - 18, e.Bounds.Y);
2604 using (StringFormat sf = new StringFormat(StringFormatFlags.NoWrap | StringFormatFlags.LineLimit))
2606 string label = ItemLabel(res.Inv, false);
2607 SizeF len = e.Graphics.MeasureString(label, lstInventorySearch.Font, rec.Width, sf);
2609 e.Graphics.DrawString(
2610 ItemLabel(res.Inv, false),
2611 lstInventorySearch.Font,
2612 e.Item.Selected ? SystemBrushes.HighlightText : SystemBrushes.WindowText,
2616 if (res.Inv is InventoryItem)
2618 string desc = ((InventoryItem)res.Inv).Description.Trim();
2619 if (desc != string.Empty)
2621 using (Font descFont = new Font(lstInventorySearch.Font, FontStyle.Italic))
2623 e.Graphics.DrawString(desc,
2625 e.Item.Selected ? SystemBrushes.HighlightText : SystemBrushes.GrayText,
2626 rec.X + len.Width + 5,
2636 private void lstInventorySearch_SizeChanged(object sender, EventArgs e)
2638 chResItemName.Width = lstInventorySearch.Width - 30;
2641 private void txtSearch_TextChanged(object sender, EventArgs e)
2646 private void rbSrchAll_CheckedChanged(object sender, EventArgs e)
2651 private void lstInventorySearch_KeyDown(object sender, KeyEventArgs e)
2653 if ((e.KeyCode == Keys.Apps) || (e.Control && e.KeyCode == RadegastContextMenuStrip.ContexMenuKeyCode))
2655 lstInventorySearch_MouseClick(sender, new MouseEventArgs(MouseButtons.Right, 1, 50, 150, 0));
2660 /// Finds and higlights inventory node
2662 /// <param name="itemID">Inventory of ID of the item to select</param>
2663 public void SelectInventoryNode(UUID itemID)
2665 TreeNode node = findNodeForItem(itemID);
2668 invTree.SelectedNode = node;
2669 if (node.Tag is InventoryItem)
2671 UpdateItemInfo(node.Tag as InventoryItem);
2675 private void lstInventorySearch_MouseClick(object sender, MouseEventArgs e)
2677 if (lstInventorySearch.SelectedIndices.Count != 1)
2682 SearchResult res = searchRes[lstInventorySearch.SelectedIndices[0]];
2683 TreeNode node = findNodeForItem(res.Inv.UUID);
2686 invTree.SelectedNode = node;
2687 if (e.Button == MouseButtons.Right)
2689 ctxInv.Show(lstInventorySearch, e.X, e.Y);
2695 private void lstInventorySearch_MouseDoubleClick(object sender, MouseEventArgs e)
2697 if (lstInventorySearch.SelectedIndices.Count != 1)
2702 SearchResult res = searchRes[lstInventorySearch.SelectedIndices[0]];
2703 TreeNode node = findNodeForItem(res.Inv.UUID);
2706 invTree.SelectedNode = node;
2707 invTree_NodeMouseDoubleClick(null, null);
2714 private void txtAssetID_Enter(object sender, EventArgs e)
2716 txtAssetID.SelectAll();
2719 private void txtInvID_Enter(object sender, EventArgs e)
2721 txtInvID.SelectAll();
2724 private void copyInitialOutfitsToolStripMenuItem_Click(object sender, EventArgs e)
2726 var c = new FolderCopy(instance);
2727 c.GetFolders("Initial Outfits");
2733 #region Sorter class
2734 // Create a node sorter that implements the IComparer interface.
2735 public class InvNodeSorter : System.Collections.IComparer
2737 bool _sysfirst = true;
2738 bool _bydate = true;
2740 int CompareFolders(InventoryFolder x, InventoryFolder y)
2744 if (x.PreferredType != AssetType.Unknown && y.PreferredType == AssetType.Unknown)
2748 else if (x.PreferredType == AssetType.Unknown && y.PreferredType != AssetType.Unknown)
2753 return String.Compare(x.Name, y.Name);
2756 public bool SystemFoldersFirst { set { _sysfirst = value; } get { return _sysfirst; } }
2757 public bool ByDate { set { _bydate = value; } get { return _bydate; } }
2759 public int Compare(object x, object y)
2761 TreeNode tx = x as TreeNode;
2762 TreeNode ty = y as TreeNode;
2764 if (tx.Tag is InventoryFolder && ty.Tag is InventoryFolder)
2766 return CompareFolders(tx.Tag as InventoryFolder, ty.Tag as InventoryFolder);
2768 else if (tx.Tag is InventoryFolder && ty.Tag is InventoryItem)
2772 else if (tx.Tag is InventoryItem && ty.Tag is InventoryFolder)
2778 if (!(tx.Tag is InventoryItem) || !(ty.Tag is InventoryItem))
2783 InventoryItem item1 = (InventoryItem)tx.Tag;
2784 InventoryItem item2 = (InventoryItem)ty.Tag;
2788 if (item1.CreationDate < item2.CreationDate)
2792 else if (item1.CreationDate > item2.CreationDate)
2797 return string.Compare(item1.Name, item2.Name);
2802 public class AttachmentInfo
2804 public Primitive Prim;
2805 public InventoryItem Item;
2806 public UUID InventoryID;
2808 public bool MarkedAttached = false;
2810 public AttachmentPoint Point
2816 return Prim.PrimData.AttachmentPoint;
2820 return AttachmentPoint.Default;