diff --git a/OpenMetaverse.GUI/AvatarList.cs b/OpenMetaverse.GUI/AvatarList.cs index 574b00ff..4ddce9b1 100644 --- a/OpenMetaverse.GUI/AvatarList.cs +++ b/OpenMetaverse.GUI/AvatarList.cs @@ -44,8 +44,13 @@ namespace OpenMetaverse.GUI { private GridClient _Client; private List _Avatars = new List(); + private ColumnSorter _ColumnSorter = new ColumnSorter(); public delegate void AvatarDoubleClickCallback(Avatar avatar); + + /// + /// Triggered when the user double clicks on an avatar in the list + /// public event AvatarDoubleClickCallback OnAvatarDoubleClick; /// @@ -68,11 +73,13 @@ namespace OpenMetaverse.GUI ColumnHeader header2 = this.Columns.Add(" "); header2.Width = 40; - this.DoubleBuffered = true; - this.Sorting = SortOrder.Ascending; - this.View = View.Details; - this.DoubleClick += new EventHandler(AvatarList_DoubleClick); + _ColumnSorter.SortColumn = 0; + this.DoubleBuffered = true; + this.ListViewItemSorter = _ColumnSorter; + this.View = View.Details; + this.ColumnClick += new ColumnClickEventHandler(AvatarList_ColumnClick); + this.DoubleClick += new EventHandler(AvatarList_DoubleClick); } /// @@ -145,6 +152,14 @@ namespace OpenMetaverse.GUI } } + private void AvatarList_ColumnClick(object sender, ColumnClickEventArgs e) + { + _ColumnSorter.SortColumn = e.Column; + if ((_ColumnSorter.Ascending = (this.Sorting == SortOrder.Ascending))) this.Sorting = SortOrder.Descending; + else this.Sorting = SortOrder.Ascending; + this.ListViewItemSorter = _ColumnSorter; + } + private void AvatarList_DoubleClick(object sender, EventArgs e) { ListView list = (ListView)sender; @@ -197,6 +212,39 @@ namespace OpenMetaverse.GUI } } + private class ColumnSorter : IComparer + { + public bool Ascending = true; + public int SortColumn = 0; + + public int Compare(object a, object b) + { + ListViewItem itemA = (ListViewItem)a; + ListViewItem itemB = (ListViewItem)b; + + if (SortColumn == 1) + { + int valueA = itemB.SubItems.Count > 1 ? int.Parse(itemA.SubItems[1].Text.Replace("m", "")) : 0; + int valueB = itemB.SubItems.Count > 1 ? int.Parse(itemB.SubItems[1].Text.Replace("m", "")) : 0; + if (Ascending) + { + if (valueA == valueB) return 0; + return valueA < valueB ? -1 : 1; + } + else + { + if (valueA == valueB) return 0; + return valueA < valueB ? 1 : -1; + } + } + else + { + if (Ascending) return string.Compare(itemA.Text, itemB.Text); + else return -string.Compare(itemA.Text, itemB.Text); + } + } + } + } } diff --git a/OpenMetaverse.GUI/InventoryTree.cs b/OpenMetaverse.GUI/InventoryTree.cs new file mode 100644 index 00000000..840db17d --- /dev/null +++ b/OpenMetaverse.GUI/InventoryTree.cs @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2007-2008, openmetaverse.org + * 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. + * - Neither the name of the openmetaverse.org 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 OWNER 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. + */ + +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; + +namespace OpenMetaverse.GUI +{ + + /// + /// TreeView GUI component for browsing a client's inventory + /// + public class InventoryTree : TreeView + { + private GridClient _Client; + + /// + /// Gets or sets the GridClient associated with this control + /// + public GridClient Client + { + get { return _Client; } + set { if (value != null) InitializeClient(value); } + } + + /// + /// TreeView control for an unspecified client's inventory + /// + public InventoryTree() + { + this.BeforeExpand += new TreeViewCancelEventHandler(InventoryTree_BeforeExpand); + } + + /// + /// TreeView control for the specified client's inventory + /// + /// + public InventoryTree(GridClient client) : this () + { + InitializeClient(client); + } + + /// + /// Thread-safe method for clearing the TreeView control + /// + public void ClearNodes() + { + if (this.InvokeRequired) this.BeginInvoke((MethodInvoker)delegate { ClearNodes(); }); + else this.Nodes.Clear(); + } + + /// + /// Thread-safe method for collapsing a TreeNode in the control + /// + /// + public void CollapseNode(TreeNode node) + { + if (this.InvokeRequired) this.BeginInvoke((MethodInvoker)delegate { CollapseNode(node); }); + else if (!node.IsExpanded) node.Collapse(); + } + + /// + /// Thread-safe method for expanding a TreeNode in the control + /// + /// + public void ExpandNode(TreeNode node) + { + if (this.InvokeRequired) this.BeginInvoke((MethodInvoker)delegate { ExpandNode(node); }); + else if (!node.IsExpanded) node.Expand(); + } + + /// + /// Thread-safe method for updating the contents of the specified folder UUID + /// + /// + public void UpdateFolder(InventoryFolder folder) + { + if (this.InvokeRequired) this.BeginInvoke((MethodInvoker)delegate { UpdateFolder(folder); }); + else + { + TreeNode node = null; + TreeNodeCollection children; + + if (folder != Client.InventoryStore.RootFolder) + { + TreeNode[] found = Nodes.Find(folder.UUID.ToString(), true); + if (found.Length > 0) + { + node = found[0]; + children = node.Nodes; + } + else + { + Logger.Log("Received update for unknown TreeView node " + folder.UUID, Helpers.LogLevel.Warning); + return; + } + } + else children = this.Nodes; + + children.Clear(); + + List contents = folder.Contents; + if (contents.Count == 0) + { + TreeNode add = children.Add(null, "(empty)"); + add.ForeColor = Color.FromKnownColor(KnownColor.GrayText); + } + else + { + foreach (InventoryBase inv in contents) + { + string key = inv.UUID.ToString(); + children.Add(key, inv.Name); + children[key].Tag = inv; + if (inv is InventoryFolder) + { + children[key].Nodes.Add(null, "Loading...").ForeColor = Color.FromKnownColor(KnownColor.GrayText); + ((InventoryFolder)inv).OnContentsRetrieved += new InventoryFolder.ContentsRetrieved(InventoryFolder_OnContentsRetrieved); + } + } + } + } + } + + private void InitializeClient(GridClient client) + { + _Client = client; + _Client.Inventory.OnSkeletonsReceived += new InventoryManager.SkeletonsReceived(Inventory_OnSkeletonsReceived); + } + + private void Inventory_OnSkeletonsReceived(InventoryManager manager) + { + _Client.InventoryStore.RootFolder.OnContentsRetrieved += new InventoryFolder.ContentsRetrieved(InventoryFolder_OnContentsRetrieved); + UpdateFolder(_Client.InventoryStore.RootFolder); + } + + private void InventoryFolder_OnContentsRetrieved(InventoryFolder folder) + { + UpdateFolder(folder); + } + + private void InventoryTree_BeforeExpand(object sender, TreeViewCancelEventArgs e) + { + InventoryFolder folder = (InventoryFolder)e.Node.Tag; + if (folder.IsStale) folder.RequestContents(); + else UpdateFolder(folder); + } + + } + +} + diff --git a/OpenMetaverse.GUI/LocalChat.cs b/OpenMetaverse.GUI/LocalChat.cs index 7aa82bb9..a2f2a2e6 100644 --- a/OpenMetaverse.GUI/LocalChat.cs +++ b/OpenMetaverse.GUI/LocalChat.cs @@ -55,8 +55,10 @@ namespace OpenMetaverse.GUI public LocalChat() { _rtfOutput.Anchor = AnchorStyles.Bottom | AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + _rtfOutput.BackColor = Color.FromKnownColor(KnownColor.Window); _rtfOutput.Width = this.Width; _rtfOutput.Height = this.Height - _txtInput.Height; + _rtfOutput.ReadOnly = true; _rtfOutput.Top = 0; _rtfOutput.Left = 0; @@ -96,6 +98,7 @@ namespace OpenMetaverse.GUI else if (type == ChatType.Whisper) volume = " whispers"; else volume = string.Empty; _rtfOutput.SelectedText = string.Format("{0}[{1}:{2}] {3}{4}: {5}", Environment.NewLine, now.Hour.ToString().PadLeft(2, '0'), now.Minute.ToString().PadLeft(2, '0'), name, volume, text); + _rtfOutput.ScrollToCaret(); } }