OSDN Git Service

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