OSDN Git Service

RAD-86: Focus of cursor when opening IM tab should be text-entry line
[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.instance.ClientChanged += new EventHandler<ClientChangedEventArgs>(instance_ClientChanged);\r
59             this.session = session;\r
60 \r
61             textManager = new IMTextManager(this.instance, new RichTextBoxPrinter(rtbIMText), this.session, sessionName);\r
62 \r
63             btnShow.Text = "Show";\r
64             chatSplit.Panel2Collapsed = true;\r
65 \r
66             // Callbacks\r
67             RegisterClientEvents(client);\r
68             client.Self.RequestJoinGroupChat(session);\r
69         }\r
70 \r
71         private void RegisterClientEvents(GridClient client)\r
72         {\r
73             client.Self.GroupChatJoined += new EventHandler<GroupChatJoinedEventArgs>(Self_GroupChatJoined);\r
74             client.Self.ChatSessionMemberAdded += new EventHandler<ChatSessionMemberAddedEventArgs>(Self_ChatSessionMemberAdded);\r
75             client.Self.ChatSessionMemberLeft += new EventHandler<ChatSessionMemberLeftEventArgs>(Self_ChatSessionMemberLeft);\r
76             client.Avatars.UUIDNameReply += new EventHandler<UUIDNameReplyEventArgs>(Avatars_UUIDNameReply);\r
77             instance.Netcom.ClientConnected += new EventHandler<EventArgs>(Netcom_Connected);\r
78             instance.Netcom.ClientDisconnected += new EventHandler<DisconnectedEventArgs>(Netcom_Disconnected);\r
79         }\r
80 \r
81         private void UnregisterClientEvents(GridClient client)\r
82         {\r
83             client.Self.GroupChatJoined -= new EventHandler<GroupChatJoinedEventArgs>(Self_GroupChatJoined);\r
84             client.Self.ChatSessionMemberAdded -= new EventHandler<ChatSessionMemberAddedEventArgs>(Self_ChatSessionMemberAdded);\r
85             client.Self.ChatSessionMemberLeft -= new EventHandler<ChatSessionMemberLeftEventArgs>(Self_ChatSessionMemberLeft);\r
86             client.Avatars.UUIDNameReply -= new EventHandler<UUIDNameReplyEventArgs>(Avatars_UUIDNameReply);\r
87             instance.Netcom.ClientConnected -= new EventHandler<EventArgs>(Netcom_Connected);\r
88             instance.Netcom.ClientDisconnected -= new EventHandler<DisconnectedEventArgs>(Netcom_Disconnected);\r
89         }\r
90 \r
91         void instance_ClientChanged(object sender, ClientChangedEventArgs e)\r
92         {\r
93             UnregisterClientEvents(e.OldClient);\r
94             RegisterClientEvents(client);\r
95         }\r
96 \r
97         private void IMTabWindow_Disposed(object sender, EventArgs e)\r
98         {\r
99             if (instance.Netcom.IsLoggedIn)\r
100             {\r
101                 client.Self.RequestLeaveGroupChat(session);\r
102             }\r
103 \r
104             UnregisterClientEvents(client);\r
105             CleanUp();\r
106         }\r
107 \r
108         void Netcom_Disconnected(object sender, DisconnectedEventArgs e)\r
109         {\r
110             RefreshControls();\r
111         }\r
112 \r
113         void Netcom_Connected(object sender, EventArgs e)\r
114         {\r
115             client.Self.RequestJoinGroupChat(session);\r
116             RefreshControls();\r
117         }\r
118 \r
119         void Avatars_UUIDNameReply(object sender, UUIDNameReplyEventArgs e)\r
120         {\r
121             if (InvokeRequired)\r
122             {\r
123                 BeginInvoke(new MethodInvoker(() => Avatars_UUIDNameReply(sender, e)));\r
124                 return;\r
125             }\r
126 \r
127             lock (AvatarListSyncRoot)\r
128             {\r
129 \r
130                 Participants.BeginUpdate();\r
131 \r
132                 foreach (KeyValuePair<UUID, string> kvp in e.Names)\r
133                 {\r
134                     if (Participants.Items.ContainsKey(kvp.Key.ToString()))\r
135                         Participants.Items[kvp.Key.ToString()].Text = kvp.Value;\r
136                 }\r
137 \r
138                 Participants.Sort();\r
139                 Participants.EndUpdate();\r
140             }\r
141         }\r
142 \r
143         void Self_ChatSessionMemberLeft(object sender, ChatSessionMemberLeftEventArgs e)\r
144         {\r
145             if (e.SessionID == session)\r
146                 UpdateParticipantList();\r
147         }\r
148 \r
149         void Self_ChatSessionMemberAdded(object sender, ChatSessionMemberAddedEventArgs e)\r
150         {\r
151             if (e.SessionID == session)\r
152                 UpdateParticipantList();\r
153         }\r
154 \r
155         void UpdateParticipantList()\r
156         {\r
157             if (InvokeRequired)\r
158             {\r
159                 BeginInvoke(new MethodInvoker(UpdateParticipantList));\r
160                 return;\r
161             }\r
162 \r
163             try\r
164             {\r
165                 lock (AvatarListSyncRoot)\r
166                 {\r
167                     Participants.BeginUpdate();\r
168                     Participants.Items.Clear();\r
169 \r
170                     List<ChatSessionMember> participants;\r
171                     List<UUID> nameLookup = new List<UUID>();\r
172 \r
173                     if (client.Self.GroupChatSessions.TryGetValue(session, out participants))\r
174                     {\r
175                         ChatSessionMember[] members = participants.ToArray();\r
176                         for (int i = 0; i < members.Length; i++)\r
177                         {\r
178                             ChatSessionMember participant = members[i];\r
179                             ListViewItem item = new ListViewItem();\r
180                             item.Name = participant.AvatarKey.ToString();\r
181                             if (instance.nameCache.ContainsKey(participant.AvatarKey))\r
182                             {\r
183                                 item.Text = instance.nameCache[participant.AvatarKey];\r
184                             }\r
185                             else\r
186                             {\r
187                                 item.Text = RadegastInstance.INCOMPLETE_NAME;\r
188                                 nameLookup.Add(participant.AvatarKey);\r
189                             }\r
190                             if (participant.IsModerator)\r
191                                 item.Font = new Font(item.Font, FontStyle.Bold);\r
192                             Participants.Items.Add(item);\r
193                         }\r
194 \r
195                         if (nameLookup.Count > 0)\r
196                             client.Avatars.RequestAvatarNames(nameLookup);\r
197                     }\r
198 \r
199                     Participants.Sort();\r
200                     Participants.EndUpdate();\r
201                 }\r
202             }\r
203             catch (Exception)\r
204             {\r
205                 Participants.EndUpdate();\r
206             }\r
207         }\r
208 \r
209         void Self_GroupChatJoined(object sender, GroupChatJoinedEventArgs e)\r
210         {\r
211             if (e.SessionID != session && e.TmpSessionID != session)\r
212             {\r
213                 return;\r
214             }\r
215 \r
216             if (InvokeRequired)\r
217             {\r
218                 Invoke(new MethodInvoker(() => Self_GroupChatJoined(sender, e)));\r
219                 return;\r
220             }\r
221 \r
222             if (e.Success)\r
223             {\r
224                 textManager.TextPrinter.PrintTextLine("Join Group Chat Success!", Color.Green);\r
225                 WaitForSessionStart.Set();\r
226             }\r
227             else\r
228             {\r
229                 textManager.TextPrinter.PrintTextLine("Join Group Chat failed.", Color.Red);\r
230             }\r
231         }\r
232 \r
233         public void CleanUp()\r
234         {\r
235             textManager.CleanUp();\r
236             textManager = null;\r
237         }\r
238 \r
239         private void btnSend_Click(object sender, EventArgs e)\r
240         {\r
241             SendMsg();\r
242             this.ClearIMInput();\r
243         }\r
244 \r
245         private void btnShow_Click(object sender, EventArgs e)\r
246         {\r
247             if (chatSplit.Panel2Collapsed)\r
248             {\r
249                 chatSplit.Panel2Collapsed = false;\r
250                 btnShow.Text = "Hide";\r
251             }\r
252             else\r
253             {\r
254                 chatSplit.Panel2Collapsed = true;\r
255                 btnShow.Text = "Show";\r
256             }\r
257         }\r
258 \r
259         private void cbxInput_TextChanged(object sender, EventArgs e)\r
260         {\r
261             RefreshControls();\r
262         }\r
263 \r
264         private void RefreshControls()\r
265         {\r
266             if (InvokeRequired)\r
267             {\r
268                 BeginInvoke(new MethodInvoker(RefreshControls));\r
269                 return;\r
270             }\r
271 \r
272             if (!netcom.IsLoggedIn)\r
273             {\r
274                 cbxInput.Enabled = false;\r
275                 btnSend.Enabled = false;\r
276                 btnShow.Enabled = false;\r
277                 btnShow.Text = "Show";\r
278                 chatSplit.Panel2Collapsed = true;\r
279                 return;\r
280             }\r
281 \r
282             cbxInput.Enabled = true;\r
283             btnShow.Enabled = true;\r
284 \r
285             if (cbxInput.Text.Length > 0)\r
286             {\r
287                 btnSend.Enabled = true;\r
288             }\r
289             else\r
290             {\r
291                 btnSend.Enabled = false;\r
292             }\r
293         }\r
294 \r
295         private void cbxInput_KeyUp(object sender, KeyEventArgs e)\r
296         {\r
297             if (e.KeyCode != Keys.Enter) return;\r
298             e.SuppressKeyPress = true;\r
299 \r
300             SendMsg();\r
301         }\r
302 \r
303         private void SendMsg()\r
304         {\r
305             if (cbxInput.Text.Length == 0) return;\r
306 \r
307             string message = cbxInput.Text.Replace(ChatInputBox.NewlineMarker, "\n");\r
308 \r
309             if (message.Length > 1023) message = message.Remove(1023);\r
310 \r
311             if (!client.Self.GroupChatSessions.ContainsKey(session))\r
312             {\r
313                 WaitForSessionStart.Reset();\r
314                 client.Self.RequestJoinGroupChat(session);\r
315             }\r
316             else\r
317             {\r
318                 WaitForSessionStart.Set();\r
319             }\r
320 \r
321             if (WaitForSessionStart.WaitOne(10000, false))\r
322             {\r
323                 client.Self.InstantMessageGroup(session, message);\r
324             }\r
325             else\r
326             {\r
327                 textManager.TextPrinter.PrintTextLine("Cannot send group IM.", Color.Red);\r
328             }\r
329             this.ClearIMInput();\r
330         }\r
331 \r
332         private void ClearIMInput()\r
333         {\r
334             cbxInput.Text = string.Empty;\r
335         }\r
336 \r
337         public void SelectIMInput()\r
338         {\r
339             cbxInput.Select();\r
340         }\r
341 \r
342         private void rtbIMText_LinkClicked(object sender, LinkClickedEventArgs e)\r
343         {\r
344             instance.MainForm.ProcessLink(e.LinkText);\r
345         }\r
346 \r
347         private void cbxInput_KeyDown(object sender, KeyEventArgs e)\r
348         {\r
349             if (e.KeyCode == Keys.Enter) e.SuppressKeyPress = true;\r
350         }\r
351 \r
352         public UUID SessionId\r
353         {\r
354             get { return session; }\r
355             set { session = value; }\r
356         }\r
357 \r
358         public IMTextManager TextManager\r
359         {\r
360             get { return textManager; }\r
361             set { textManager = value; }\r
362         }\r
363 \r
364         private void Participants_MouseDoubleClick(object sender, MouseEventArgs e)\r
365         {\r
366             ListViewItem item = Participants.GetItemAt(e.X, e.Y);\r
367             if (item != null)\r
368             {\r
369                 try\r
370                 {\r
371                     instance.MainForm.ShowAgentProfile(item.Text, new UUID(item.Name));\r
372                 }\r
373                 catch (Exception) { }\r
374             }\r
375         }\r
376 \r
377         private void cbxInput_VisibleChanged(object sender, EventArgs e)\r
378         {\r
379             if (Visible) cbxInput.Focus();\r
380         }\r
381     }\r
382 }\r