OSDN Git Service

Merged Mojito's sounds branch
[radegast/radegast.git] / Radegast / GUI / Consoles / GroupIMTabWindow.cs
1 // 
2 // Radegast Metaverse Client
3 // Copyright (c) 2009, Radegast Development Team
4 // All rights reserved.
5 // 
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
8 // 
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.
17 // 
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.
28 //
29 // $Id$
30 //
31 using System;
32 using System.Drawing;
33 using System.Collections.Generic;
34 using System.Windows.Forms;
35 using System.Threading;
36 using Radegast.Netcom;
37 using OpenMetaverse;
38
39 namespace Radegast
40 {
41     public partial class GroupIMTabWindow : UserControl
42     {
43         private RadegastInstance instance;
44         private GridClient client { get { return instance.Client; } }
45         private RadegastNetcom netcom { get { return instance.Netcom; } }
46         private UUID session;
47         private IMTextManager textManager;
48         private object AvatarListSyncRoot = new object();
49         private List<string> chatHistory = new List<string>();
50         private int chatPointer;
51
52         ManualResetEvent WaitForSessionStart = new ManualResetEvent(false);
53
54         public GroupIMTabWindow(RadegastInstance instance, UUID session, string sessionName)
55         {
56             InitializeComponent();
57             Disposed += new EventHandler(IMTabWindow_Disposed);
58
59             this.instance = instance;
60             this.session = session;
61
62             textManager = new IMTextManager(this.instance, new RichTextBoxPrinter(rtbIMText), IMTextManagerType.Group, this.session, sessionName);
63
64             btnShow.Text = "Show";
65             chatSplit.Panel2Collapsed = true;
66
67             // Callbacks
68             RegisterClientEvents(client);
69             if (!client.Self.GroupChatSessions.ContainsKey(session))
70             {
71                 client.Self.RequestJoinGroupChat(session);
72             }
73             UpdateFontSize();
74             Load += new EventHandler(GroupIMTabWindow_Load);
75         }
76
77         private void RegisterClientEvents(GridClient client)
78         {
79             client.Self.GroupChatJoined += new EventHandler<GroupChatJoinedEventArgs>(Self_GroupChatJoined);
80             client.Self.ChatSessionMemberAdded += new EventHandler<ChatSessionMemberAddedEventArgs>(Self_ChatSessionMemberAdded);
81             client.Self.ChatSessionMemberLeft += new EventHandler<ChatSessionMemberLeftEventArgs>(Self_ChatSessionMemberLeft);
82             client.Avatars.UUIDNameReply += new EventHandler<UUIDNameReplyEventArgs>(Avatars_UUIDNameReply);
83             instance.Netcom.ClientConnected += new EventHandler<EventArgs>(Netcom_Connected);
84             instance.Netcom.ClientDisconnected += new EventHandler<DisconnectedEventArgs>(Netcom_Disconnected);
85             instance.GlobalSettings.OnSettingChanged += new Settings.SettingChangedCallback(GlobalSettings_OnSettingChanged);
86             instance.ClientChanged += new EventHandler<ClientChangedEventArgs>(instance_ClientChanged);
87         }
88
89         private void UnregisterClientEvents(GridClient client)
90         {
91             client.Self.GroupChatJoined -= new EventHandler<GroupChatJoinedEventArgs>(Self_GroupChatJoined);
92             client.Self.ChatSessionMemberAdded -= new EventHandler<ChatSessionMemberAddedEventArgs>(Self_ChatSessionMemberAdded);
93             client.Self.ChatSessionMemberLeft -= new EventHandler<ChatSessionMemberLeftEventArgs>(Self_ChatSessionMemberLeft);
94             client.Avatars.UUIDNameReply -= new EventHandler<UUIDNameReplyEventArgs>(Avatars_UUIDNameReply);
95             instance.Netcom.ClientConnected -= new EventHandler<EventArgs>(Netcom_Connected);
96             instance.Netcom.ClientDisconnected -= new EventHandler<DisconnectedEventArgs>(Netcom_Disconnected);
97             instance.GlobalSettings.OnSettingChanged -= new Settings.SettingChangedCallback(GlobalSettings_OnSettingChanged);
98             instance.ClientChanged -= new EventHandler<ClientChangedEventArgs>(instance_ClientChanged);
99         }
100
101         void instance_ClientChanged(object sender, ClientChangedEventArgs e)
102         {
103             UnregisterClientEvents(e.OldClient);
104             RegisterClientEvents(client);
105         }
106
107         void GroupIMTabWindow_Load(object sender, EventArgs e)
108         {
109             UpdateParticipantList();
110         }
111
112         private void IMTabWindow_Disposed(object sender, EventArgs e)
113         {
114             if (instance.Netcom.IsLoggedIn)
115             {
116                 client.Self.RequestLeaveGroupChat(session);
117             }
118
119             UnregisterClientEvents(client);
120             CleanUp();
121         }
122
123         void UpdateFontSize()
124         {
125             float size = (float)instance.GlobalSettings["chat_font_size"].AsReal();
126             cbxInput.Font = ChatConsole.ChangeFontSize(cbxInput.Font, size);
127             rtbIMText.Font = ChatConsole.ChangeFontSize(rtbIMText.Font, size);
128             textManager.ReprintAllText();
129         }
130
131         void GlobalSettings_OnSettingChanged(object sender, SettingsEventArgs e)
132         {
133             if (e.Key == "chat_font_size")
134                 UpdateFontSize();
135         }
136
137         void Netcom_Disconnected(object sender, DisconnectedEventArgs e)
138         {
139             RefreshControls();
140         }
141
142         void Netcom_Connected(object sender, EventArgs e)
143         {
144             client.Self.RequestJoinGroupChat(session);
145             RefreshControls();
146         }
147
148         void Avatars_UUIDNameReply(object sender, UUIDNameReplyEventArgs e)
149         {
150             if (InvokeRequired)
151             {
152                 if (IsHandleCreated)
153                     BeginInvoke(new MethodInvoker(() => Avatars_UUIDNameReply(sender, e)));
154                 return;
155             }
156
157             lock (AvatarListSyncRoot)
158             {
159
160                 Participants.BeginUpdate();
161
162                 foreach (KeyValuePair<UUID, string> kvp in e.Names)
163                 {
164                     if (Participants.Items.ContainsKey(kvp.Key.ToString()))
165                         Participants.Items[kvp.Key.ToString()].Text = kvp.Value;
166                 }
167
168                 Participants.Sort();
169                 Participants.EndUpdate();
170             }
171         }
172
173         void Self_ChatSessionMemberLeft(object sender, ChatSessionMemberLeftEventArgs e)
174         {
175             if (e.SessionID == session)
176                 UpdateParticipantList();
177         }
178
179         void Self_ChatSessionMemberAdded(object sender, ChatSessionMemberAddedEventArgs e)
180         {
181             if (e.SessionID == session)
182                 UpdateParticipantList();
183         }
184
185         void UpdateParticipantList()
186         {
187             if (InvokeRequired)
188             {
189                 if (IsHandleCreated)
190                     BeginInvoke(new MethodInvoker(UpdateParticipantList));
191                 return;
192             }
193
194             try
195             {
196                 lock (AvatarListSyncRoot)
197                 {
198                     Participants.BeginUpdate();
199                     Participants.Items.Clear();
200
201                     List<ChatSessionMember> participants;
202                     List<UUID> nameLookup = new List<UUID>();
203
204                     if (client.Self.GroupChatSessions.TryGetValue(session, out participants))
205                     {
206                         ChatSessionMember[] members = participants.ToArray();
207                         for (int i = 0; i < members.Length; i++)
208                         {
209                             ChatSessionMember participant = members[i];
210                             ListViewItem item = new ListViewItem();
211                             item.Name = participant.AvatarKey.ToString();
212                             if (instance.nameCache.ContainsKey(participant.AvatarKey))
213                             {
214                                 item.Text = instance.nameCache[participant.AvatarKey];
215                             }
216                             else
217                             {
218                                 item.Text = RadegastInstance.INCOMPLETE_NAME;
219                                 nameLookup.Add(participant.AvatarKey);
220                             }
221                             if (participant.IsModerator)
222                                 item.Font = new Font(item.Font, FontStyle.Bold);
223                             Participants.Items.Add(item);
224                         }
225
226                         if (nameLookup.Count > 0)
227                             client.Avatars.RequestAvatarNames(nameLookup);
228                     }
229
230                     Participants.Sort();
231                     Participants.EndUpdate();
232                 }
233             }
234             catch (Exception)
235             {
236                 Participants.EndUpdate();
237             }
238         }
239
240         void Self_GroupChatJoined(object sender, GroupChatJoinedEventArgs e)
241         {
242             if (e.SessionID != session && e.TmpSessionID != session)
243             {
244                 return;
245             }
246
247             if (InvokeRequired)
248             {
249                 if (IsHandleCreated)
250                     Invoke(new MethodInvoker(() => Self_GroupChatJoined(sender, e)));
251                 return;
252             }
253
254             if (e.Success)
255             {
256                 textManager.TextPrinter.PrintTextLine("Join Group Chat Success!", Color.Green);
257                 WaitForSessionStart.Set();
258             }
259             else
260             {
261                 textManager.TextPrinter.PrintTextLine("Join Group Chat failed.", Color.Red);
262             }
263         }
264
265         public void CleanUp()
266         {
267             textManager.CleanUp();
268             textManager = null;
269             instance = null;
270         }
271
272         private void btnSend_Click(object sender, EventArgs e)
273         {
274             SendMsg();
275             this.ClearIMInput();
276         }
277
278         private void btnShow_Click(object sender, EventArgs e)
279         {
280             if (chatSplit.Panel2Collapsed)
281             {
282                 chatSplit.Panel2Collapsed = false;
283                 btnShow.Text = "Hide";
284             }
285             else
286             {
287                 chatSplit.Panel2Collapsed = true;
288                 btnShow.Text = "Show";
289             }
290         }
291
292         private void cbxInput_TextChanged(object sender, EventArgs e)
293         {
294             RefreshControls();
295         }
296
297         private void RefreshControls()
298         {
299             if (InvokeRequired)
300             {
301                 if (IsHandleCreated)
302                     BeginInvoke(new MethodInvoker(RefreshControls));
303                 return;
304             }
305
306             if (!netcom.IsLoggedIn)
307             {
308                 cbxInput.Enabled = false;
309                 btnSend.Enabled = false;
310                 btnShow.Enabled = false;
311                 btnShow.Text = "Show";
312                 chatSplit.Panel2Collapsed = true;
313                 return;
314             }
315
316             cbxInput.Enabled = true;
317             btnShow.Enabled = true;
318
319             if (cbxInput.Text.Length > 0)
320             {
321                 btnSend.Enabled = true;
322             }
323             else
324             {
325                 btnSend.Enabled = false;
326             }
327         }
328
329         void ChatHistoryPrev()
330         {
331             if (chatPointer == 0) return;
332             chatPointer--;
333             if (chatHistory.Count > chatPointer)
334             {
335                 cbxInput.Text = chatHistory[chatPointer];
336                 cbxInput.SelectionStart = cbxInput.Text.Length;
337                 cbxInput.SelectionLength = 0;
338             }
339         }
340
341         void ChatHistoryNext()
342         {
343             if (chatPointer == chatHistory.Count) return;
344             chatPointer++;
345             if (chatPointer == chatHistory.Count)
346             {
347                 cbxInput.Text = string.Empty;
348                 return;
349             }
350             cbxInput.Text = chatHistory[chatPointer];
351             cbxInput.SelectionStart = cbxInput.Text.Length;
352             cbxInput.SelectionLength = 0;
353         }
354
355
356         private void cbxInput_KeyDown(object sender, KeyEventArgs e)
357         {
358             if (e.KeyCode == Keys.Up && e.Modifiers == Keys.Control)
359             {
360                 e.Handled = e.SuppressKeyPress = true;
361                 ChatHistoryPrev();
362                 return;
363             }
364
365             if (e.KeyCode == Keys.Down && e.Modifiers == Keys.Control)
366             {
367                 e.Handled = e.SuppressKeyPress = true;
368                 ChatHistoryNext();
369                 return;
370             }
371
372             if (e.KeyCode != Keys.Enter) return;
373             e.Handled = e.SuppressKeyPress = true;
374
375             SendMsg();
376         }
377
378         private void SendMsg()
379         {
380             if (cbxInput.Text.Length == 0) return;
381
382             chatHistory.Add(cbxInput.Text);
383             chatPointer = chatHistory.Count;
384
385             string message = cbxInput.Text.Replace(ChatInputBox.NewlineMarker, "\n");
386
387             if (instance.GlobalSettings["mu_emotes"].AsBoolean() && message.StartsWith(":"))
388             {
389                 message = "/me " + message.Substring(1);
390             }
391
392             this.ClearIMInput();
393
394             if (instance.RLV.RestictionActive("sendim")) return;
395
396             if (message.Length > 1023) message = message.Remove(1023);
397
398             if (!client.Self.GroupChatSessions.ContainsKey(session))
399             {
400                 WaitForSessionStart.Reset();
401                 client.Self.RequestJoinGroupChat(session);
402             }
403             else
404             {
405                 WaitForSessionStart.Set();
406             }
407
408             if (WaitForSessionStart.WaitOne(10000, false))
409             {
410                 client.Self.InstantMessageGroup(session, message);
411             }
412             else
413             {
414                 textManager.TextPrinter.PrintTextLine("Cannot send group IM.", Color.Red);
415             }
416         }
417
418         private void ClearIMInput()
419         {
420             cbxInput.Text = string.Empty;
421         }
422
423         public void SelectIMInput()
424         {
425             cbxInput.Select();
426         }
427
428         private void rtbIMText_LinkClicked(object sender, LinkClickedEventArgs e)
429         {
430             instance.MainForm.ProcessLink(e.LinkText);
431         }
432
433         public UUID SessionId
434         {
435             get { return session; }
436             set { session = value; }
437         }
438
439         public IMTextManager TextManager
440         {
441             get { return textManager; }
442             set { textManager = value; }
443         }
444
445         private void Participants_MouseDoubleClick(object sender, MouseEventArgs e)
446         {
447             ListViewItem item = Participants.GetItemAt(e.X, e.Y);
448             if (item != null)
449             {
450                 try
451                 {
452                     instance.MainForm.ShowAgentProfile(item.Text, new UUID(item.Name));
453                 }
454                 catch (Exception) { }
455             }
456         }
457
458         private void cbxInput_VisibleChanged(object sender, EventArgs e)
459         {
460             if (Visible) cbxInput.Focus();
461         }
462
463         private void cbxInput_SizeChanged(object sender, EventArgs e)
464         {
465             pnlChatInput.Height = cbxInput.Height + 7;
466         }
467     }
468 }