OSDN Git Service

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