OSDN Git Service

RAD-307: Added support for Multiple Attachments
authorLatif Khalifa <latifer@streamgrid.net>
Fri, 7 Oct 2011 13:30:28 +0000 (13:30 +0000)
committerLatif Khalifa <latifer@streamgrid.net>
Fri, 7 Oct 2011 13:30:28 +0000 (13:30 +0000)
RAD-295: My avatar gets partially stripped when using Radegast

git-svn-id: https://radegast.googlecode.com/svn/trunk@1160 f7a694da-4d33-11de-9ad6-1127a62b9fcd

Radegast/Core/RadegastInstance.cs
Radegast/GUI/Consoles/Inventory/CurrentOutfitFolder.cs [new file with mode: 0644]
Radegast/GUI/Consoles/Inventory/InventoryConsole.Designer.cs
Radegast/GUI/Consoles/Inventory/InventoryConsole.cs
Radegast/Radegast.csproj

index 4832138..1242307 100644 (file)
@@ -214,6 +214,8 @@ namespace Radegast
 
         public Keyboard Keyboard;
 
+        public CurrentOutfitFolder COF;
+
         #region Events
 
         #region ClientChanged event
@@ -307,6 +309,7 @@ namespace Radegast
             gridManager.LoadGrids();
 
             names = new NameManager(this);
+            COF = new CurrentOutfitFolder(this);
 
             mainForm = new frmMain(this);
             mainForm.InitializeControls();
