corrade-vassal – Rev 1

Subversion Repositories:
Rev:
using OpenMetaverse;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace OpenMetaverse.GUI
{
    /// <summary>
    /// ToolStrip GUI component for displaying and switching between IM windows
    /// </summary>
    public class MessageBar : ToolStrip
    {
        private GridClient _Client;
        private Dictionary<UUID, MessageBarButton> _Sessions;

        /// <summary>
        /// A ToolBarButton representing an IM session, including its associated window
        /// </summary>
        class MessageBarButton : ToolStripButton
        {
            public delegate void MessageNeedsSendingCallback(UUID targetID, string message);
            public event MessageNeedsSendingCallback OnMessageNeedsSending;

            /// <summary>Target avatar name</summary>
            public string TargetName;
            /// <summary>Target avatar ID</summary>
            public UUID TargetID;
            /// <summary>IM session ID</summary>
            public UUID IMSessionID;
            /// <summary>Window for this IM session</summary>
            public MessageWindow Window;

            /// <summary>
            /// A class representing each IM session and its associated button and window objects
            /// </summary>
            public MessageBarButton(string targetName, UUID targetID, UUID imSessionID)
            {
                TargetName = targetName;
                TargetID = targetID;
                IMSessionID = imSessionID;

                this.Text = targetName;

                Window = new MessageWindow(targetName);
                Window.FormClosing += new FormClosingEventHandler(Window_FormClosing);
                Window.OnTextInput += new MessageWindow.TextInputCallback(Window_OnTextInput);
            }

            void Window_FormClosing(object sender, FormClosingEventArgs e)
            {
                this.Parent.Items.Remove(this);
                this.Dispose();
            }

            void Window_OnTextInput(string text)
            {
                if (OnMessageNeedsSending != null)
                    OnMessageNeedsSending(TargetID, text);
            }
        }

        /// <summary>
        /// A generic form for displaying text and accepting user input
        /// </summary>
        class MessageWindow : Form
        {
            private RichTextBox rtfOutput = new RichTextBox();
            private TextBox txtInput = new TextBox();

            public delegate void TextInputCallback(string text);
            public event TextInputCallback OnTextInput;

            /// <summary>
            /// A generic form for displaying text and accepting user input
            /// </summary>
            public MessageWindow(string title)
            {
                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;

                txtInput.Dock = DockStyle.Bottom;
                txtInput.KeyDown += new KeyEventHandler(txtInput_KeyDown);

                this.Text = title;
                this.Controls.AddRange(new Control[] { txtInput, rtfOutput });

                this.Resize += new EventHandler(MessageWindow_Resize);
            }

            /// <summary>
            /// Thread-safe method for adding text of a specified color to the display output
            /// </summary>
            /// <param name="text"></param>
            /// <param name="color"></param>
            public void LogText(string text, Color color)
            {
                if (this.InvokeRequired)
                {
                    this.BeginInvoke((MethodInvoker)delegate { LogText(text, color); });
                }
                else
                {
                    rtfOutput.SelectionStart = rtfOutput.Text.Length;
                    rtfOutput.SelectionColor = color;
                    DateTime now = DateTime.Now;
                    rtfOutput.SelectedText = string.Format("{0}[{1}:{2}] {3}", Environment.NewLine, now.Hour.ToString().PadLeft(2, '0'), now.Minute.ToString().PadLeft(2, '0'), text);
                    rtfOutput.ScrollToCaret();
                }
            }

            /// <summary>
            /// Thread-safe method for setting the window title
            /// </summary>
            /// <param name="title"></param>
            public void SetTitle(string title)
            {
                if (this.InvokeRequired)
                {
                    this.BeginInvoke((MethodInvoker)delegate { SetTitle(title); });
                }
                else
                {
                    this.Text = title;
                }
            }

            void MessageWindow_Resize(object sender, EventArgs e)
            {
                if (this.WindowState == FormWindowState.Minimized)
                    this.Hide();
            }

            void txtInput_KeyDown(object sender, KeyEventArgs e)
            {
                if (e.KeyCode == Keys.Enter && txtInput.Text != string.Empty)
                {
                    e.SuppressKeyPress = true;

                    if (OnTextInput != null)
                        OnTextInput(txtInput.Text);

                    txtInput.Clear();
                }
            }
        }

        /// <summary>
        /// Gets or sets the GridClient associated with this control
        /// </summary>
        public GridClient Client
        {
            get { return _Client; }
            set { if (value != null) InitializeClient(value); }
        }

        /// <summary>
        /// ToolStrip control for displaying and switching between an unspecified client's IM windows
        /// </summary>
        public MessageBar()
        {
            _Sessions = new Dictionary<UUID, MessageBarButton>();

            this.Dock = System.Windows.Forms.DockStyle.Bottom;
            this.Location = new System.Drawing.Point(0, 523);
            this.Size = new System.Drawing.Size(772, 25);
            this.TabIndex = 6;
            
            this.ItemClicked += new ToolStripItemClickedEventHandler(MessageBar_ItemClicked);
        }

        public void CreateSession(string name, UUID id, UUID imSessionID, bool open)
        {
            MessageBarButton button = new MessageBarButton(name, id, imSessionID);
            button.Disposed += new EventHandler(button_Disposed);
            button.OnMessageNeedsSending += new MessageBarButton.MessageNeedsSendingCallback(button_OnMessageNeedsSending);
            AddButton(button, open);
        }

        private void AddButton(MessageBarButton button, bool open)
        {
            if (this.InvokeRequired) this.BeginInvoke((MethodInvoker)delegate { AddButton(button, open); });
            else
            {
                _Sessions.Add(button.TargetID, button);
                this.Items.Add((ToolStripItem)button);
                if (open)
                    button.Window.Show();
            }
        }

        private void AddButton(MessageBarButton button, InstantMessage im)
        {
            if (this.InvokeRequired) this.BeginInvoke((MethodInvoker)delegate { AddButton(button, im); });
            else
            {
                AddButton(button, false);
                _Sessions[im.FromAgentID].Window.LogText(im.FromAgentName + ": " + im.Message, Color.FromKnownColor(KnownColor.ControlText));
            }            
        }

        private void InitializeClient(GridClient client)
        {
            _Client = client;
            _Client.Self.IM += Self_IM;
        }

        void Self_IM(object sender, InstantMessageEventArgs e)
        {
            if (e.IM.Dialog == InstantMessageDialog.MessageFromAgent)
            {
                lock (_Sessions)
                {
                    if (_Sessions.ContainsKey(e.IM.FromAgentID))
                    {
                        _Sessions[e.IM.FromAgentID].IMSessionID = e.IM.IMSessionID;
                        _Sessions[e.IM.FromAgentID].Window.LogText(e.IM.FromAgentName + ": " + e.IM.Message, Color.FromKnownColor(KnownColor.ControlText));
                    }
                    else
                    {
                        CreateSession(e.IM.FromAgentName, e.IM.FromAgentID, e.IM.IMSessionID, false);
                    }
                }
            }
        }

        void button_OnMessageNeedsSending(UUID targetID, string message)
        {
            lock (_Sessions)
            {
                MessageBarButton button;
                if (_Sessions.TryGetValue(targetID, out button))
                {
                    button.Window.LogText(Client.Self.Name + ": " + message, Color.FromKnownColor(KnownColor.ControlText));
                    Client.Self.InstantMessage(targetID, message, button.IMSessionID);
                }
            }
        }

        void MessageBar_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            MessageBarButton button = (MessageBarButton)e.ClickedItem;

            if (this.InvokeRequired) this.BeginInvoke((MethodInvoker)delegate { button.Window.Show(); button.Window.Activate(); button.Window.WindowState = FormWindowState.Normal; });
            else { button.Window.Show(); button.Window.Activate(); button.Window.WindowState = FormWindowState.Normal; }
        }
     
        void button_Disposed(object sender, EventArgs e)
        {
            MessageBarButton button = (MessageBarButton)sender;
            lock (_Sessions)
            {
                if (_Sessions.ContainsKey(button.TargetID))
                    _Sessions.Remove(button.TargetID);
            }
        }
    }
}