OSDN Git Service

Mono sucks. Let's try to guard against its suckiness.
[radegast/radegast.git] / Radegast / GUI / Consoles / GroupIMTabWindow.cs
1 // \r
2 // Radegast Metaverse Client\r
3 // Copyright (c) 2009, Radegast Development Team\r
4 // All rights reserved.\r
5 // \r
6 // Redistribution and use in source and binary forms, with or without\r
7 // modification, are permitted provided that the following conditions are met:\r
8 // \r
9 //     * Redistributions of source code must retain the above copyright notice,\r
10 //       this list of conditions and the following disclaimer.\r
11 //     * Redistributions in binary form must reproduce the above copyright\r
12 //       notice, this list of conditions and the following disclaimer in the\r
13 //       documentation and/or other materials provided with the distribution.\r
14 //     * Neither the name of the application "Radegast", nor the names of its\r
15 //       contributors may be used to endorse or promote products derived from\r
16 //       this software without specific prior written permission.\r
17 // \r
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
21 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\r
22 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r
24 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
25 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
26 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
28 //\r
29 // $Id$\r
30 //\r
31 using System;\r
32 using System.Drawing;\r
33 using System.Collections.Generic;\r
34 using System.Windows.Forms;\r
35 using System.Threading;\r
36 using Radegast.Netcom;\r
37 using OpenMetaverse;\r
38 \r
39 namespace Radegast\r
40 {\r
41     public partial class GroupIMTabWindow : UserControl\r
42     {\r
43         private RadegastInstance instance;\r
44         private GridClient client { get { return instance.Client; } }\r
45         private RadegastNetcom netcom { get { return instance.Netcom; } }\r
46         private UUID session;\r
47         private IMTextManager textManager;\r
48         private object AvatarListSyncRoot = new object();\r
49 \r
50         ManualResetEvent WaitForSessionStart = new ManualResetEvent(false);\r
51 \r
52         public GroupIMTabWindow(RadegastInstance instance, UUID session, string sessionName)\r
53         {\r
54             InitializeComponent();\r
55             Disposed += new EventHandler(IMTabWindow_Disposed);\r
56 \r
57             this.instance = instance;\r
58             this.session = session;\r
59 \r
60             textManager = new IMTextManager(this.instance, new RichTextBoxPrinter(rtbIMText), IMTextManagerType.Group, this.session, sessionName);\r
61 \r
62             btnShow.Text = "Show";\r
63             chatSplit.Panel2Collapsed = true;\r
64 \r
65             // Callbacks\r
66             RegisterClientEvents(client);\r
67             client.Self.RequestJoinGroupChat(session);\r
68 \r
69             UpdateFontSize();\r
70         }\r
71 \r
72         private void RegisterClientEvents(GridClient client)\r
73         {\r
74             client.Self.GroupChatJoined += new EventHandler<GroupChatJoinedEventArgs>(Self_GroupChatJoined);\r
75             client.Self.ChatSessionMemberAdded += new EventHandler<ChatSessionMemberAddedEventArgs>(Self_ChatSessionMemberAdded);\r
76             client.Self.ChatSessionMemberLeft += new EventHandler<ChatSessionMemberLeftEventArgs>(Self_ChatSessionMemberLeft);\r
77             client.Avatars.UUIDNameReply += new EventHandler<UUIDNameReplyEventArgs>(Avatars_UUIDNameReply);\r
78             instance.Netcom.ClientConnected += new EventHandler<EventArgs>(Netcom_Connected);\r
79             instance.Netcom.ClientDisconnected += new EventHandler<DisconnectedEventArgs>(Netcom_Disconnected);\r
80             instance.GlobalSettings.OnSettingChanged += new Settings.SettingChangedCallback(GlobalSettings_OnSettingChanged);\r
81             instance.ClientChanged += new EventHandler<ClientChangedEventArgs>(instance_ClientChanged);\r
82         }\r
83 \r
84         private void UnregisterClientEvents(GridClient client)\r
85         {\r
86             client.Self.GroupChatJoined -= new EventHandler<GroupChatJoinedEventArgs>(Self_GroupChatJoined);\r
87             client.Self.ChatSessionMemberAdded -= new EventHandler<ChatSessionMemberAddedEventArgs>(Self_ChatSessionMemberAdded);\r
88             client.Self.ChatSessionMemberLeft -= new EventHandler<ChatSessionMemberLeftEventArgs>(Self_ChatSessionMemberLeft);\r
89             client.Avatars.UUIDNameReply -= new EventHandler<UUIDNameReplyEventArgs>(Avatars_UUIDNameReply);\r
90             instance.Netcom.ClientConnected -= new EventHandler<EventArgs>(Netcom_Connected);\r
91             instance.Netcom.ClientDisconnected -= new EventHandler<DisconnectedEventArgs>(Netcom_Disconnected);\r
92             instance.GlobalSettings.OnSettingChanged -= new Settings.SettingChangedCallback(GlobalSettings_OnSettingChanged);\r
93             instance.ClientChanged -= new EventHandler<ClientChangedEventArgs>(instance_ClientChanged);\r
94         }\r
95 \r
96         void instance_ClientChanged(object sender, ClientChangedEventArgs e)\r
97         {\r
98             UnregisterClientEvents(e.OldClient);\r
99             RegisterClientEvents(client);\r
100         }\r
101 \r
102         private void IMTabWindow_Disposed(object sender, EventArgs e)\r
103         {\r
104             if (instance.Netcom.IsLoggedIn)\r
105             {\r
106                 client.Self.RequestLeaveGroupChat(session);\r
107             }\r
108 \r
109             UnregisterClientEvents(client);\r
110             CleanUp();\r
111         }\r
112 \r
113         void UpdateFontSize()\r
114         {\r
115             float size = (float)instance.GlobalSettings["chat_font_size"].AsReal();\r
116             cbxInput.Font = ChatConsole.ChangeFontSize(cbxInput.Font, size);\r
117             rtbIMText.Font = ChatConsole.ChangeFontSize(rtbIMText.Font, size);\r
118             textManager.ReprintAllText();\r
119         }\r
120 \r
121         void GlobalSettings_OnSettingChanged(object sender, SettingsEventArgs e)\r
122         {\r
123             if (e.Key == "chat_font_size")\r
124                 UpdateFontSize();\r
125         }\r
126 \r
127         void Netcom_Disconnected(object sender, DisconnectedEventArgs e)\r
128         {\r
129             RefreshControls();\r
130         }\r
131 \r
132         void Netcom_Connected(object sender, EventArgs e)\r
133         {\r
134             client.Self.RequestJoinGroupChat(session);\r
135             RefreshControls();\r
136         }\r
137 \r
138         void Avatars_UUIDNameReply(object sender, UUIDNameReplyEventArgs e)\r
139         {\r
140             if (InvokeRequired)\r
141             {\r
142                 if (IsHandleCreated)\r
143                     BeginInvoke(new MethodInvoker(() => Avatars_UUIDNameReply(sender, e)));\r
144                 return;\r
145             }\r
146 \r
147             lock (AvatarListSyncRoot)\r
148             {\r
149 \r
150                 Participants.BeginUpdate();\r
151 \r
152                 foreach (KeyValuePair<UUID, string> kvp in e.Names)\r
153                 {\r
154                     if (Participants.Items.ContainsKey(kvp.Key.ToString()))\r
155                         Participants.Items[kvp.Key.ToString()].Text = kvp.Value;\r
156                 }\r
157 \r
158                 Participants.Sort();\r
159                 Participants.EndUpdate();\r
160             }\r
161         }\r
162 \r
163         void Self_ChatSessionMemberLeft(object sender, ChatSessionMemberLeftEventArgs e)\r
164         {\r
165             if (e.SessionID == session)\r
166                 UpdateParticipantList();\r
167         }\r
168 \r
169         void Self_ChatSessionMemberAdded(object sender, ChatSessionMemberAddedEventArgs e)\r
170         {\r
171             if (e.SessionID == session)\r
172                 UpdateParticipantList();\r
173         }\r
174 \r
175         void UpdateParticipantList()\r
176         {\r
177             if (InvokeRequired)\r
178             {\r
179                 if (IsHandleCreated)\r
180                     BeginInvoke(new MethodInvoker(UpdateParticipantList));\r
181                 return;\r
182             }\r
183 \r
184             try\r
185             {\r
186                 lock (AvatarListSyncRoot)\r
187                 {\r
188                     Participants.BeginUpdate();\r
189                     Participants.Items.Clear();\r
190 \r
191                     List<ChatSessionMember> participants;\r
192                     List<UUID> nameLookup = new List<UUID>();\r
193 \r
194                     if (client.Self.GroupChatSessions.TryGetValue(session, out participants))\r
195                     {\r
196                         ChatSessionMember[] members = participants.ToArray();\r
197                         for (int i = 0; i < members.Length; i++)\r
198                         {\r
199                             ChatSessionMember participant = members[i];\r
200                             ListViewItem item = new ListViewItem();\r
201                             item.Name = participant.AvatarKey.ToString();\r
202                             if (instance.nameCache.ContainsKey(participant.AvatarKey))\r
203                             {\r
204                                 item.Text = instance.nameCache[participant.AvatarKey];\r
205                             }\r
206                             else\r
207                             {\r
208                                 item.Text = RadegastInstance.INCOMPLETE_NAME;\r
209                                 nameLookup.Add(participant.AvatarKey);\r
210                             }\r
211                             if (participant.IsModerator)\r
212                                 item.Font = new Font(item.Font, FontStyle.Bold);\r
213                             Participants.Items.Add(item);\r
214                         }\r
215 \r
216                         if (nameLookup.Count > 0)\r
217                             client.Avatars.RequestAvatarNames(nameLookup);\r
218                     }\r
219 \r
220                     Participants.Sort();\r
221                     Participants.EndUpdate();\r
222                 }\r
223             }\r
224             catch (Exception)\r
225             {\r
226                 Participants.EndUpdate();\r
227             }\r
228         }\r
229 \r
230         void Self_GroupChatJoined(object sender, GroupChatJoinedEventArgs e)\r
231         {\r
232             if (e.SessionID != session && e.TmpSessionID != session)\r
233             {\r
234                 return;\r
235             }\r
236 \r
237             if (InvokeRequired)\r
238             {\r
239                 if (IsHandleCreated)\r
240                     Invoke(new MethodInvoker(() => Self_GroupChatJoined(sender, e)));\r
241                 return;\r
242             }\r
243 \r
244             if (e.Success)\r
245             {\r
246                 textManager.TextPrinter.PrintTextLine("Join Group Chat Success!", Color.Green);\r
247                 WaitForSessionStart.Set();\r
248             }\r
249             else\r
250             {\r
251                 textManager.TextPrinter.PrintTextLine("Join Group Chat failed.", Color.Red);\r
252             }\r
253         }\r
254 \r
255         public void CleanUp()\r
256         {\r
257             textManager.CleanUp();\r
258             textManager = null;\r
259             instance = null;\r
260         }\r
261 \r
262         private void btnSend_Click(object sender, EventArgs e)\r
263         {\r
264             SendMsg();\r
265             this.ClearIMInput();\r
266         }\r
267 \r
268         private void btnShow_Click(object sender, EventArgs e)\r
269         {\r
270             if (chatSplit.Panel2Collapsed)\r
271             {\r
272                 chatSplit.Panel2Collapsed = false;\r
273                 btnShow.Text = "Hide";\r
274             }\r
275             else\r
276             {\r
277                 chatSplit.Panel2Collapsed = true;\r
278                 btnShow.Text = "Show";\r
279             }\r
280         }\r
281 \r
282         private void cbxInput_TextChanged(object sender, EventArgs e)\r
283         {\r
284             RefreshControls();\r
285         }\r
286 \r
287         private void RefreshControls()\r
288         {\r
289             if (InvokeRequired)\r
290             {\r
291                 if (IsHandleCreated)\r
292                     BeginInvoke(new MethodInvoker(RefreshControls));\r
293                 return;\r
294             }\r
295 \r
296             if (!netcom.IsLoggedIn)\r
297             {\r
298                 cbxInput.Enabled = false;\r
299                 btnSend.Enabled = false;\r
300                 btnShow.Enabled = false;\r
301                 btnShow.Text = "Show";\r
302                 chatSplit.Panel2Collapsed = true;\r
303                 return;\r
304             }\r
305 \r
306             cbxInput.Enabled = true;\r
307             btnShow.Enabled = true;\r
308 \r
309             if (cbxInput.Text.Length > 0)\r
310             {\r
311                 btnSend.Enabled = true;\r
312             }\r
313             else\r
314             {\r
315                 btnSend.Enabled = false;\r
316             }\r
317         }\r
318 \r
319         private void cbxInput_KeyUp(object sender, KeyEventArgs e)\r
320         {\r
321             if (e.KeyCode != Keys.Enter) return;\r
322             e.SuppressKeyPress = true;\r
323 \r
324             SendMsg();\r
325         }\r
326 \r
327         private void SendMsg()\r
328         {\r
329             if (cbxInput.Text.Length == 0) return;\r
330 \r
331             string message = cbxInput.Text.Replace(ChatInputBox.NewlineMarker, "\n");\r
332 \r
333             if (instance.GlobalSettings["mu_emotes"].AsBoolean() && message.StartsWith(":"))\r
334             {\r
335                 message = "/me " + message.Substring(1);\r
336             }\r
337 \r
338             this.ClearIMInput();\r
339 \r
340             if (instance.RLV.RestictionActive("sendim")) return;\r
341 \r
342             if (message.Length > 1023) message = message.Remove(1023);\r
343 \r
344             if (!client.Self.GroupChatSessions.ContainsKey(session))\r
345             {\r
346                 WaitForSessionStart.Reset();\r
347                 client.Self.RequestJoinGroupChat(session);\r
348             }\r
349             else\r
350             {\r
351                 WaitForSessionStart.Set();\r
352             }\r
353 \r
354             if (WaitForSessionStart.WaitOne(10000, false))\r
355             {\r
356                 client.Self.InstantMessageGroup(session, message);\r
357             }\r
358             else\r
359             {\r
360                 textManager.TextPrinter.PrintTextLine("Cannot send group IM.", Color.Red);\r
361             }\r
362         }\r
363 \r
364         private void ClearIMInput()\r
365         {\r
366             cbxInput.Text = string.Empty;\r
367         }\r
368 \r
369         public void SelectIMInput()\r
370         {\r
371             cbxInput.Select();\r
372         }\r
373 \r
374         private void rtbIMText_LinkClicked(object sender, LinkClickedEventArgs e)\r
375         {\r
376             instance.MainForm.ProcessLink(e.LinkText);\r
377         }\r
378 \r
379         private void cbxInput_KeyDown(object sender, KeyEventArgs e)\r
380         {\r
381             if (e.KeyCode == Keys.Enter) e.SuppressKeyPress = true;\r
382         }\r
383 \r
384         public UUID SessionId\r
385         {\r
386             get { return session; }\r
387             set { session = value; }\r
388         }\r
389 \r
390         public IMTextManager TextManager\r
391         {\r
392             get { return textManager; }\r
393             set { textManager = value; }\r
394         }\r
395 \r
396         private void Participants_MouseDoubleClick(object sender, MouseEventArgs e)\r
397         {\r
398             ListViewItem item = Participants.GetItemAt(e.X, e.Y);\r
399             if (item != null)\r
400             {\r
401                 try\r
402                 {\r
403                     instance.MainForm.ShowAgentProfile(item.Text, new UUID(item.Name));\r
404                 }\r
405                 catch (Exception) { }\r
406             }\r
407         }\r
408 \r
409         private void cbxInput_VisibleChanged(object sender, EventArgs e)\r
410         {\r
411             if (Visible) cbxInput.Focus();\r
412         }\r
413 \r
414         private void cbxInput_SizeChanged(object sender, EventArgs e)\r
415         {\r
416             pnlChatInput.Height = cbxInput.Height + 7;\r
417         }\r
418     }\r
419 }\r