@@ -427,6 +430,12 @@ namespace Radegast
 
         public void CleanUp()
         {
+            if (COF != null)
+            {
+                COF.Dispose();
+                COF = null;
+            }
+            
             if (names != null)
             {
                 names.Dispose();
diff --git a/Radegast/GUI/Consoles/Inventory/CurrentOutfitFolder.cs b/Radegast/GUI/Consoles/Inventory/CurrentOutfitFolder.cs
new file mode 100644 (file)
index 0000000..5e2a00c
--- /dev/null
@@ -0,0 +1,396 @@
+// 
+// Radegast Metaverse Client
+// Copyright (c) 2009-2011, Radegast Development Team
+// All rights reserved.
+// 
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+// 
+//     * Redistributions of source code must retain the above copyright notice,
+//       this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above copyright
+//       notice, this list of conditions and the following disclaimer in the
+//       documentation and/or other materials provided with the distribution.
+//     * Neither the name of the application "Radegast", nor the names of its
+//       contributors may be used to endorse or promote products derived from
+//       this software without specific prior written permission.
+// 
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// $Id$
+//
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using OpenMetaverse;
+using OpenMetaverse.StructuredData;
+
+namespace Radegast
+{
+    public class CurrentOutfitFolder : IDisposable
+    {
+        #region Fields
+        GridClient Client;
+        RadegastInstance Instance;
+        bool InitiCOF = false;
+        bool InvCAP = false;
+        bool AppearanceSent = false;
+        bool COFReady = false;
+        bool InitialUpdateDone = false;
+        public List<InventoryItem> ContentLinks = new List<InventoryItem>();
+        public Dictionary<UUID, InventoryItem> Content = new Dictionary<UUID, InventoryItem>();
+        public InventoryFolder COF;
+        #endregion Fields
+
+        #region Construction and disposal
+        public CurrentOutfitFolder(RadegastInstance instance)
+        {
+            this.Instance = instance;
+            this.Client = instance.Client;
+            Instance.ClientChanged += new EventHandler<ClientChangedEventArgs>(instance_ClientChanged);
+            RegisterClientEvents(Client);
+        }
+
+        public void Dispose()
+        {
+            UnregisterClientEvents(Client);
+            Instance.ClientChanged -= new EventHandler<ClientChangedEventArgs>(instance_ClientChanged);
+        }
+        #endregion Construction and disposal
+
+        #region Event handling
+        void instance_ClientChanged(object sender, ClientChangedEventArgs e)
+        {
+            UnregisterClientEvents(Client);
+            Client = e.Client;
+            RegisterClientEvents(Client);
+        }
+
+        void RegisterClientEvents(GridClient client)
+        {
+            client.Network.EventQueueRunning += new EventHandler<EventQueueRunningEventArgs>(Network_EventQueueRunning);
+            client.Inventory.FolderUpdated += new EventHandler<FolderUpdatedEventArgs>(Inventory_FolderUpdated);
+            client.Inventory.ItemReceived += new EventHandler<ItemReceivedEventArgs>(Inventory_ItemReceived);
+            client.Appearance.AppearanceSet += new EventHandler<AppearanceSetEventArgs>(Appearance_AppearanceSet);
+            client.Objects.KillObject += new EventHandler<KillObjectEventArgs>(Objects_KillObject);
+        }
+
+        void UnregisterClientEvents(GridClient client)
+        {
+            client.Network.EventQueueRunning -= new EventHandler<EventQueueRunningEventArgs>(Network_EventQueueRunning);
+            client.Inventory.FolderUpdated -= new EventHandler<FolderUpdatedEventArgs>(Inventory_FolderUpdated);
+            client.Inventory.ItemReceived -= new EventHandler<ItemReceivedEventArgs>(Inventory_ItemReceived);
+            client.Appearance.AppearanceSet -= new EventHandler<AppearanceSetEventArgs>(Appearance_AppearanceSet);
+            client.Objects.KillObject -= new EventHandler<KillObjectEventArgs>(Objects_KillObject);
+            lock (Content) Content.Clear();
+            lock (ContentLinks) ContentLinks.Clear();
+            InitiCOF = false;
+            InvCAP = false;
+            AppearanceSent = false;
+            COFReady = false;
+            InitialUpdateDone = false;
+        }
+
+        void Appearance_AppearanceSet(object sender, AppearanceSetEventArgs e)
+        {
+            AppearanceSent = true;
+            if (COFReady)
+            {
+                InitialUpdate();
+            }
+        }
+
+        void Inventory_ItemReceived(object sender, ItemReceivedEventArgs e)
+        {
+            lock (ContentLinks)
+            {
+                bool partOfCOF = false;
+                foreach (var cofItem in ContentLinks)
+                {
+                    if (cofItem.AssetUUID == e.Item.UUID)
+                    {
+                        partOfCOF = true;
+                        break;
+                    }
+                }
+
+                if (partOfCOF)
+                {
+                    lock (Content)
+                    {
+                        Content[e.Item.UUID] = e.Item;
+                    }
+                }
+            }
+
+            if (Content.Count == ContentLinks.Count)
+            {
+                COFReady = true;
+                if (AppearanceSent)
+                {
+                    InitialUpdate();
+                }
+            }
+        }
+
+        void Inventory_FolderUpdated(object sender, FolderUpdatedEventArgs e)
+        {
+            if (COF == null) return;
+
+            if (e.FolderID == COF.UUID && e.Success)
+            {
+                lock (Content) Content.Clear();
+                lock (ContentLinks) ContentLinks.Clear();
+
+                List<InventoryBase> content = Client.Inventory.Store.GetContents(COF);
+                foreach (var baseItem in content)
+                {
+                    if (baseItem is InventoryItem)
+                    {
+                        InventoryItem item = (InventoryItem)baseItem;
+                        if (item.AssetType == AssetType.Link)
+                        {
+                            ContentLinks.Add(item);
+                        }
+                    }
+                }
+
+                List<UUID> items = new List<UUID>();
+                List<UUID> owners = new List<UUID>();
+
+                lock (ContentLinks)
+                {
+                    foreach (var link in ContentLinks)
+                    {
+                        items.Add(link.AssetUUID);
+                        owners.Add(Client.Self.AgentID);
+                    }
+                }
+
+                if (items.Count > 0)
+                {
+                    Client.Inventory.RequestFetchInventory(items, owners);
+                }
+            }
+        }
+
+        void Objects_KillObject(object sender, KillObjectEventArgs e)
+        {
+            if (Client.Network.CurrentSim != e.Simulator) return;
+
+            Primitive prim = null;
+            if (Client.Network.CurrentSim.ObjectsPrimitives.TryGetValue(e.ObjectLocalID, out prim))
+            {
+                UUID invItem = GetAttachmentItem(prim);
+                if (invItem != UUID.Zero)
+                {
+                    RemoveLink(invItem);
+                }
+            }
+        }
+
+        void Network_EventQueueRunning(object sender, EventQueueRunningEventArgs e)
+        {
+            if (e.Simulator == Client.Network.CurrentSim && !InitiCOF)
+            {
+                InitiCOF = true;
+                InitCOF();
+            }
+        }
+        #endregion Event handling
+
+        #region Private methods
+        void RequestDescendants(UUID folderID)
+        {
+            if (InvCAP)
+            {
+                Client.Inventory.RequestFolderContentsCap(folderID, Client.Self.AgentID, true, true, InventorySortOrder.ByDate);
+            }
+            else
+            {
+                Client.Inventory.RequestFolderContents(folderID, Client.Self.AgentID, true, true, InventorySortOrder.ByDate);
+            }
+        }
+
+        void InitCOF()
+        {
+            Uri url = null;
+
+            if (Client.Network.CurrentSim.Caps == null ||
+                null == (url = Client.Network.CurrentSim.Caps.CapabilityURI("FetchInventoryDescendents2")))
+            {
+                InvCAP = false;
+            }
+            else
+            {
+                InvCAP = true;
+            }
+
+            List<InventoryBase> rootContent = Client.Inventory.Store.GetContents(Client.Inventory.Store.RootFolder.UUID);
+            foreach (InventoryBase baseItem in rootContent)
+            {
+                if (baseItem is InventoryFolder && ((InventoryFolder)baseItem).PreferredType == AssetType.CurrentOutfitFolder)
+                {
+                    COF = (InventoryFolder)baseItem;
+                    break;
+                }
+            }
+
+            if (COF == null)
+            {
+                CreateCOF();
+            }
+            else
+            {
+                RequestDescendants(COF.UUID);
+            }
+        }
+
+        void CreateCOF()
+        {
+            UUID cofID = Client.Inventory.CreateFolder(Client.Inventory.Store.RootFolder.UUID, "Current Look", AssetType.CurrentOutfitFolder);
+            if (Client.Inventory.Store.Items.ContainsKey(cofID) && Client.Inventory.Store.Items[cofID].Data is InventoryFolder)
+            {
+                COF = (InventoryFolder)Client.Inventory.Store.Items[cofID].Data;
+                COFReady = true;
+                if (AppearanceSent)
+                {
+                    InitialUpdate();
+                }
+            }
+        }
+
+        void InitialUpdate()
+        {
+            if (InitialUpdateDone) return;
+            InitialUpdateDone = true;
+            lock (Content)
+            {
+                List<Primitive> myAtt = Client.Network.CurrentSim.ObjectsPrimitives.FindAll((Primitive p) => p.ParentID == Client.Self.LocalID);
+
+                foreach (InventoryItem item in Content.Values)
+                {
+                    if (item is InventoryObject || item is InventoryAttachment)
+                    {
+                        if (!IsAttached(myAtt, item))
+                        {
+                            Client.Appearance.Attach(item, AttachmentPoint.Default, false);
+                        }
+                    }
+                }
+            }
+        }
+        #endregion Private methods
+
+        #region Public methods
+        /// <summary>
+        /// Get inventory ID of a prim
+        /// </summary>
+        /// <param name="prim">Prim to check</param>
+        /// <returns>Inventory ID of the object. UUID.Zero if not found</returns>
+        public static UUID GetAttachmentItem(Primitive prim)
+        {
+            if (prim.NameValues == null) return UUID.Zero;
+
+            for (int i = 0; i < prim.NameValues.Length; i++)
+            {
+                if (prim.NameValues[i].Name == "AttachItemID")
+                {
+                    return (UUID)prim.NameValues[i].Value.ToString();
+                }
+            }
+            return UUID.Zero;
+        }
+
+        /// <summary>
+        /// Is an inventory item currently attached
+        /// </summary>
+        /// <param name="attachments">List of root prims that are attached to our avatar</param>
+        /// <param name="item">Inventory item to check</param>
+        /// <returns>True if the inventory item is attached to avatar</returns>
+        public static bool IsAttached(List<Primitive> attachments, InventoryItem item)
+        {
+            foreach (Primitive prim in attachments)
+            {
+                if (GetAttachmentItem(prim) == item.UUID)
+                {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        /// Attach an inventory item
+        /// </summary>
+        /// <param name="item">Item to be attached</param>
+        /// <param name="point">Attachment point</param>
+        /// <param name="replace">Replace existing attachment at that point first?</param>
+        public void Attach(InventoryItem item, AttachmentPoint point, bool replace)
+        {
+            Client.Appearance.Attach(item, point, replace);
+            if (COF == null) return;
+
+            bool linkExists = false;
+            lock (ContentLinks)
+            {
+                linkExists = null != ContentLinks.Find(itemLink => itemLink.AssetUUID == item.UUID);
+            }
+            if (!linkExists)
+            {
+                Client.Inventory.CreateLink(COF.UUID, item, (success, newItem) =>
+                {
+                    if (success)
+                    {
+                        lock (ContentLinks)
+                        {
+                            ContentLinks.Add(newItem);
+                        }
+                    }
+                });
+            }
+        }
+
+        /// <summary>
+        /// Remove a link to specified inventory item
+        /// </summary>
+        /// <param name="itemID">ID of the target inventory item for which we want link to be removed</param>
+        public void RemoveLink(UUID itemID)
+        {
+            if (COF == null) return;
+
+            lock (ContentLinks)
+            {
+                InventoryItem attachment = ContentLinks.Find(itemLink => itemLink.AssetUUID == itemID);
+                if (attachment != null)
+                {
+                    Client.Inventory.RemoveItem(attachment.UUID);
+                    ContentLinks.Remove(attachment);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Remove attachment
+        /// </summary>
+        /// <param name="item">>Inventory item to be detached</param>
+        public void Detach(InventoryItem item)
+        {
+            Client.Appearance.Detach(item);
+            RemoveLink(item.UUID);
+        }
+        #endregion Public methods
+    }
+}
index 2fdd14f..c7940ce 100644 (file)
@@ -127,9 +127,11 @@ namespace Radegast
             this.txtCreated = new System.Windows.Forms.TextBox();
             this.txtAssetID = new System.Windows.Forms.TextBox();
             this.lblCreated = new System.Windows.Forms.Label();
+            this.txtItemDescription = new System.Windows.Forms.TextBox();
             this.txtItemName = new System.Windows.Forms.TextBox();
             this.lblAsset = new System.Windows.Forms.Label();
             this.lblCreator = new System.Windows.Forms.Label();
+            this.label1 = new System.Windows.Forms.Label();
             this.lblItemName = new System.Windows.Forms.Label();
             this.splitContainer1.Panel1.SuspendLayout();
             this.splitContainer1.Panel2.SuspendLayout();
@@ -507,7 +509,7 @@ namespace Radegast
             this.pnlDetail.Dock = System.Windows.Forms.DockStyle.Fill;
             this.pnlDetail.Location = new System.Drawing.Point(3, 3);
             this.pnlDetail.Name = "pnlDetail";
-            this.pnlDetail.Size = new System.Drawing.Size(427, 297);
+            this.pnlDetail.Size = new System.Drawing.Size(427, 289);
             this.pnlDetail.TabIndex = 2;
             // 
             // pnlItemProperties
@@ -518,14 +520,16 @@ namespace Radegast
             this.pnlItemProperties.Controls.Add(this.txtCreated);
             this.pnlItemProperties.Controls.Add(this.txtAssetID);
             this.pnlItemProperties.Controls.Add(this.lblCreated);
+            this.pnlItemProperties.Controls.Add(this.txtItemDescription);
             this.pnlItemProperties.Controls.Add(this.txtItemName);
             this.pnlItemProperties.Controls.Add(this.lblAsset);
             this.pnlItemProperties.Controls.Add(this.lblCreator);
+            this.pnlItemProperties.Controls.Add(this.label1);
             this.pnlItemProperties.Controls.Add(this.lblItemName);
             this.pnlItemProperties.Dock = System.Windows.Forms.DockStyle.Bottom;
-            this.pnlItemProperties.Location = new System.Drawing.Point(3, 300);
+            this.pnlItemProperties.Location = new System.Drawing.Point(3, 292);
             this.pnlItemProperties.Name = "pnlItemProperties";
-            this.pnlItemProperties.Size = new System.Drawing.Size(427, 154);
+            this.pnlItemProperties.Size = new System.Drawing.Size(427, 162);
             this.pnlItemProperties.TabIndex = 0;
             // 
             // gbxPerms
@@ -538,9 +542,9 @@ namespace Radegast
             this.gbxPerms.Controls.Add(this.cbOwnerModify);
             this.gbxPerms.Controls.Add(this.label8);
             this.gbxPerms.Controls.Add(this.label7);
-            this.gbxPerms.Location = new System.Drawing.Point(6, 81);
+            this.gbxPerms.Location = new System.Drawing.Point(6, 100);
             this.gbxPerms.Name = "gbxPerms";
-            this.gbxPerms.Size = new System.Drawing.Size(267, 64);
+            this.gbxPerms.Size = new System.Drawing.Size(267, 58);
             this.gbxPerms.TabIndex = 15;
             this.gbxPerms.TabStop = false;
             // 
@@ -630,7 +634,7 @@ namespace Radegast
             this.btnProfile.AccessibleDescription = "Open profile";
             this.btnProfile.Enabled = false;
             this.btnProfile.Image = global::Radegast.Properties.Resources.applications_16;
-            this.btnProfile.Location = new System.Drawing.Point(50, 29);
+            this.btnProfile.Location = new System.Drawing.Point(48, 53);
             this.btnProfile.Name = "btnProfile";
             this.btnProfile.Size = new System.Drawing.Size(26, 23);
             this.btnProfile.TabIndex = 12;
@@ -640,17 +644,17 @@ namespace Radegast
             // txtCreator
             // 
             this.txtCreator.BackColor = System.Drawing.SystemColors.Window;
-            this.txtCreator.Location = new System.Drawing.Point(80, 29);
+            this.txtCreator.Location = new System.Drawing.Point(80, 55);
             this.txtCreator.Name = "txtCreator";
             this.txtCreator.ReadOnly = true;
             this.txtCreator.Size = new System.Drawing.Size(169, 20);
-            this.txtCreator.TabIndex = 11;
+            this.txtCreator.TabIndex = 12;
             // 
             // txtCreated
             // 
             this.txtCreated.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
                         | System.Windows.Forms.AnchorStyles.Right)));
-            this.txtCreated.Location = new System.Drawing.Point(305, 29);
+            this.txtCreated.Location = new System.Drawing.Point(305, 55);
             this.txtCreated.Name = "txtCreated";
             this.txtCreated.ReadOnly = true;
             this.txtCreated.Size = new System.Drawing.Size(113, 20);
@@ -658,21 +662,31 @@ namespace Radegast
             // 
             // txtAssetID
             // 
-            this.txtAssetID.Location = new System.Drawing.Point(80, 55);
+            this.txtAssetID.Location = new System.Drawing.Point(80, 81);
             this.txtAssetID.Name = "txtAssetID";
             this.txtAssetID.ReadOnly = true;
-            this.txtAssetID.Size = new System.Drawing.Size(338, 20);
+            this.txtAssetID.Size = new System.Drawing.Size(169, 20);
             this.txtAssetID.TabIndex = 14;
             // 
             // lblCreated
             // 
             this.lblCreated.AutoSize = true;
-            this.lblCreated.Location = new System.Drawing.Point(255, 34);
+            this.lblCreated.Location = new System.Drawing.Point(255, 58);
             this.lblCreated.Name = "lblCreated";
             this.lblCreated.Size = new System.Drawing.Size(44, 13);
             this.lblCreated.TabIndex = 0;
             this.lblCreated.Text = "Created";
             // 
+            // txtItemDescription
+            // 
+            this.txtItemDescription.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+                        | System.Windows.Forms.AnchorStyles.Right)));
+            this.txtItemDescription.Location = new System.Drawing.Point(80, 29);
+            this.txtItemDescription.Name = "txtItemDescription";
+            this.txtItemDescription.Size = new System.Drawing.Size(338, 20);
+            this.txtItemDescription.TabIndex = 11;
+            this.txtItemDescription.Leave += new System.EventHandler(this.txtItemDescription_Leave);
+            // 
             // txtItemName
             // 
             this.txtItemName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
@@ -686,7 +700,7 @@ namespace Radegast
             // lblAsset
             // 
             this.lblAsset.AutoSize = true;
-            this.lblAsset.Location = new System.Drawing.Point(3, 58);
+            this.lblAsset.Location = new System.Drawing.Point(3, 84);
             this.lblAsset.Name = "lblAsset";
             this.lblAsset.Size = new System.Drawing.Size(47, 13);
             this.lblAsset.TabIndex = 0;
@@ -695,16 +709,25 @@ namespace Radegast
             // lblCreator
             // 
             this.lblCreator.AutoSize = true;
-            this.lblCreator.Location = new System.Drawing.Point(3, 32);
+            this.lblCreator.Location = new System.Drawing.Point(3, 58);
             this.lblCreator.Name = "lblCreator";
             this.lblCreator.Size = new System.Drawing.Size(41, 13);
             this.lblCreator.TabIndex = 0;
             this.lblCreator.Text = "Creator";
             // 
+            // label1
+            // 
+            this.label1.AutoSize = true;
+            this.label1.Location = new System.Drawing.Point(3, 32);
+            this.label1.Name = "label1";
+            this.label1.Size = new System.Drawing.Size(60, 13);
+            this.label1.TabIndex = 0;
+            this.label1.Text = "Description";
+            // 
             // lblItemName
             // 
             this.lblItemName.AutoSize = true;
-            this.lblItemName.Location = new System.Drawing.Point(3, 10);
+            this.lblItemName.Location = new System.Drawing.Point(3, 6);
             this.lblItemName.Name = "lblItemName";
             this.lblItemName.Size = new System.Drawing.Size(27, 13);
             this.lblItemName.TabIndex = 0;
@@ -793,5 +816,7 @@ namespace Radegast
         public System.Windows.Forms.TabPage tabSearch;
         public ListViewNoFlicker lstInventorySearch;
         public System.Windows.Forms.ColumnHeader chResItemName;
+        public System.Windows.Forms.TextBox txtItemDescription;
+        public System.Windows.Forms.Label label1;
     }
 }
