OSDN Git Service

RAD-96: Make optional: Window flash on friend online/offline
[radegast/radegast.git] / Radegast / GUI / Consoles / TabsConsole.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.Collections.Generic;\r
33 using System.ComponentModel;\r
34 using System.Drawing;\r
35 using System.Windows.Forms;\r
36 using Radegast.Netcom;\r
37 using OpenMetaverse;\r
38 \r
39 namespace Radegast\r
40 {\r
41     public partial class TabsConsole : UserControl\r
42     {\r
43         /// <summary>\r
44         /// Delegate invoked on tab operations\r
45         /// </summary>\r
46         /// <param name="sender">Event sender</param>\r
47         /// <param name="e">Event arguments</param>\r
48         public delegate void TabCallback(object sender, TabEventArgs e);\r
49 \r
50         /// <summary>\r
51         /// Fired when a tab is selected\r
52         /// </summary>\r
53         public event TabCallback OnTabSelected;\r
54 \r
55 \r
56         /// <summary>\r
57         /// Delegate invoked when chat notification is printed\r
58         /// </summary>\r
59         /// <param name="sender">Event sender</param>\r
60         /// <param name="e">Event arguments</param>\r
61         public delegate void ChatNotificationCallback(object sender, ChatNotificationEventArgs e);\r
62 \r
63         /// <summary>\r
64         /// Fired when a tab is selected\r
65         /// </summary>\r
66         public event ChatNotificationCallback OnChatNotification;\r
67 \r
68         /// <summary>\r
69         /// Fired when a new tab is added\r
70         /// </summary>\r
71         public event TabCallback OnTabAdded;\r
72 \r
73         /// <summary>\r
74         /// Fired when a tab is removed\r
75         /// </summary>\r
76         public event TabCallback OnTabRemoved;\r
77 \r
78         private RadegastInstance instance;\r
79         private GridClient client { get { return instance.Client; } }\r
80         private RadegastNetcom netcom { get { return instance.Netcom; } }\r
81         private ChatTextManager mainChatManger;\r
82 \r
83         private Dictionary<string, RadegastTab> tabs = new Dictionary<string, RadegastTab>();\r
84         public Dictionary<string, RadegastTab> Tabs { get { return tabs; } }\r
85 \r
86         private ChatConsole chatConsole;\r
87 \r
88         private RadegastTab selectedTab;\r
89 \r
90         /// <summary>\r
91         /// Currently selected tab\r
92         /// </summary>\r
93         public RadegastTab SelectedTab\r
94         {\r
95             get\r
96             {\r
97                 return selectedTab;\r
98             }\r
99         }\r
100 \r
101         private Form owner;\r
102 \r
103         public TabsConsole(RadegastInstance instance)\r
104         {\r
105             InitializeComponent();\r
106             Disposed += new EventHandler(TabsConsole_Disposed);\r
107 \r
108             this.instance = instance;\r
109             this.instance.ClientChanged += new EventHandler<ClientChangedEventArgs>(instance_ClientChanged);\r
110 \r
111             AddNetcomEvents();\r
112 \r
113             InitializeMainTab();\r
114             InitializeChatTab();\r
115 \r
116             // Callbacks\r
117             RegisterClientEvents(client);\r
118         }\r
119 \r
120         private void RegisterClientEvents(GridClient client)\r
121         {\r
122             client.Self.ScriptQuestion += new EventHandler<ScriptQuestionEventArgs>(Self_ScriptQuestion);\r
123             client.Self.ScriptDialog += new EventHandler<ScriptDialogEventArgs>(Self_ScriptDialog);\r
124         }\r
125 \r
126         private void UnregisterClientEvents(GridClient client)\r
127         {\r
128             client.Self.ScriptQuestion -= new EventHandler<ScriptQuestionEventArgs>(Self_ScriptQuestion);\r
129             client.Self.ScriptDialog -= new EventHandler<ScriptDialogEventArgs>(Self_ScriptDialog);\r
130         }\r
131 \r
132         void instance_ClientChanged(object sender, ClientChangedEventArgs e)\r
133         {\r
134             UnregisterClientEvents(e.OldClient);\r
135             RegisterClientEvents(client);\r
136         }\r
137 \r
138         void TabsConsole_Disposed(object sender, EventArgs e)\r
139         {\r
140             RemoveNetcomEvents();\r
141             UnregisterClientEvents(client);\r
142         }\r
143 \r
144         private void AddNetcomEvents()\r
145         {\r
146             netcom.ClientLoginStatus += new EventHandler<LoginProgressEventArgs>(netcom_ClientLoginStatus);\r
147             netcom.ClientLoggedOut += new EventHandler(netcom_ClientLoggedOut);\r
148             netcom.ClientDisconnected += new EventHandler<DisconnectedEventArgs>(netcom_ClientDisconnected);\r
149             netcom.ChatReceived += new EventHandler<ChatEventArgs>(netcom_ChatReceived);\r
150             netcom.ChatSent += new EventHandler<ChatSentEventArgs>(netcom_ChatSent);\r
151             netcom.AlertMessageReceived += new EventHandler<AlertMessageEventArgs>(netcom_AlertMessageReceived);\r
152             netcom.InstantMessageReceived += new EventHandler<InstantMessageEventArgs>(netcom_InstantMessageReceived);\r
153         }\r
154 \r
155         private void RemoveNetcomEvents()\r
156         {\r
157             netcom.ClientLoginStatus -= new EventHandler<LoginProgressEventArgs>(netcom_ClientLoginStatus);\r
158             netcom.ClientLoggedOut -= new EventHandler(netcom_ClientLoggedOut);\r
159             netcom.ClientDisconnected -= new EventHandler<DisconnectedEventArgs>(netcom_ClientDisconnected);\r
160             netcom.ChatReceived -= new EventHandler<ChatEventArgs>(netcom_ChatReceived);\r
161             netcom.ChatSent -= new EventHandler<ChatSentEventArgs>(netcom_ChatSent);\r
162             netcom.AlertMessageReceived -= new EventHandler<AlertMessageEventArgs>(netcom_AlertMessageReceived);\r
163             netcom.InstantMessageReceived -= new EventHandler<InstantMessageEventArgs>(netcom_InstantMessageReceived);\r
164         }\r
165 \r
166         void Self_ScriptDialog(object sender, ScriptDialogEventArgs e)\r
167         {\r
168             instance.MainForm.AddNotification(new ntfScriptDialog(instance, e.Message, e.ObjectName, e.ImageID, e.ObjectID, e.FirstName, e.LastName, e.Channel, e.ButtonLabels));\r
169         }\r
170 \r
171         void Self_ScriptQuestion(object sender, ScriptQuestionEventArgs e)\r
172         {\r
173             instance.MainForm.AddNotification(new ntfPermissions(instance, e.Simulator, e.TaskID, e.ItemID, e.ObjectName, e.ObjectOwnerName, e.Questions));\r
174         }\r
175 \r
176         private void netcom_ClientLoginStatus(object sender, LoginProgressEventArgs e)\r
177         {\r
178             if (e.Status == LoginStatus.Failed)\r
179             {\r
180                 DisplayNotificationInChat("Login error: " + e.Message, ChatBufferTextStyle.Error);\r
181             }\r
182             else if (e.Status == LoginStatus.Success)\r
183             {\r
184                 DisplayNotificationInChat("Logged in as " + netcom.LoginOptions.FullName + ".", ChatBufferTextStyle.StatusDarkBlue);\r
185                 DisplayNotificationInChat("Login reply: " + e.Message, ChatBufferTextStyle.StatusDarkBlue);\r
186 \r
187                 InitializeOnlineTabs();\r
188 \r
189                 if (tabs.ContainsKey("login"))\r
190                 {\r
191                     if (selectedTab.Name == "login")\r
192                         SelectDefaultTab();\r
193                     ForceCloseTab("login");\r
194                 }\r
195 \r
196                 client.Self.RetrieveInstantMessages();\r
197             }\r
198         }\r
199 \r
200         private void netcom_ClientLoggedOut(object sender, EventArgs e)\r
201         {\r
202             DisposeOnlineTabs();\r
203 \r
204             SelectDefaultTab();\r
205             DisplayNotificationInChat("Logged out.");\r
206 \r
207         }\r
208 \r
209         private void netcom_ClientDisconnected(object sender, DisconnectedEventArgs e)\r
210         {\r
211             if (e.Reason == NetworkManager.DisconnectType.ClientInitiated) return;\r
212 \r
213             DisposeOnlineTabs();\r
214             SelectDefaultTab();\r
215             DisplayNotificationInChat("Disconnected: " + e.Message, ChatBufferTextStyle.Error);\r
216         }\r
217 \r
218         private void netcom_AlertMessageReceived(object sender, AlertMessageEventArgs e)\r
219         {\r
220             tabs["chat"].Highlight();\r
221         }\r
222 \r
223         private void netcom_ChatSent(object sender, ChatSentEventArgs e)\r
224         {\r
225             tabs["chat"].Highlight();\r
226         }\r
227 \r
228         private void netcom_ChatReceived(object sender, ChatEventArgs e)\r
229         {\r
230             if (string.IsNullOrEmpty(e.Message)) return;\r
231 \r
232             tabs["chat"].Highlight();\r
233         }\r
234 \r
235         private void netcom_InstantMessageReceived(object sender, InstantMessageEventArgs e)\r
236         {\r
237             switch (e.IM.Dialog)\r
238             {\r
239                 case InstantMessageDialog.SessionSend:\r
240                     if (instance.Groups.ContainsKey(e.IM.IMSessionID))\r
241                     {\r
242                         HandleGroupIM(e);\r
243                     }\r
244                     else\r
245                     {\r
246                         HandleConferenceIM(e);\r
247                     }\r
248                     break;\r
249 \r
250                 case InstantMessageDialog.MessageFromAgent:\r
251                     if (e.IM.FromAgentName == "Second Life")\r
252                     {\r
253                         HandleIMFromObject(e);\r
254                     }\r
255                     else if (e.IM.GroupIM || instance.Groups.ContainsKey(e.IM.IMSessionID))\r
256                     {\r
257                         HandleGroupIM(e);\r
258                     }\r
259                     else if (e.IM.BinaryBucket.Length > 1)\r
260                     { // conference\r
261                         HandleConferenceIM(e);\r
262                     }\r
263                     else\r
264                     {\r
265                         HandleIM(e);\r
266                     }\r
267                     break;\r
268 \r
269                 case InstantMessageDialog.MessageFromObject:\r
270                     HandleIMFromObject(e);\r
271                     break;\r
272 \r
273                 case InstantMessageDialog.StartTyping:\r
274                     if (TabExists(e.IM.FromAgentName))\r
275                     {\r
276                         RadegastTab tab = tabs[e.IM.FromAgentName.ToLower()];\r
277                         if (!tab.Highlighted) tab.PartialHighlight();\r
278                     }\r
279 \r
280                     break;\r
281 \r
282                 case InstantMessageDialog.StopTyping:\r
283                     if (TabExists(e.IM.FromAgentName))\r
284                     {\r
285                         RadegastTab tab = tabs[e.IM.FromAgentName.ToLower()];\r
286                         if (!tab.Highlighted) tab.Unhighlight();\r
287                     }\r
288 \r
289                     break;\r
290 \r
291                 case InstantMessageDialog.MessageBox:\r
292                     instance.MainForm.AddNotification(new ntfGeneric(instance, e.IM.Message));\r
293                     break;\r
294 \r
295                 case InstantMessageDialog.RequestTeleport:\r
296                     if (instance.RLV.AutoAcceptTP(e.IM.FromAgentID))\r
297                     {\r
298                         DisplayNotificationInChat("Auto accepting teleprot from " + e.IM.FromAgentName);\r
299                         instance.Client.Self.TeleportLureRespond(e.IM.FromAgentID, true);\r
300                     }\r
301                     else\r
302                     {\r
303                         instance.MainForm.AddNotification(new ntfTeleport(instance, e.IM));\r
304                     }\r
305                     break;\r
306 \r
307                 case InstantMessageDialog.GroupInvitation:\r
308                     instance.MainForm.AddNotification(new ntfGroupInvitation(instance, e.IM));\r
309                     break;\r
310 \r
311                 case InstantMessageDialog.FriendshipOffered:\r
312                     instance.MainForm.AddNotification(new ntfFriendshipOffer(instance, e.IM));\r
313                     break;\r
314 \r
315                 case InstantMessageDialog.InventoryAccepted:\r
316                     DisplayNotificationInChat(e.IM.FromAgentName + " accepted your inventory offer.");\r
317                     break;\r
318 \r
319                 case InstantMessageDialog.InventoryDeclined:\r
320                     DisplayNotificationInChat(e.IM.FromAgentName + " declined your inventory offer.");\r
321                     break;\r
322 \r
323                 case InstantMessageDialog.GroupNotice:\r
324                     instance.MainForm.AddNotification(new ntfGroupNotice(instance, e.IM));\r
325                     break;\r
326 \r
327                 case InstantMessageDialog.InventoryOffered:\r
328                 case InstantMessageDialog.TaskInventoryOffered:\r
329                     instance.MainForm.AddNotification(new ntfInventoryOffer(instance, e.IM));\r
330                     break;\r
331             }\r
332         }\r
333 \r
334         /// <summary>\r
335         /// Make default tab (chat) active\r
336         /// </summary>\r
337         public void SelectDefaultTab()\r
338         {\r
339             if (TabExists("chat"))\r
340                 tabs["chat"].Select();\r
341         }\r
342 \r
343         /// <summary>\r
344         /// Displays notification in the main chat tab\r
345         /// </summary>\r
346         /// <param name="msg">Message to be printed in the chat tab</param>\r
347         public void DisplayNotificationInChat(string msg)\r
348         {\r
349             DisplayNotificationInChat(msg, ChatBufferTextStyle.ObjectChat);\r
350         }\r
351 \r
352         /// <summary>\r
353         /// Displays notification in the main chat tab\r
354         /// </summary>\r
355         /// <param name="msg">Message to be printed in the chat tab</param>\r
356         /// <param name="style">Style of the message to be printed, normal, object, etc.</param>\r
357         public void DisplayNotificationInChat(string msg, ChatBufferTextStyle style)\r
358         {\r
359             DisplayNotificationInChat(msg, style, true);\r
360         }\r
361 \r
362         /// <summary>\r
363         /// Displays notification in the main chat tab\r
364         /// </summary>\r
365         /// <param name="msg">Message to be printed in the chat tab</param>\r
366         /// <param name="style">Style of the message to be printed, normal, object, etc.</param>\r
367         /// <param name="highlightChatTab">Highligt (and flash in taskbar) chat tab if not selected</param>\r
368         public void DisplayNotificationInChat(string msg, ChatBufferTextStyle style, bool highlightChatTab)\r
369         {\r
370             if (InvokeRequired)\r
371             {\r
372                 BeginInvoke(new MethodInvoker(() => DisplayNotificationInChat(msg, style, highlightChatTab)));\r
373                 return;\r
374             }\r
375 \r
376             if (style != ChatBufferTextStyle.Invisible)\r
377             {\r
378                 ChatBufferItem line = new ChatBufferItem(\r
379                     DateTime.Now,\r
380                     msg,\r
381                     style\r
382                 );\r
383 \r
384                 try\r
385                 {\r
386                     mainChatManger.ProcessBufferItem(line, true);\r
387                     if (highlightChatTab)\r
388                     {\r
389                         tabs["chat"].Highlight();\r
390                     }\r
391                 }\r
392                 catch (Exception) { }\r
393             }\r
394 \r
395             if (OnChatNotification != null)\r
396             {\r
397                 try { OnChatNotification(this, new ChatNotificationEventArgs(msg, style)); }\r
398                 catch { }\r
399             }\r
400         }\r
401 \r
402         private void HandleIMFromObject(InstantMessageEventArgs e)\r
403         {\r
404             DisplayNotificationInChat(e.IM.FromAgentName + ": " + e.IM.Message);\r
405         }\r
406 \r
407         private void HandleIM(InstantMessageEventArgs e)\r
408         {\r
409             if (TabExists(e.IM.IMSessionID.ToString()))\r
410             {\r
411                 RadegastTab tab = tabs[e.IM.IMSessionID.ToString()];\r
412                 if (!tab.Selected) tab.Highlight();\r
413                 return;\r
414             }\r
415 \r
416             IMTabWindow imTab = AddIMTab(e);\r
417             tabs[e.IM.IMSessionID.ToString()].Highlight();\r
418         }\r
419 \r
420         private void HandleConferenceIM(InstantMessageEventArgs e)\r
421         {\r
422             if (TabExists(e.IM.IMSessionID.ToString()))\r
423             {\r
424                 RadegastTab tab = tabs[e.IM.IMSessionID.ToString()];\r
425                 if (!tab.Selected) tab.Highlight();\r
426                 return;\r
427             }\r
428 \r
429             ConferenceIMTabWindow imTab = AddConferenceIMTab(e);\r
430             tabs[e.IM.IMSessionID.ToString()].Highlight();\r
431         }\r
432 \r
433         private void HandleGroupIM(InstantMessageEventArgs e)\r
434         {\r
435             if (TabExists(e.IM.IMSessionID.ToString()))\r
436             {\r
437                 RadegastTab tab = tabs[e.IM.IMSessionID.ToString()];\r
438                 if (!tab.Selected) tab.Highlight();\r
439                 return;\r
440             }\r
441 \r
442             GroupIMTabWindow imTab = AddGroupIMTab(e);\r
443             tabs[e.IM.IMSessionID.ToString()].Highlight();\r
444         }\r
445 \r
446         private void InitializeMainTab()\r
447         {\r
448             LoginConsole loginConsole = new LoginConsole(instance);\r
449 \r
450             RadegastTab tab = AddTab("login", "Login", loginConsole);\r
451             tab.AllowClose = false;\r
452             tab.AllowDetach = false;\r
453             tab.AllowMerge = false;\r
454             tab.AllowHide = false;\r
455 \r
456             loginConsole.RegisterTab(tab);\r
457         }\r
458 \r
459         private void InitializeChatTab()\r
460         {\r
461             chatConsole = new ChatConsole(instance);\r
462             mainChatManger = chatConsole.ChatManager;\r
463 \r
464             RadegastTab tab = AddTab("chat", "Chat", chatConsole);\r
465             tab.AllowClose = false;\r
466             tab.AllowDetach = false;\r
467             tab.AllowHide = false;\r
468         }\r
469 \r
470 \r
471         /// <summary>\r
472         /// Create Tabs that only make sense when connected\r
473         /// </summary>\r
474         private void InitializeOnlineTabs()\r
475         {\r
476             RadegastTab tab = AddTab("friends", "Friends", new FriendsConsole(instance));\r
477             tab.AllowClose = false;\r
478             tab.AllowDetach = true;\r
479             tab.Visible = false;\r
480 \r
481             tab = AddTab("groups", "Groups", new GroupsConsole(instance));\r
482             tab.AllowClose = false;\r
483             tab.AllowDetach = true;\r
484             tab.Visible = false;\r
485 \r
486             tab = AddTab("inventory", "Inventory", new InventoryConsole(instance));\r
487             tab.AllowClose = false;\r
488             tab.AllowDetach = true;\r
489             tab.Visible = false;\r
490 \r
491             tab = AddTab("search", "Search", new SearchConsole(instance));\r
492             tab.AllowClose = false;\r
493             tab.AllowDetach = true;\r
494             tab.Visible = false;\r
495 \r
496             if (!TabExists("map"))\r
497             {\r
498                 tab = AddTab("map", "Map", new MapConsole(instance));\r
499                 tab.AllowClose = false;\r
500                 tab.AllowDetach = true;\r
501                 tab.Visible = false;\r
502             }\r
503 \r
504             tab = AddTab("voice", "Voice", new VoiceConsole(instance));\r
505             tab.AllowClose = false;\r
506             tab.AllowDetach = true;\r
507             tab.Visible = false;\r
508         }\r
509 \r
510         /// <summary>\r
511         /// Close tabs that make no sense when not connected\r
512         /// </summary>\r
513         private void DisposeOnlineTabs()\r
514         {\r
515             lock (tabs)\r
516             {\r
517                 ForceCloseTab("voice");\r
518 \r
519                 // Mono crashes if we try to open map for the second time\r
520                 if (!instance.MonoRuntime)\r
521                     ForceCloseTab("map");\r
522                 else if (TabExists("map"))\r
523                     tabs["map"].Hide();\r
524 \r
525                 ForceCloseTab("search");\r
526                 ForceCloseTab("inventory");\r
527                 ForceCloseTab("groups");\r
528                 ForceCloseTab("friends");\r
529             }\r
530         }\r
531 \r
532         private void ForceCloseTab(string name)\r
533         {\r
534             if (!TabExists(name)) return;\r
535 \r
536             RadegastTab tab = tabs[name];\r
537             if (tab.Merged) SplitTab(tab);\r
538 \r
539             tab.AllowClose = true;\r
540             tab.Close();\r
541             tab = null;\r
542         }\r
543 \r
544 \r
545         public void RegisterContextAction(Type libomvType, String label, EventHandler handler)\r
546         {\r
547             instance.ContextActionManager.RegisterContextAction(libomvType, label, handler);\r
548         }\r
549 \r
550         public void RegisterContextAction(ContextAction handler)\r
551         {\r
552             instance.ContextActionManager.RegisterContextAction(handler);\r
553         }\r
554 \r
555         public void AddTab(RadegastTab tab)\r
556         {\r
557             ToolStripButton button = (ToolStripButton)tstTabs.Items.Add(tab.Label);\r
558             button.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText;\r
559             button.Image = null;\r
560             button.AutoToolTip = false;\r
561             button.Tag = tab.Name;\r
562             button.Click += new EventHandler(TabButtonClick);\r
563             tab.Button = button;\r
564             tabs.Add(tab.Name, tab);\r
565 \r
566             if (OnTabAdded != null)\r
567             {\r
568                 try { OnTabAdded(this, new TabEventArgs(tab)); }\r
569                 catch (Exception) { }\r
570             }\r
571         }\r
572 \r
573         public RadegastTab AddTab(string name, string label, Control control)\r
574         {\r
575             // WORKAROUND: one should never add tab that alrady exists\r
576             // but under some weird conditions disconnect/connect\r
577             // fire in the wrong order\r
578             if (TabExists(name))\r
579             {\r
580                 Logger.Log("Force closing tab '" + name + "'", Helpers.LogLevel.Warning, client);\r
581                 ForceCloseTab(name);\r
582             }\r
583 \r
584             control.Visible = false;\r
585             control.Dock = DockStyle.Fill;\r
586             toolStripContainer1.ContentPanel.Controls.Add(control);\r
587 \r
588             ToolStripButton button = (ToolStripButton)tstTabs.Items.Add(label);\r
589             button.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText;\r
590             button.Image = null;\r
591             button.AutoToolTip = false;\r
592             button.Tag = name.ToLower();\r
593             button.Click += new EventHandler(TabButtonClick);\r
594 \r
595             RadegastTab tab = new RadegastTab(instance, button, control, name.ToLower(), label);\r
596             tab.TabAttached += new EventHandler(tab_TabAttached);\r
597             tab.TabDetached += new EventHandler(tab_TabDetached);\r
598             tab.TabSelected += new EventHandler(tab_TabSelected);\r
599             tab.TabClosed += new EventHandler(tab_TabClosed);\r
600             tab.TabHidden += new EventHandler(tab_TabHidden);\r
601             tabs.Add(name.ToLower(), tab);\r
602 \r
603             if (OnTabAdded != null)\r
604             {\r
605                 try { OnTabAdded(this, new TabEventArgs(tab)); }\r
606                 catch (Exception) { }\r
607             }\r
608 \r
609             return tab;\r
610         }\r
611 \r
612         private void tab_TabAttached(object sender, EventArgs e)\r
613         {\r
614             RadegastTab tab = (RadegastTab)sender;\r
615             tab.Select();\r
616         }\r
617 \r
618         private void tab_TabDetached(object sender, EventArgs e)\r
619         {\r
620             RadegastTab tab = (RadegastTab)sender;\r
621             frmDetachedTab form = (frmDetachedTab)tab.Owner;\r
622 \r
623             form.ReattachStrip = tstTabs;\r
624             form.ReattachContainer = toolStripContainer1.ContentPanel;\r
625         }\r
626 \r
627         private void tab_TabSelected(object sender, EventArgs e)\r
628         {\r
629             RadegastTab tab = (RadegastTab)sender;\r
630 \r
631             if (selectedTab != null &&\r
632                 selectedTab != tab)\r
633             { selectedTab.Deselect(); }\r
634 \r
635             selectedTab = tab;\r
636 \r
637             tbtnCloseTab.Enabled = tab.AllowClose || tab.AllowHide;\r
638             owner.AcceptButton = tab.DefaultControlButton;\r
639 \r
640             if (OnTabSelected != null)\r
641             {\r
642                 try { OnTabSelected(this, new TabEventArgs(selectedTab)); }\r
643                 catch (Exception) { }\r
644             }\r
645         }\r
646 \r
647         void tab_TabHidden(object sender, EventArgs e)\r
648         {\r
649             RadegastTab tab = (RadegastTab)sender;\r
650 \r
651             if (selectedTab != null && selectedTab == tab)\r
652             {\r
653                 tab.Deselect();\r
654                 SelectDefaultTab();\r
655             }\r
656         }\r
657 \r
658         private void tab_TabClosed(object sender, EventArgs e)\r
659         {\r
660             RadegastTab tab = (RadegastTab)sender;\r
661 \r
662             if (selectedTab != null && selectedTab == tab && tab.Name != "chat")\r
663             {\r
664                 tab.Deselect();\r
665                 SelectDefaultTab();\r
666             }\r
667 \r
668             tabs.Remove(tab.Name);\r
669 \r
670             if (OnTabRemoved != null)\r
671             {\r
672                 try { OnTabRemoved(this, new TabEventArgs(tab)); }\r
673                 catch (Exception) { }\r
674             }\r
675 \r
676             tab = null;\r
677         }\r
678 \r
679         private void TabButtonClick(object sender, EventArgs e)\r
680         {\r
681             ToolStripButton button = (ToolStripButton)sender;\r
682 \r
683             RadegastTab tab = tabs[button.Tag.ToString()];\r
684             tab.Select();\r
685         }\r
686 \r
687         public void RemoveTabEntry(RadegastTab tab)\r
688         {\r
689             if (tstTabs.Items.Contains(tab.Button))\r
690             {\r
691                 tstTabs.Items.Remove(tab.Button);\r
692             }\r
693 \r
694             tab.Button.Dispose();\r
695             tabs.Remove(tab.Name);\r
696         }\r
697 \r
698         public void RemoveTab(string name)\r
699         {\r
700             if (tabs.ContainsKey(name))\r
701             {\r
702                 tabs.Remove(name);\r
703             }\r
704         }\r
705 \r
706         //Used for outside classes that have a reference to TabsConsole\r
707         public void SelectTab(string name)\r
708         {\r
709             tabs[name.ToLower()].Select();\r
710         }\r
711 \r
712         public bool TabExists(string name)\r
713         {\r
714             return tabs.ContainsKey(name.ToLower());\r
715         }\r
716 \r
717         public RadegastTab GetTab(string name)\r
718         {\r
719             return tabs[name.ToLower()];\r
720         }\r
721 \r
722         public List<RadegastTab> GetOtherTabs()\r
723         {\r
724             List<RadegastTab> otherTabs = new List<RadegastTab>();\r
725 \r
726             foreach (ToolStripItem item in tstTabs.Items)\r
727             {\r
728                 if (item.Tag == null) continue;\r
729                 if ((ToolStripItem)item == selectedTab.Button) continue;\r
730 \r
731                 RadegastTab tab = tabs[item.Tag.ToString()];\r
732                 if (!tab.AllowMerge) continue;\r
733                 if (tab.Merged) continue;\r
734 \r
735                 otherTabs.Add(tab);\r
736             }\r
737 \r
738             return otherTabs;\r
739         }\r
740 \r
741         /// <summary>\r
742         /// Activates the next tab\r
743         /// </summary>\r
744         public void SelectNextTab()\r
745         {\r
746             List<ToolStripItem> buttons = new List<ToolStripItem>();\r
747 \r
748             foreach (ToolStripItem item in tstTabs.Items)\r
749             {\r
750                 if (item.Tag == null || !item.Visible) continue;\r
751 \r
752                 buttons.Add(item);\r
753             }\r
754 \r
755             int current = 0;\r
756 \r
757             for (int i = 0; i < buttons.Count; i++)\r
758             {\r
759                 if (buttons[i] == selectedTab.Button)\r
760                 {\r
761                     current = i;\r
762                     break;\r
763                 }\r
764             }\r
765 \r
766             current++;\r
767 \r
768             if (current == buttons.Count)\r
769                 current = 0;\r
770 \r
771             SelectTab(tabs[buttons[current].Tag.ToString()].Name);\r
772         }\r
773 \r
774         /// <summary>\r
775         /// Activates the previous tab\r
776         /// </summary>\r
777         public void SelectPreviousTab()\r
778         {\r
779             List<ToolStripItem> buttons = new List<ToolStripItem>();\r
780 \r
781             foreach (ToolStripItem item in tstTabs.Items)\r
782             {\r
783                 if (item.Tag == null || !item.Visible) continue;\r
784 \r
785                 buttons.Add(item);\r
786             }\r
787 \r
788             int current = 0;\r
789 \r
790             for (int i = 0; i < buttons.Count; i++)\r
791             {\r
792                 if (buttons[i] == selectedTab.Button)\r
793                 {\r
794                     current = i;\r
795                     break;\r
796                 }\r
797             }\r
798 \r
799             current--;\r
800 \r
801             if (current == -1)\r
802                 current = buttons.Count - 1;\r
803 \r
804             SelectTab(tabs[buttons[current].Tag.ToString()].Name);\r
805         }\r
806 \r
807 \r
808         public IMTabWindow AddIMTab(UUID target, UUID session, string targetName)\r
809         {\r
810             IMTabWindow imTab = new IMTabWindow(instance, target, session, targetName);\r
811 \r
812             RadegastTab tab = AddTab(session.ToString(), "IM: " + targetName, imTab);\r
813             imTab.SelectIMInput();\r
814             tab.Highlight();\r
815 \r
816             return imTab;\r
817         }\r
818 \r
819         public ConferenceIMTabWindow AddConferenceIMTab(UUID session, string name)\r
820         {\r
821             ConferenceIMTabWindow imTab = new ConferenceIMTabWindow(instance, session, name);\r
822 \r
823             RadegastTab tab = AddTab(session.ToString(), name, imTab);\r
824             imTab.SelectIMInput();\r
825 \r
826             return imTab;\r
827         }\r
828 \r
829 \r
830         public ConferenceIMTabWindow AddConferenceIMTab(InstantMessageEventArgs e)\r
831         {\r
832             ConferenceIMTabWindow imTab = AddConferenceIMTab(e.IM.IMSessionID, Utils.BytesToString(e.IM.BinaryBucket));\r
833             imTab.TextManager.ProcessIM(e);\r
834             return imTab;\r
835         }\r
836 \r
837         public GroupIMTabWindow AddGroupIMTab(UUID session, string name)\r
838         {\r
839             GroupIMTabWindow imTab = new GroupIMTabWindow(instance, session, name);\r
840 \r
841             RadegastTab tab = AddTab(session.ToString(), name, imTab);\r
842             imTab.SelectIMInput();\r
843 \r
844             return imTab;\r
845         }\r
846 \r
847         public GroupIMTabWindow AddGroupIMTab(InstantMessageEventArgs e)\r
848         {\r
849             GroupIMTabWindow imTab = AddGroupIMTab(e.IM.IMSessionID, Utils.BytesToString(e.IM.BinaryBucket));\r
850             imTab.TextManager.ProcessIM(e);\r
851             return imTab;\r
852         }\r
853 \r
854         public IMTabWindow AddIMTab(InstantMessageEventArgs e)\r
855         {\r
856             IMTabWindow imTab = AddIMTab(e.IM.FromAgentID, e.IM.IMSessionID, e.IM.FromAgentName);\r
857             imTab.TextManager.ProcessIM(e);\r
858             return imTab;\r
859         }\r
860 \r
861         public OutfitTextures AddOTTab(Avatar avatar)\r
862         {\r
863             OutfitTextures otTab = new OutfitTextures(instance, avatar);\r
864 \r
865             RadegastTab tab = AddTab("OT: " + avatar.Name, "OT: " + avatar.Name, otTab);\r
866             otTab.GetTextures();\r
867             return otTab;\r
868         }\r
869 \r
870         public MasterTab AddMSTab(Avatar avatar)\r
871         {\r
872             MasterTab msTab = new MasterTab(instance, avatar);\r
873 \r
874             RadegastTab tab = AddTab("MS: " + avatar.Name, "MS: " + avatar.Name, msTab);\r
875             return msTab;\r
876         }\r
877 \r
878         public AttachmentTab AddATTab(Avatar avatar)\r
879         {\r
880             AttachmentTab atTab = new AttachmentTab(instance, avatar);\r
881 \r
882             RadegastTab tab = AddTab("AT: " + avatar.Name, "AT: " + avatar.Name, atTab);\r
883             return atTab;\r
884         }\r
885 \r
886         public AnimTab AddAnimTab(Avatar avatar)\r
887         {\r
888             AnimTab animTab = new AnimTab(instance, avatar);\r
889 \r
890             RadegastTab tab = AddTab("Anim: " + avatar.Name, "Anim: " + avatar.Name, animTab);\r
891             return animTab;\r
892         }\r
893 \r
894         private void tbtnTabOptions_Click(object sender, EventArgs e)\r
895         {\r
896             tmnuMergeWith.Enabled = selectedTab.AllowMerge;\r
897             tmnuDetachTab.Enabled = selectedTab.AllowDetach;\r
898 \r
899             tmnuMergeWith.DropDown.Items.Clear();\r
900 \r
901             if (!selectedTab.AllowMerge) return;\r
902             if (!selectedTab.Merged)\r
903             {\r
904                 tmnuMergeWith.Text = "Merge With";\r
905 \r
906                 List<RadegastTab> otherTabs = GetOtherTabs();\r
907 \r
908                 tmnuMergeWith.Enabled = (otherTabs.Count > 0);\r
909                 if (!tmnuMergeWith.Enabled) return;\r
910 \r
911                 foreach (RadegastTab tab in otherTabs)\r
912                 {\r
913                     ToolStripItem item = tmnuMergeWith.DropDown.Items.Add(tab.Label);\r
914                     item.Tag = tab.Name;\r
915                     item.Click += new EventHandler(MergeItemClick);\r
916                 }\r
917             }\r
918             else\r
919             {\r
920                 tmnuMergeWith.Text = "Split";\r
921                 tmnuMergeWith.Click += new EventHandler(SplitClick);\r
922             }\r
923         }\r
924 \r
925         private void MergeItemClick(object sender, EventArgs e)\r
926         {\r
927             ToolStripItem item = (ToolStripItem)sender;\r
928             RadegastTab tab = tabs[item.Tag.ToString()];\r
929 \r
930             selectedTab.MergeWith(tab);\r
931 \r
932             SplitContainer container = (SplitContainer)selectedTab.Control;\r
933             toolStripContainer1.ContentPanel.Controls.Add(container);\r
934 \r
935             selectedTab.Select();\r
936             RemoveTabEntry(tab);\r
937 \r
938             tabs.Add(tab.Name, selectedTab);\r
939         }\r
940 \r
941         private void SplitClick(object sender, EventArgs e)\r
942         {\r
943             SplitTab(selectedTab);\r
944             selectedTab.Select();\r
945         }\r
946 \r
947         public void SplitTab(RadegastTab tab)\r
948         {\r
949             RadegastTab otherTab = tab.Split();\r
950             if (otherTab == null) return;\r
951 \r
952             toolStripContainer1.ContentPanel.Controls.Add(tab.Control);\r
953             toolStripContainer1.ContentPanel.Controls.Add(otherTab.Control);\r
954 \r
955             tabs.Remove(otherTab.Name);\r
956             AddTab(otherTab);\r
957         }\r
958 \r
959         private void tmnuDetachTab_Click(object sender, EventArgs e)\r
960         {\r
961             if (!selectedTab.AllowDetach) return;\r
962             RadegastTab tab = selectedTab;\r
963             SelectDefaultTab();\r
964             tab.Detach(instance);\r
965         }\r
966 \r
967         private void tbtnCloseTab_Click(object sender, EventArgs e)\r
968         {\r
969             RadegastTab tab = selectedTab;\r
970             if (tab.AllowClose)\r
971                 tab.Close();\r
972             else if (tab.AllowHide)\r
973                 tab.Hide();\r
974         }\r
975 \r
976         private void TabsConsole_Load(object sender, EventArgs e)\r
977         {\r
978             owner = this.FindForm();\r
979         }\r
980 \r
981         private void ctxTabs_Opening(object sender, CancelEventArgs e)\r
982         {\r
983             Point pt = this.PointToClient(Cursor.Position);\r
984             ToolStripItem stripItem = tstTabs.GetItemAt(pt);\r
985 \r
986             if (stripItem == null)\r
987             {\r
988                 e.Cancel = true;\r
989             }\r
990             else\r
991             {\r
992                 tabs[stripItem.Tag.ToString()].Select();\r
993 \r
994                 ctxBtnClose.Enabled = selectedTab.AllowClose || selectedTab.AllowHide;\r
995                 ctxBtnDetach.Enabled = selectedTab.AllowDetach;\r
996                 ctxBtnMerge.Enabled = selectedTab.AllowMerge;\r
997                 ctxBtnMerge.DropDown.Items.Clear();\r
998 \r
999                 if (!ctxBtnClose.Enabled && !ctxBtnDetach.Enabled && !ctxBtnMerge.Enabled)\r
1000                 {\r
1001                     e.Cancel = true;\r
1002                     return;\r
1003                 }\r
1004 \r
1005                 if (!selectedTab.AllowMerge) return;\r
1006                 if (!selectedTab.Merged)\r
1007                 {\r
1008                     ctxBtnMerge.Text = "Merge With";\r
1009 \r
1010                     List<RadegastTab> otherTabs = GetOtherTabs();\r
1011 \r
1012                     ctxBtnMerge.Enabled = (otherTabs.Count > 0);\r
1013                     if (!ctxBtnMerge.Enabled) return;\r
1014 \r
1015                     foreach (RadegastTab tab in otherTabs)\r
1016                     {\r
1017                         ToolStripItem item = ctxBtnMerge.DropDown.Items.Add(tab.Label);\r
1018                         item.Tag = tab.Name;\r
1019                         item.Click += new EventHandler(MergeItemClick);\r
1020                     }\r
1021                 }\r
1022                 else\r
1023                 {\r
1024                     ctxBtnMerge.Text = "Split";\r
1025                     ctxBtnMerge.Click += new EventHandler(SplitClick);\r
1026                 }\r
1027 \r
1028             }\r
1029         }\r
1030 \r
1031     }\r
1032 \r
1033     /// <summary>\r
1034     /// Arguments for tab events\r
1035     /// </summary>\r
1036     public class TabEventArgs : EventArgs\r
1037     {\r
1038         /// <summary>\r
1039         /// Tab that was manipulated in the event\r
1040         /// </summary>\r
1041         public RadegastTab Tab;\r
1042 \r
1043         public TabEventArgs()\r
1044             : base()\r
1045         {\r
1046         }\r
1047 \r
1048         public TabEventArgs(RadegastTab tab)\r
1049             : base()\r
1050         {\r
1051             Tab = tab;\r
1052         }\r
1053     }\r
1054 \r
1055     /// <summary>\r
1056     /// Argument for chat notification events\r
1057     /// </summary>\r
1058     public class ChatNotificationEventArgs : EventArgs\r
1059     {\r
1060         public string Message;\r
1061         public ChatBufferTextStyle Style;\r
1062 \r
1063         public ChatNotificationEventArgs(string message, ChatBufferTextStyle style)\r
1064         {\r
1065             Message = message;\r
1066             Style = style;\r
1067         }\r
1068     }\r
1069 }\r