OSDN Git Service

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