OSDN Git Service

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