OSDN Git Service

Disable avatar name links by default, causing trouble for the blind users, and other...
[radegast/radegast.git] / Radegast / Core / ChatTextManager.cs
1 // 
2 // Radegast Metaverse Client
3 // Copyright (c) 2009-2012, 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.Collections.Generic;
33 using System.Drawing;
34 using System.Text;
35 using Radegast.Netcom;
36 using OpenMetaverse;
37 using OpenMetaverse.StructuredData;
38
39 namespace Radegast
40 {
41     public class ChatTextManager : IDisposable
42     {
43         public event EventHandler<ChatLineAddedArgs> ChatLineAdded;
44
45         private RadegastInstance instance;
46         private RadegastNetcom netcom { get { return instance.Netcom; } }
47         private GridClient client { get { return instance.Client; } }
48         private ITextPrinter textPrinter;
49
50         private List<ChatBufferItem> textBuffer;
51
52         private bool showTimestamps;
53
54         public ChatTextManager(RadegastInstance instance, ITextPrinter textPrinter)
55         {
56             this.textPrinter = textPrinter;
57             this.textBuffer = new List<ChatBufferItem>();
58
59             this.instance = instance;
60             InitializeConfig();
61
62             // Callbacks
63             netcom.ChatReceived += new EventHandler<ChatEventArgs>(netcom_ChatReceived);
64             netcom.ChatSent += new EventHandler<ChatSentEventArgs>(netcom_ChatSent);
65             netcom.AlertMessageReceived += new EventHandler<AlertMessageEventArgs>(netcom_AlertMessageReceived);
66         }
67
68         public void Dispose()
69         {
70             netcom.ChatReceived -= new EventHandler<ChatEventArgs>(netcom_ChatReceived);
71             netcom.ChatSent -= new EventHandler<ChatSentEventArgs>(netcom_ChatSent);
72             netcom.AlertMessageReceived -= new EventHandler<AlertMessageEventArgs>(netcom_AlertMessageReceived);
73         }
74
75         private void InitializeConfig()
76         {
77             Settings s = instance.GlobalSettings;
78
79             if (s["chat_timestamps"].Type == OSDType.Unknown)
80                 s["chat_timestamps"] = OSD.FromBoolean(true);
81
82             showTimestamps = s["chat_timestamps"].AsBoolean();
83
84             s.OnSettingChanged += new Settings.SettingChangedCallback(s_OnSettingChanged);
85         }
86
87         void s_OnSettingChanged(object sender, SettingsEventArgs e)
88         {
89             if (e.Key == "chat_timestamps" && e.Value != null)
90             {
91                 showTimestamps = e.Value.AsBoolean();
92                 ReprintAllText();
93             }
94         }
95
96         private void netcom_ChatSent(object sender, ChatSentEventArgs e)
97         {
98             if (e.Channel == 0) return;
99
100             ProcessOutgoingChat(e);
101         }
102
103         private void netcom_AlertMessageReceived(object sender, AlertMessageEventArgs e)
104         {
105             if (e.Message.ToLower().Contains("autopilot canceled")) return; //workaround the stupid autopilot alerts
106
107             ChatBufferItem item = new ChatBufferItem(
108                 DateTime.Now, "Alert message", UUID.Zero, ": " + e.Message, ChatBufferTextStyle.Alert);
109
110             ProcessBufferItem(item, true);
111         }
112
113         private void netcom_ChatReceived(object sender, ChatEventArgs e)
114         {
115             ProcessIncomingChat(e);
116         }
117
118         public void PrintStartupMessage()
119         {
120             ChatBufferItem title = new ChatBufferItem(
121                 DateTime.Now, "", UUID.Zero, Properties.Resources.RadegastTitle + "." + RadegastBuild.CurrentRev, ChatBufferTextStyle.StartupTitle);
122
123             ChatBufferItem ready = new ChatBufferItem(
124                 DateTime.Now, "", UUID.Zero, "Ready.", ChatBufferTextStyle.StatusBlue);
125
126             ProcessBufferItem(title, true);
127             ProcessBufferItem(ready, true);
128         }
129
130         private Object SyncChat = new Object();
131
132         public void ProcessBufferItem(ChatBufferItem item, bool addToBuffer)
133         {
134             if (ChatLineAdded != null)
135             {
136                 ChatLineAdded(this, new ChatLineAddedArgs(item));
137             }
138
139             lock (SyncChat)
140             {
141                 instance.LogClientMessage("chat.txt", item.From + item.Text);
142                 if (addToBuffer) textBuffer.Add(item);
143
144                 if (showTimestamps)
145                 {
146                     textPrinter.ForeColor = SystemColors.GrayText;
147                     textPrinter.PrintText(item.Timestamp.ToString("[HH:mm] "));
148                 }
149
150                 switch (item.Style)
151                 {
152                     case ChatBufferTextStyle.Normal:
153                         textPrinter.ForeColor = SystemColors.WindowText;
154                         break;
155
156                     case ChatBufferTextStyle.StatusBlue:
157                         textPrinter.ForeColor = Color.Blue;
158                         break;
159
160                     case ChatBufferTextStyle.StatusDarkBlue:
161                         textPrinter.ForeColor = Color.DarkBlue;
162                         break;
163
164                     case ChatBufferTextStyle.LindenChat:
165                         textPrinter.ForeColor = Color.DarkGreen;
166                         break;
167
168                     case ChatBufferTextStyle.ObjectChat:
169                         textPrinter.ForeColor = Color.DarkCyan;
170                         break;
171
172                     case ChatBufferTextStyle.StartupTitle:
173                         textPrinter.ForeColor = SystemColors.WindowText;
174                         textPrinter.Font = new Font(textPrinter.Font, FontStyle.Bold);
175                         break;
176
177                     case ChatBufferTextStyle.Alert:
178                         textPrinter.ForeColor = Color.DarkRed;
179                         break;
180
181                     case ChatBufferTextStyle.Error:
182                         textPrinter.ForeColor = Color.Red;
183                         break;
184
185                     case ChatBufferTextStyle.OwnerSay:
186                         textPrinter.ForeColor = Color.FromArgb(255, 180, 150, 0);
187                         break;
188                 }
189
190                 if (item.Style == ChatBufferTextStyle.Normal && item.ID != UUID.Zero && instance.GlobalSettings["av_name_link"])
191                 {
192                     textPrinter.InsertLink(item.From, string.Format("secondlife:///app/agent/{0}/about", item.ID));
193                     textPrinter.PrintTextLine(item.Text);
194                 }
195                 else
196                 {
197                     textPrinter.PrintTextLine(item.From + item.Text);
198                 }
199             }
200         }
201
202         //Used only for non-public chat
203         private void ProcessOutgoingChat(ChatSentEventArgs e)
204         {
205             StringBuilder sb = new StringBuilder();
206
207             switch (e.Type)
208             {
209                 case ChatType.Normal:
210                     sb.Append(": ");
211                     break;
212
213                 case ChatType.Whisper:
214                     sb.Append(" whisper: ");
215                     break;
216
217                 case ChatType.Shout:
218                     sb.Append(" shout: ");
219                     break;
220             }
221
222             sb.Append(e.Message);
223
224             ChatBufferItem item = new ChatBufferItem(
225                 DateTime.Now, string.Format("(channel {0}) {1}", e.Channel, client.Self.Name), client.Self.AgentID, sb.ToString(), ChatBufferTextStyle.StatusDarkBlue);
226
227             ProcessBufferItem(item, true);
228
229             sb = null;
230         }
231
232         private void ProcessIncomingChat(ChatEventArgs e)
233         {
234             if (string.IsNullOrEmpty(e.Message)) return;
235
236             // Check if the sender agent is muted
237             if (e.SourceType == ChatSourceType.Agent &&
238                 null != client.Self.MuteList.Find(me => me.Type == MuteType.Resident && me.ID == e.SourceID)
239                 ) return;
240
241             // Check if sender object is muted
242             if (e.SourceType == ChatSourceType.Object &&
243                 null != client.Self.MuteList.Find(me =>
244                     (me.Type == MuteType.Resident && me.ID == e.OwnerID) // Owner muted
245                     || (me.Type == MuteType.Object && me.ID == e.SourceID) // Object muted by ID
246                     || (me.Type == MuteType.ByName && me.Name == e.FromName) // Object muted by name
247                 )) return;
248
249             if (instance.RLV.Enabled && e.Message.StartsWith("@"))
250             {
251                 instance.RLV.TryProcessCMD(e);
252 #if !DEBUG
253                 return;
254 #endif
255             }
256
257             ChatBufferItem item = new ChatBufferItem();
258             item.ID = e.SourceID;
259             item.RawMessage = e;
260             StringBuilder sb = new StringBuilder();
261
262             if (e.SourceType == ChatSourceType.Agent)
263             {
264                 item.From = instance.Names.Get(e.SourceID, e.FromName);
265             }
266             else
267             {
268                 item.From = e.FromName;
269             }
270
271             bool isEmote = e.Message.ToLower().StartsWith("/me ");
272
273             if (!isEmote)
274             {
275                 switch (e.Type)
276                 {
277
278                     case ChatType.Whisper:
279                         sb.Append(" whispers");
280                         break;
281
282                     case ChatType.Shout:
283                         sb.Append(" shouts");
284                         break;
285                 }
286             }
287
288             if (isEmote)
289             {
290                 if (e.SourceType == ChatSourceType.Agent && instance.RLV.RestictionActive("recvemote", e.SourceID.ToString()))
291                     sb.Append(" ...");
292                 else
293                     sb.Append(e.Message.Substring(3));
294             }
295             else
296             {
297                 sb.Append(": ");
298                 if (e.SourceType == ChatSourceType.Agent && !e.Message.StartsWith("/") && instance.RLV.RestictionActive("recvchat", e.SourceID.ToString()))
299                     sb.Append("...");
300                 else
301                     sb.Append(e.Message);
302             }
303
304             item.Timestamp = DateTime.Now;
305             item.Text = sb.ToString();
306
307             switch (e.SourceType)
308             {
309                 case ChatSourceType.Agent:
310                     item.Style =
311                         (e.FromName.EndsWith("Linden") ?
312                         ChatBufferTextStyle.LindenChat : ChatBufferTextStyle.Normal);
313                     break;
314
315                 case ChatSourceType.Object:
316                     if (e.Type == ChatType.OwnerSay)
317                     {
318                         item.Style = ChatBufferTextStyle.OwnerSay;
319                     }
320                     else
321                     {
322                         item.Style = ChatBufferTextStyle.ObjectChat;
323                     }
324                     break;
325             }
326
327             ProcessBufferItem(item, true);
328             instance.TabConsole.Tabs["chat"].Highlight();
329
330             sb = null;
331         }
332
333         public void ReprintAllText()
334         {
335             textPrinter.ClearText();
336
337             foreach (ChatBufferItem item in textBuffer)
338             {
339                 ProcessBufferItem(item, false);
340             }
341         }
342
343         public void ClearInternalBuffer()
344         {
345             textBuffer.Clear();
346         }
347
348         public ITextPrinter TextPrinter
349         {
350             get { return textPrinter; }
351             set { textPrinter = value; }
352         }
353     }
354
355     public class ChatLineAddedArgs : EventArgs
356     {
357         ChatBufferItem mItem;
358         public ChatBufferItem Item { get { return mItem; } }
359
360         public ChatLineAddedArgs(ChatBufferItem item)
361         {
362             mItem = item;
363         }
364     }
365 }