index 2457834..5a8661b 100644 (file)
@@ -947,6 +947,7 @@ namespace Radegast
             pnlItemProperties.Visible = true;
             btnProfile.Enabled = true;
             txtItemName.Text = item.Name;
+            txtItemDescription.Text = item.Description;
             txtCreator.AgentID = item.CreatorID;
             txtCreator.Tag = item.CreatorID;
             txtCreated.Text = item.CreationDate.ToString();
@@ -1054,6 +1055,20 @@ namespace Radegast
             client.Inventory.RequestFetchInventory(item.UUID, item.OwnerID);
         }
 
+        private void txtItemDescription_Leave(object sender, EventArgs e)
+        {
+            InventoryItem item = null;
+            if (pnlItemProperties.Tag != null && pnlItemProperties.Tag is InventoryItem)
+            {
+                item = (InventoryItem)pnlItemProperties.Tag;
+            }
+            if (item == null) return;
+
+            item.Description = txtItemDescription.Text;
+
+            client.Inventory.RequestUpdateItem(item);
+            client.Inventory.RequestFetchInventory(item.UUID, item.OwnerID);
+        }
 
         void invTree_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
         {
@@ -1758,22 +1773,22 @@ namespace Radegast
                         break;
 
                     case "detach":
-                        client.Appearance.Detach(item.UUID);
+                        instance.COF.Detach(item);
                         attachments.Remove(item.UUID);
                         invTree.SelectedNode.Text = ItemLabel(item, false);
                         break;
 
                     case "wear_attachment":
-                        client.Appearance.Attach(item, AttachmentPoint.Default);
+                        instance.COF.Attach(item, AttachmentPoint.Default, true);
                         break;
 
                     case "wear_attachment_add":
-                        client.Appearance.Attach(item, AttachmentPoint.Default, false);
+                        instance.COF.Attach(item, AttachmentPoint.Default, false);
                         break;
 
                     case "attach_to":
                         AttachmentPoint pt = (AttachmentPoint)((ToolStripMenuItem)sender).Tag;
-                        client.Appearance.Attach(item, pt);
+                        instance.COF.Attach(item, pt, true);
                         break;
 
                     case "edit_script":
index b01b1f8..e243974 100644 (file)
     <Compile Include="GUI\Consoles\ImageUploadConsole.Designer.cs">\r
       <DependentUpon>ImageUploadConsole.cs</DependentUpon>\r
     </Compile>\r
+    <Compile Include="GUI\Consoles\Inventory\CurrentOutfitFolder.cs" />\r
     <Compile Include="GUI\Consoles\Inventory\InventoryBackup.cs">\r
       <SubType>Form</SubType>\r
     </Compile>\r