OSDN Git Service

Set eol style property
[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             tab.TabAttached += new EventHandler(tab_TabAttached);
626             tab.TabDetached += new EventHandler(tab_TabDetached);
627             tab.TabSelected += new EventHandler(tab_TabSelected);
628             tab.TabClosed += new EventHandler(tab_TabClosed);
629             tab.TabHidden += new EventHandler(tab_TabHidden);
630             tabs.Add(name.ToLower(), tab);
631
632             if (OnTabAdded != null)
633             {
634                 try { OnTabAdded(this, new TabEventArgs(tab)); }
635                 catch (Exception) { }
636             }
637
638             return tab;
639         }
640
641         private void tab_TabAttached(object sender, EventArgs e)
642         {
643             RadegastTab tab = (RadegastTab)sender;
644             tab.Select();
645         }
646
647         private void tab_TabDetached(object sender, EventArgs e)
648         {
649             RadegastTab tab = (RadegastTab)sender;
650             frmDetachedTab form = (frmDetachedTab)tab.Owner;
651
652             form.ReattachStrip = tstTabs;
653             form.ReattachContainer = toolStripContainer1.ContentPanel;
654         }
655
656         private void tab_TabSelected(object sender, EventArgs e)
657         {
658             RadegastTab tab = (RadegastTab)sender;
659
660             if (selectedTab != null &&
661                 selectedTab != tab)
662             { selectedTab.Deselect(); }
663
664             selectedTab = tab;
665
666             tbtnCloseTab.Enabled = tab.AllowClose || tab.AllowHide;
667             owner.AcceptButton = tab.DefaultControlButton;
668
669             if (OnTabSelected != null)
670             {
671                 try { OnTabSelected(this, new TabEventArgs(selectedTab)); }
672                 catch (Exception) { }
673             }
674         }
675
676         void tab_TabHidden(object sender, EventArgs e)
677         {
678             RadegastTab tab = (RadegastTab)sender;
679
680             if (selectedTab != null && selectedTab == tab)
681             {
682                 tab.Deselect();
683                 SelectDefaultTab();
684             }
685         }
686
687         private void tab_TabClosed(object sender, EventArgs e)
688         {
689             RadegastTab tab = (RadegastTab)sender;
690
691             if (selectedTab != null && selectedTab == tab && tab.Name != "chat")
692             {
693                 tab.Deselect();
694                 SelectDefaultTab();
695             }
696
697             tabs.Remove(tab.Name);
698
699             if (OnTabRemoved != null)
700             {
701                 try { OnTabRemoved(this, new TabEventArgs(tab)); }
702                 catch (Exception) { }
703             }
704
705             tab = null;
706         }
707
708         private void TabButtonClick(object sender, EventArgs e)
709         {
710             ToolStripButton button = (ToolStripButton)sender;
711
712             RadegastTab tab = tabs[button.Tag.ToString()];
713             tab.Select();
714         }
715
716         public void RemoveTabEntry(RadegastTab tab)
717         {
718             if (tstTabs.Items.Contains(tab.Button))
719             {
720                 tstTabs.Items.Remove(tab.Button);
721             }
722
723             tab.Button.Dispose();
724             tabs.Remove(tab.Name);
725         }
726
727         public void RemoveTab(string name)
728         {
729             if (tabs.ContainsKey(name))
730             {
731                 tabs.Remove(name);
732             }
733         }
734
735         //Used for outside classes that have a reference to TabsConsole
736         public void SelectTab(string name)
737         {
738             tabs[name.ToLower()].Select();
739         }
740
741         public bool TabExists(string name)
742         {
743             return tabs.ContainsKey(name.ToLower());
744         }
745
746         public RadegastTab GetTab(string name)
747         {
748             return tabs[name.ToLower()];
749         }
750
751         public List<RadegastTab> GetOtherTabs()
752         {
753             List<RadegastTab> otherTabs = new List<RadegastTab>();
754
755             foreach (ToolStripItem item in tstTabs.Items)
756             {
757                 if (item.Tag == null) continue;
758                 if ((ToolStripItem)item == selectedTab.Button) continue;
759
760                 RadegastTab tab = tabs[item.Tag.ToString()];
761                 if (!tab.AllowMerge) continue;
762                 if (tab.Merged) continue;
763
764                 otherTabs.Add(tab);
765             }
766
767             return otherTabs;
768         }
769
770         /// <summary>
771         /// Activates the next tab
772         /// </summary>
773         public void SelectNextTab()
774         {
775             List<ToolStripItem> buttons = new List<ToolStripItem>();
776
777             foreach (ToolStripItem item in tstTabs.Items)
778             {
779                 if (item.Tag == null || !item.Visible) continue;
780
781                 buttons.Add(item);
782             }
783
784             int current = 0;
785
786             for (int i = 0; i < buttons.Count; i++)
787             {
788                 if (buttons[i] == selectedTab.Button)
789                 {
790                     current = i;
791                     break;
792                 }
793             }
794
795             current++;
796
797             if (current == buttons.Count)
798                 current = 0;
799
800             SelectTab(tabs[buttons[current].Tag.ToString()].Name);
801         }
802
803         /// <summary>
804         /// Activates the previous tab
805         /// </summary>
806         public void SelectPreviousTab()
807         {
808             List<ToolStripItem> buttons = new List<ToolStripItem>();
809
810             foreach (ToolStripItem item in tstTabs.Items)
811             {
812                 if (item.Tag == null || !item.Visible) continue;
813
814                 buttons.Add(item);
815             }
816
817             int current = 0;
818
819             for (int i = 0; i < buttons.Count; i++)
820             {
821                 if (buttons[i] == selectedTab.Button)
822                 {
823                     current = i;
824                     break;
825                 }
826             }
827
828             current--;
829
830             if (current == -1)
831                 current = buttons.Count - 1;
832
833             SelectTab(tabs[buttons[current].Tag.ToString()].Name);
834         }
835
836
837         public IMTabWindow AddIMTab(UUID target, UUID session, string targetName)
838         {
839             IMTabWindow imTab = new IMTabWindow(instance, target, session, targetName);
840
841             RadegastTab tab = AddTab(session.ToString(), "IM: " + targetName, imTab);
842             imTab.SelectIMInput();
843             tab.Highlight();
844
845             return imTab;
846         }
847
848         public ConferenceIMTabWindow AddConferenceIMTab(UUID session, string name)
849         {
850             ConferenceIMTabWindow imTab = new ConferenceIMTabWindow(instance, session, name);
851
852             RadegastTab tab = AddTab(session.ToString(), name, imTab);
853             imTab.SelectIMInput();
854
855             return imTab;
856         }
857
858
859         public ConferenceIMTabWindow AddConferenceIMTab(InstantMessageEventArgs e)
860         {
861             ConferenceIMTabWindow imTab = AddConferenceIMTab(e.IM.IMSessionID, Utils.BytesToString(e.IM.BinaryBucket));
862             imTab.TextManager.ProcessIM(e);
863             return imTab;
864         }
865
866         public GroupIMTabWindow AddGroupIMTab(UUID session, string name)
867         {
868             GroupIMTabWindow imTab = new GroupIMTabWindow(instance, session, name);
869
870             RadegastTab tab = AddTab(session.ToString(), name, imTab);
871             imTab.SelectIMInput();
872
873             return imTab;
874         }
875
876         public GroupIMTabWindow AddGroupIMTab(InstantMessageEventArgs e)
877         {
878             GroupIMTabWindow imTab = AddGroupIMTab(e.IM.IMSessionID, Utils.BytesToString(e.IM.BinaryBucket));
879             imTab.TextManager.ProcessIM(e);
880             return imTab;
881         }
882
883         public IMTabWindow AddIMTab(InstantMessageEventArgs e)
884         {
885             IMTabWindow imTab = AddIMTab(e.IM.FromAgentID, e.IM.IMSessionID, e.IM.FromAgentName);
886             imTab.TextManager.ProcessIM(e);
887             return imTab;
888         }
889
890         public OutfitTextures AddOTTab(Avatar avatar)
891         {
892             OutfitTextures otTab = new OutfitTextures(instance, avatar);
893
894             RadegastTab tab = AddTab("OT: " + avatar.Name, "OT: " + avatar.Name, otTab);
895             otTab.GetTextures();
896             return otTab;
897         }
898
899         public MasterTab AddMSTab(Avatar avatar)
900         {
901             MasterTab msTab = new MasterTab(instance, avatar);
902
903             RadegastTab tab = AddTab("MS: " + avatar.Name, "MS: " + avatar.Name, msTab);
904             return msTab;
905         }
906
907         public AttachmentTab AddATTab(Avatar avatar)
908         {
909             AttachmentTab atTab = new AttachmentTab(instance, avatar);
910
911             RadegastTab tab = AddTab("AT: " + avatar.Name, "AT: " + avatar.Name, atTab);
912             return atTab;
913         }
914
915         public AnimTab AddAnimTab(Avatar avatar)
916         {
917             AnimTab animTab = new AnimTab(instance, avatar);
918
919             RadegastTab tab = AddTab("Anim: " + avatar.Name, "Anim: " + avatar.Name, animTab);
920             return animTab;
921         }
922
923         private void tbtnTabOptions_Click(object sender, EventArgs e)
924         {
925             tmnuMergeWith.Enabled = selectedTab.AllowMerge;
926             tmnuDetachTab.Enabled = selectedTab.AllowDetach;
927
928             tmnuMergeWith.DropDown.Items.Clear();
929
930             if (!selectedTab.AllowMerge) return;
931             if (!selectedTab.Merged)
932             {
933                 tmnuMergeWith.Text = "Merge With";
934
935                 List<RadegastTab> otherTabs = GetOtherTabs();
936
937                 tmnuMergeWith.Enabled = (otherTabs.Count > 0);
938                 if (!tmnuMergeWith.Enabled) return;
939
940                 foreach (RadegastTab tab in otherTabs)
941                 {
942                     ToolStripItem item = tmnuMergeWith.DropDown.Items.Add(tab.Label);
943                     item.Tag = tab.Name;
944                     item.Click += new EventHandler(MergeItemClick);
945                 }
946             }
947             else
948             {
949                 tmnuMergeWith.Text = "Split";
950                 tmnuMergeWith.Click += new EventHandler(SplitClick);
951             }
952         }
953
954         private void MergeItemClick(object sender, EventArgs e)
955         {
956             ToolStripItem item = (ToolStripItem)sender;
957             RadegastTab tab = tabs[item.Tag.ToString()];
958
959             selectedTab.MergeWith(tab);
960
961             SplitContainer container = (SplitContainer)selectedTab.Control;
962             toolStripContainer1.ContentPanel.Controls.Add(container);
963
964             selectedTab.Select();
965             RemoveTabEntry(tab);
966
967             tabs.Add(tab.Name, selectedTab);
968         }
969
970         private void SplitClick(object sender, EventArgs e)
971         {
972             SplitTab(selectedTab);
973             selectedTab.Select();
974         }
975
976         public void SplitTab(RadegastTab tab)
977         {
978             RadegastTab otherTab = tab.Split();
979             if (otherTab == null) return;
980
981             toolStripContainer1.ContentPanel.Controls.Add(tab.Control);
982             toolStripContainer1.ContentPanel.Controls.Add(otherTab.Control);
983
984             tabs.Remove(otherTab.Name);
985             AddTab(otherTab);
986         }
987
988         private void tmnuDetachTab_Click(object sender, EventArgs e)
989         {
990             if (!selectedTab.AllowDetach) return;
991             RadegastTab tab = selectedTab;
992             SelectDefaultTab();
993             tab.Detach(instance);
994         }
995
996         private void tbtnCloseTab_Click(object sender, EventArgs e)
997         {
998             RadegastTab tab = selectedTab;
999             if (tab.AllowClose)
1000                 tab.Close();
1001             else if (tab.AllowHide)
1002                 tab.Hide();
1003         }
1004
1005         private void TabsConsole_Load(object sender, EventArgs e)
1006         {
1007             owner = this.FindForm();
1008         }
1009
1010         private void ctxTabs_Opening(object sender, CancelEventArgs e)
1011         {
1012             Point pt = this.PointToClient(Cursor.Position);
1013             ToolStripItem stripItem = tstTabs.GetItemAt(pt);
1014
1015             if (stripItem == null)
1016             {
1017                 e.Cancel = true;
1018             }
1019             else
1020             {
1021                 tabs[stripItem.Tag.ToString()].Select();
1022
1023                 ctxBtnClose.Enabled = selectedTab.AllowClose || selectedTab.AllowHide;
1024                 ctxBtnDetach.Enabled = selectedTab.AllowDetach;
1025                 ctxBtnMerge.Enabled = selectedTab.AllowMerge;
1026                 ctxBtnMerge.DropDown.Items.Clear();
1027
1028                 if (!ctxBtnClose.Enabled && !ctxBtnDetach.Enabled && !ctxBtnMerge.Enabled)
1029                 {
1030                     e.Cancel = true;
1031                     return;
1032                 }
1033
1034                 if (!selectedTab.AllowMerge) return;
1035                 if (!selectedTab.Merged)
1036                 {
1037                     ctxBtnMerge.Text = "Merge With";
1038
1039                     List<RadegastTab> otherTabs = GetOtherTabs();
1040
1041                     ctxBtnMerge.Enabled = (otherTabs.Count > 0);
1042                     if (!ctxBtnMerge.Enabled) return;
1043
1044                     foreach (RadegastTab tab in otherTabs)
1045                     {
1046                         ToolStripItem item = ctxBtnMerge.DropDown.Items.Add(tab.Label);
1047                         item.Tag = tab.Name;
1048                         item.Click += new EventHandler(MergeItemClick);
1049                     }
1050                 }
1051                 else
1052                 {
1053                     ctxBtnMerge.Text = "Split";
1054                     ctxBtnMerge.Click += new EventHandler(SplitClick);
1055                 }
1056
1057             }
1058         }
1059
1060     }
1061
1062     /// <summary>
1063     /// Arguments for tab events
1064     /// </summary>
1065     public class TabEventArgs : EventArgs
1066     {
1067         /// <summary>
1068         /// Tab that was manipulated in the event
1069         /// </summary>
1070         public RadegastTab Tab;
1071
1072         public TabEventArgs()
1073             : base()
1074         {
1075         }
1076
1077         public TabEventArgs(RadegastTab tab)
1078             : base()
1079         {
1080             Tab = tab;
1081         }
1082     }
1083
1084     /// <summary>
1085     /// Argument for chat notification events
1086     /// </summary>
1087     public class ChatNotificationEventArgs : EventArgs
1088     {
1089         public string Message;
1090         public ChatBufferTextStyle Style;
1091
1092         public ChatNotificationEventArgs(string message, ChatBufferTextStyle style)
1093         {
1094             Message = message;
1095             Style = style;
1096         }
1097     }
1098
1099     /// <summary>
1100     /// Element of list of nearby avatars
1101     /// </summary>
1102     public class NearbyAvatar
1103     {
1104         public UUID ID { get; set; }
1105         public string Name { get; set; }
1106     }
1107
1108 }