2 // Radegast Metaverse Client
3 // Copyright (c) 2009-2014, Radegast Development Team
4 // All rights reserved.
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
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.
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.
32 using System.Collections.Generic;
33 using System.ComponentModel;
35 using System.Windows.Forms;
36 using Radegast.Netcom;
41 public partial class TabsConsole : UserControl
45 /// List of nearby avatars (radar data)
47 public List<NearbyAvatar> NearbyAvatars
51 List<NearbyAvatar> res = new List<NearbyAvatar>();
53 if (TabExists("chat"))
55 ChatConsole c = (ChatConsole)Tabs["chat"].Control;
56 lock (c.agentSimHandle)
58 foreach (ListViewItem item in c.lvwObjects.Items)
60 if (item.Name != client.Self.AgentID.ToString())
62 res.Add(new NearbyAvatar() { ID = new UUID(item.Name), Name = item.Text });
73 /// Delegate invoked on tab operations
75 /// <param name="sender">Event sender</param>
76 /// <param name="e">Event arguments</param>
77 public delegate void TabCallback(object sender, TabEventArgs e);
80 /// Fired when a tab is selected
82 public event TabCallback OnTabSelected;
86 /// Delegate invoked when chat notification is printed
88 /// <param name="sender">Event sender</param>
89 /// <param name="e">Event arguments</param>
90 public delegate void ChatNotificationCallback(object sender, ChatNotificationEventArgs e);
93 /// Fired when a tab is selected
95 public event ChatNotificationCallback OnChatNotification;
98 /// Fired when a new tab is added
100 public event TabCallback OnTabAdded;
103 /// Fired when a tab is removed
105 public event TabCallback OnTabRemoved;
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 public ChatTextManager MainChatManger { get { return mainChatManger; } }
113 private Dictionary<string, RadegastTab> tabs = new Dictionary<string, RadegastTab>();
114 public Dictionary<string, RadegastTab> Tabs { get { return tabs; } }
116 private ChatConsole chatConsole;
118 private RadegastTab selectedTab;
121 /// Currently selected tab
123 public RadegastTab SelectedTab
133 public TabsConsole(RadegastInstance instance)
135 InitializeComponent();
136 Disposed += new EventHandler(TabsConsole_Disposed);
138 this.instance = instance;
139 this.instance.ClientChanged += new EventHandler<ClientChangedEventArgs>(instance_ClientChanged);
147 RegisterClientEvents(client);
150 private void RegisterClientEvents(GridClient client)
152 client.Self.ScriptQuestion += new EventHandler<ScriptQuestionEventArgs>(Self_ScriptQuestion);
153 client.Self.ScriptDialog += new EventHandler<ScriptDialogEventArgs>(Self_ScriptDialog);
154 client.Self.LoadURL += new EventHandler<LoadUrlEventArgs>(Self_LoadURL);
155 client.Self.SetDisplayNameReply += new EventHandler<SetDisplayNameReplyEventArgs>(Self_SetDisplayNameReply);
156 client.Avatars.DisplayNameUpdate += new EventHandler<DisplayNameUpdateEventArgs>(Avatars_DisplayNameUpdate);
157 client.Network.EventQueueRunning += new EventHandler<EventQueueRunningEventArgs>(Network_EventQueueRunning);
158 client.Network.RegisterCallback(OpenMetaverse.Packets.PacketType.ScriptTeleportRequest, ScriptTeleportRequestHandler);
161 private void UnregisterClientEvents(GridClient client)
163 client.Self.ScriptQuestion -= new EventHandler<ScriptQuestionEventArgs>(Self_ScriptQuestion);
164 client.Self.ScriptDialog -= new EventHandler<ScriptDialogEventArgs>(Self_ScriptDialog);
165 client.Self.LoadURL -= new EventHandler<LoadUrlEventArgs>(Self_LoadURL);
166 client.Self.SetDisplayNameReply -= new EventHandler<SetDisplayNameReplyEventArgs>(Self_SetDisplayNameReply);
167 client.Avatars.DisplayNameUpdate -= new EventHandler<DisplayNameUpdateEventArgs>(Avatars_DisplayNameUpdate);
168 client.Network.EventQueueRunning -= new EventHandler<EventQueueRunningEventArgs>(Network_EventQueueRunning);
169 client.Network.UnregisterCallback(OpenMetaverse.Packets.PacketType.ScriptTeleportRequest, ScriptTeleportRequestHandler);
172 void instance_ClientChanged(object sender, ClientChangedEventArgs e)
174 UnregisterClientEvents(e.OldClient);
175 RegisterClientEvents(client);
178 void TabsConsole_Disposed(object sender, EventArgs e)
180 RemoveNetcomEvents();
181 UnregisterClientEvents(client);
184 private void AddNetcomEvents()
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.ChatSent += new EventHandler<ChatSentEventArgs>(netcom_ChatSent);
190 netcom.AlertMessageReceived += new EventHandler<AlertMessageEventArgs>(netcom_AlertMessageReceived);
191 netcom.InstantMessageReceived += new EventHandler<InstantMessageEventArgs>(netcom_InstantMessageReceived);
194 private void RemoveNetcomEvents()
196 netcom.ClientLoginStatus -= new EventHandler<LoginProgressEventArgs>(netcom_ClientLoginStatus);
197 netcom.ClientLoggedOut -= new EventHandler(netcom_ClientLoggedOut);
198 netcom.ClientDisconnected -= new EventHandler<DisconnectedEventArgs>(netcom_ClientDisconnected);
199 netcom.ChatSent -= new EventHandler<ChatSentEventArgs>(netcom_ChatSent);
200 netcom.AlertMessageReceived -= new EventHandler<AlertMessageEventArgs>(netcom_AlertMessageReceived);
201 netcom.InstantMessageReceived -= new EventHandler<InstantMessageEventArgs>(netcom_InstantMessageReceived);
204 void ScriptTeleportRequestHandler(object sender, PacketReceivedEventArgs e)
208 if (IsHandleCreated || !instance.MonoRuntime)
209 BeginInvoke(new MethodInvoker(() => ScriptTeleportRequestHandler(sender, e)));
213 var msg = (OpenMetaverse.Packets.ScriptTeleportRequestPacket)e.Packet;
215 if (TabExists("map"))
217 Tabs["map"].Select();
218 ((MapConsole)Tabs["map"].Control).CenterOnGlobalPos(
219 (float)(client.Self.GlobalPosition.X - client.Self.SimPosition.X) + msg.Data.SimPosition.X,
220 (float)(client.Self.GlobalPosition.Y - client.Self.SimPosition.Y) + msg.Data.SimPosition.Y,
221 msg.Data.SimPosition.Z);
225 void Network_EventQueueRunning(object sender, EventQueueRunningEventArgs e)
229 BeginInvoke(new MethodInvoker(() => Network_EventQueueRunning(sender, e)));
233 if (TabExists("friends")) return;
234 if (e.Simulator == client.Network.CurrentSim)
236 client.Self.UpdateAgentLanguage("en", true);
237 InitializeOnlineTabs();
241 void Self_ScriptDialog(object sender, ScriptDialogEventArgs e)
243 if (instance.MainForm.InvokeRequired)
245 instance.MainForm.BeginInvoke(new MethodInvoker(() => Self_ScriptDialog(sender, e)));
249 // Is this object muted
250 if (null != client.Self.MuteList.Find(m => (m.Type == MuteType.Object && m.ID == e.ObjectID) // muted object by id
251 || (m.Type == MuteType.ByName && m.Name == e.ObjectName) // object muted by name
254 instance.MainForm.AddNotification(new ntfScriptDialog(instance, e.Message, e.ObjectName, e.ImageID, e.ObjectID, e.FirstName, e.LastName, e.Channel, e.ButtonLabels));
257 void Self_ScriptQuestion(object sender, ScriptQuestionEventArgs e)
259 // Is this object muted
260 if (null != client.Self.MuteList.Find(m => (m.Type == MuteType.Object && m.ID == e.TaskID) // muted object by id
261 || (m.Type == MuteType.ByName && m.Name == e.ObjectName) // object muted by name
264 if (instance.GlobalSettings["on_script_question"] == "Auto Decline"
265 || instance.RLV.RestictionActive("denypermission"))
267 instance.Client.Self.ScriptQuestionReply(e.Simulator, e.ItemID, e.TaskID, 0);
269 else if (instance.GlobalSettings["on_script_question"] == "Auto Accept"
270 || instance.RLV.RestictionActive("acceptpermission"))
272 instance.Client.Self.ScriptQuestionReply(e.Simulator, e.ItemID, e.TaskID, e.Questions);
276 instance.MainForm.AddNotification(new ntfPermissions(instance, e.Simulator, e.TaskID, e.ItemID, e.ObjectName, e.ObjectOwnerName, e.Questions));
280 private void netcom_ClientLoginStatus(object sender, LoginProgressEventArgs e)
282 if (e.Status == LoginStatus.Failed)
284 DisplayNotificationInChat("Login error: " + e.Message, ChatBufferTextStyle.Error);
286 else if (e.Status == LoginStatus.Success)
288 DisplayNotificationInChat("Logged in as " + netcom.LoginOptions.FullName + ".", ChatBufferTextStyle.StatusDarkBlue);
289 DisplayNotificationInChat("Login reply: " + e.Message, ChatBufferTextStyle.StatusDarkBlue);
291 if (tabs.ContainsKey("login"))
293 if (selectedTab.Name == "login")
295 ForceCloseTab("login");
298 client.Self.RetrieveInstantMessages();
302 private void netcom_ClientLoggedOut(object sender, EventArgs e)
307 DisplayNotificationInChat("Logged out.");
311 private void netcom_ClientDisconnected(object sender, DisconnectedEventArgs e)
313 if (e.Reason == NetworkManager.DisconnectType.ClientInitiated) return;
317 DisplayNotificationInChat("Disconnected: " + e.Message, ChatBufferTextStyle.Error);
320 void Avatars_DisplayNameUpdate(object sender, DisplayNameUpdateEventArgs e)
322 DisplayNotificationInChat(string.Format("({0}) is now known as {1}", e.DisplayName.UserName, e.DisplayName.DisplayName));
325 void Self_SetDisplayNameReply(object sender, SetDisplayNameReplyEventArgs e)
329 DisplayNotificationInChat("You are now knows as " + e.DisplayName.DisplayName);
333 DisplayNotificationInChat("Failed to set a new display name: " + e.Reason, ChatBufferTextStyle.Error);
337 private void netcom_AlertMessageReceived(object sender, AlertMessageEventArgs e)
339 tabs["chat"].Highlight();
342 private void netcom_ChatSent(object sender, ChatSentEventArgs e)
344 tabs["chat"].Highlight();
347 void Self_LoadURL(object sender, LoadUrlEventArgs e)
349 // Is the object or the owner muted?
350 if (null != client.Self.MuteList.Find(m => (m.Type == MuteType.Object && m.ID == e.ObjectID) // muted object by id
351 || (m.Type == MuteType.ByName && m.Name == e.ObjectName) // object muted by name
352 || (m.Type == MuteType.Resident && m.ID == e.OwnerID) // object's owner muted
355 instance.MainForm.AddNotification(new ntfLoadURL(instance, e));
358 private void netcom_InstantMessageReceived(object sender, InstantMessageEventArgs e)
360 // Messaage from someone we muted?
361 if (null != client.Self.MuteList.Find(me => me.Type == MuteType.Resident && me.ID == e.IM.FromAgentID)) return;
365 if (instance.State.LSLHelper.ProcessIM(e))
372 Logger.Log("Failed executing automation action: " + ex.ToString(), Helpers.LogLevel.Warning);
377 case InstantMessageDialog.SessionSend:
378 if (instance.Groups.ContainsKey(e.IM.IMSessionID))
384 HandleConferenceIM(e);
388 case InstantMessageDialog.MessageFromAgent:
389 if (e.IM.FromAgentName == "Second Life")
391 HandleIMFromObject(e);
393 else if (e.IM.FromAgentID == UUID.Zero)
395 instance.MainForm.AddNotification(new ntfGeneric(instance, e.IM.Message));
397 else if (e.IM.GroupIM || instance.Groups.ContainsKey(e.IM.IMSessionID))
401 else if (e.IM.BinaryBucket.Length > 1)
403 HandleConferenceIM(e);
405 else if (e.IM.IMSessionID == UUID.Zero)
407 String msg = string.Format("Message from {0}: {1}", instance.Names.Get(e.IM.FromAgentID, e.IM.FromAgentName), e.IM.Message);
408 instance.MainForm.AddNotification(new ntfGeneric(instance, msg));
409 DisplayNotificationInChat(msg);
417 case InstantMessageDialog.MessageFromObject:
418 HandleIMFromObject(e);
421 case InstantMessageDialog.StartTyping:
422 if (TabExists(e.IM.FromAgentName))
424 RadegastTab tab = tabs[e.IM.FromAgentName.ToLower()];
425 if (!tab.Highlighted) tab.PartialHighlight();
430 case InstantMessageDialog.StopTyping:
431 if (TabExists(e.IM.FromAgentName))
433 RadegastTab tab = tabs[e.IM.FromAgentName.ToLower()];
434 if (!tab.Highlighted) tab.Unhighlight();
439 case InstantMessageDialog.MessageBox:
440 instance.MainForm.AddNotification(new ntfGeneric(instance, e.IM.Message));
443 case InstantMessageDialog.RequestTeleport:
444 if (instance.RLV.AutoAcceptTP(e.IM.FromAgentID))
446 DisplayNotificationInChat("Auto accepting teleprot from " + e.IM.FromAgentName);
447 instance.Client.Self.TeleportLureRespond(e.IM.FromAgentID, e.IM.IMSessionID, true);
451 instance.MainForm.AddNotification(new ntfTeleport(instance, e.IM));
455 case InstantMessageDialog.RequestLure:
456 instance.MainForm.AddNotification(new ntfRequestLure(instance, e.IM));
459 case InstantMessageDialog.GroupInvitation:
460 instance.MainForm.AddNotification(new ntfGroupInvitation(instance, e.IM));
463 case InstantMessageDialog.FriendshipOffered:
464 if (e.IM.FromAgentName == "Second Life")
466 HandleIMFromObject(e);
470 instance.MainForm.AddNotification(new ntfFriendshipOffer(instance, e.IM));
474 case InstantMessageDialog.InventoryAccepted:
475 DisplayNotificationInChat(e.IM.FromAgentName + " accepted your inventory offer.");
478 case InstantMessageDialog.InventoryDeclined:
479 DisplayNotificationInChat(e.IM.FromAgentName + " declined your inventory offer.");
482 case InstantMessageDialog.GroupNotice:
483 // Is this group muted?
484 if (null != client.Self.MuteList.Find(me => me.Type == MuteType.Group && me.ID == e.IM.FromAgentID)) break;
486 instance.MainForm.AddNotification(new ntfGroupNotice(instance, e.IM));
489 case InstantMessageDialog.InventoryOffered:
490 var ion = new ntfInventoryOffer(instance, e.IM);
491 instance.MainForm.AddNotification(ion);
492 if (instance.GlobalSettings["inv_auto_accept_mode"].AsInteger() == 1)
494 ion.btnAccept.PerformClick();
496 else if (instance.GlobalSettings["inv_auto_accept_mode"].AsInteger() == 2)
498 ion.btnDiscard.PerformClick();
502 case InstantMessageDialog.TaskInventoryOffered:
503 // Is the object muted by name?
504 if (null != client.Self.MuteList.Find(me => me.Type == MuteType.ByName && me.Name == e.IM.FromAgentName)) break;
506 var iont = new ntfInventoryOffer(instance, e.IM);
507 instance.MainForm.AddNotification(iont);
508 if (instance.GlobalSettings["inv_auto_accept_mode"].AsInteger() == 1)
510 iont.btnAccept.PerformClick();
512 else if (instance.GlobalSettings["inv_auto_accept_mode"].AsInteger() == 2)
514 iont.btnDiscard.PerformClick();
521 /// Make default tab (chat) active
523 public void SelectDefaultTab()
525 if (IsHandleCreated && TabExists("chat"))
526 tabs["chat"].Select();
530 /// Displays notification in the main chat tab
532 /// <param name="msg">Message to be printed in the chat tab</param>
533 public void DisplayNotificationInChat(string msg)
535 DisplayNotificationInChat(msg, ChatBufferTextStyle.ObjectChat);
539 /// Displays notification in the main chat tab
541 /// <param name="msg">Message to be printed in the chat tab</param>
542 /// <param name="style">Style of the message to be printed, normal, object, etc.</param>
543 public void DisplayNotificationInChat(string msg, ChatBufferTextStyle style)
545 DisplayNotificationInChat(msg, style, true);
549 /// Displays notification in the main chat tab
551 /// <param name="msg">Message to be printed in the chat tab</param>
552 /// <param name="style">Style of the message to be printed, normal, object, etc.</param>
553 /// <param name="highlightChatTab">Highligt (and flash in taskbar) chat tab if not selected</param>
554 public void DisplayNotificationInChat(string msg, ChatBufferTextStyle style, bool highlightChatTab)
558 if (!instance.MonoRuntime || IsHandleCreated)
559 BeginInvoke(new MethodInvoker(() => DisplayNotificationInChat(msg, style, highlightChatTab)));
563 if (style != ChatBufferTextStyle.Invisible)
565 ChatBufferItem line = new ChatBufferItem(
575 mainChatManger.ProcessBufferItem(line, true);
576 if (highlightChatTab)
578 tabs["chat"].Highlight();
581 catch (Exception) { }
584 if (OnChatNotification != null)
586 try { OnChatNotification(this, new ChatNotificationEventArgs(msg, style)); }
591 private void HandleIMFromObject(InstantMessageEventArgs e)
593 // Is the object or the owner muted?
594 if (null != client.Self.MuteList.Find(m => (m.Type == MuteType.Object && m.ID == e.IM.IMSessionID) // muted object by id
595 || (m.Type == MuteType.ByName && m.Name == e.IM.FromAgentName) // object muted by name
596 || (m.Type == MuteType.Resident && m.ID == e.IM.FromAgentID) // object's owner muted
599 DisplayNotificationInChat(e.IM.FromAgentName + ": " + e.IM.Message);
602 public static Control FindFocusedControl(Control control)
604 var container = control as ContainerControl;
605 while (container != null)
607 control = container.ActiveControl;
608 container = control as ContainerControl;
614 /// Creates new IM tab if needed
616 /// <param name="agentID">IM session with agentID</param>
617 /// <param name="label">Tab label</param>
618 /// <param name="makeActive">Should tab be selected and focused</param>
619 /// <returns>True if there was an existing IM tab, false if it was created</returns>
620 public bool ShowIMTab(UUID agentID, string label, bool makeActive)
622 if (instance.TabConsole.TabExists((client.Self.AgentID ^ agentID).ToString()))
626 instance.TabConsole.SelectTab((client.Self.AgentID ^ agentID).ToString());
633 instance.MediaManager.PlayUISound(UISounds.IMWindow);
637 instance.MediaManager.PlayUISound(UISounds.IM);
640 Control active = FindFocusedControl(instance.MainForm);
642 instance.TabConsole.AddIMTab(agentID, client.Self.AgentID ^ agentID, label);
646 instance.TabConsole.SelectTab((client.Self.AgentID ^ agentID).ToString());
648 else if (active != null)
656 private void HandleIM(InstantMessageEventArgs e)
658 bool isNew = ShowIMTab(e.IM.FromAgentID, e.IM.FromAgentName, false);
659 if (!TabExists(e.IM.IMSessionID.ToString())) return; // this should now exist. sanity check anyway
660 RadegastTab tab = tabs[e.IM.IMSessionID.ToString()];
665 ((IMTabWindow)tab.Control).TextManager.ProcessIM(e);
669 private void HandleConferenceIM(InstantMessageEventArgs e)
671 if (TabExists(e.IM.IMSessionID.ToString()))
673 RadegastTab tab = tabs[e.IM.IMSessionID.ToString()];
678 instance.MediaManager.PlayUISound(UISounds.IM);
680 Control active = FindFocusedControl(instance.MainForm);
682 ConferenceIMTabWindow imTab = AddConferenceIMTab(e.IM.IMSessionID, Utils.BytesToString(e.IM.BinaryBucket));
683 tabs[e.IM.IMSessionID.ToString()].Highlight();
684 imTab.TextManager.ProcessIM(e);
692 private void HandleGroupIM(InstantMessageEventArgs e)
694 // Ignore group IM from a muted group
695 if (null != client.Self.MuteList.Find(me => me.Type == MuteType.Group && (me.ID == e.IM.IMSessionID || me.ID == e.IM.FromAgentID))) return;
697 if (TabExists(e.IM.IMSessionID.ToString()))
699 RadegastTab tab = tabs[e.IM.IMSessionID.ToString()];
704 instance.MediaManager.PlayUISound(UISounds.IM);
706 Control active = FindFocusedControl(instance.MainForm);
708 GroupIMTabWindow imTab = AddGroupIMTab(e.IM.IMSessionID, Utils.BytesToString(e.IM.BinaryBucket));
709 imTab.TextManager.ProcessIM(e);
710 tabs[e.IM.IMSessionID.ToString()].Highlight();
718 public void InitializeMainTab()
720 if (TabExists("login"))
722 ForceCloseTab("login");
725 LoginConsole loginConsole = new LoginConsole(instance);
727 RadegastTab tab = AddTab("login", "Login", loginConsole);
728 tab.AllowClose = false;
729 tab.AllowDetach = false;
730 tab.AllowMerge = false;
731 tab.AllowHide = false;
733 loginConsole.RegisterTab(tab);
736 private void InitializeChatTab()
738 chatConsole = new ChatConsole(instance);
739 mainChatManger = chatConsole.ChatManager;
741 RadegastTab tab = AddTab("chat", "Chat", chatConsole);
742 tab.AllowClose = false;
743 tab.AllowDetach = false;
744 tab.AllowHide = false;
749 /// Create Tabs that only make sense when connected
751 private void InitializeOnlineTabs()
753 RadegastTab tab = AddTab("friends", "Friends", new FriendsConsole(instance));
754 tab.AllowClose = false;
755 tab.AllowDetach = true;
758 tab = AddTab("groups", "Groups", new GroupsConsole(instance));
759 tab.AllowClose = false;
760 tab.AllowDetach = true;
763 // Ugly workaround for a mono bug
764 InventoryConsole inv = new InventoryConsole(instance);
765 if (instance.MonoRuntime) inv.invTree.Scrollable = false;
766 tab = AddTab("inventory", "Inventory", inv);
767 if (instance.MonoRuntime) inv.invTree.Scrollable = true;
768 tab.AllowClose = false;
769 tab.AllowDetach = true;
772 tab = AddTab("search", "Search", new SearchConsole(instance));
773 tab.AllowClose = false;
774 tab.AllowDetach = true;
777 tab = AddTab("map", "Map", new MapConsole(instance));
778 tab.AllowClose = false;
779 tab.AllowDetach = true;
782 tab = AddTab("voice", "Voice", new VoiceConsole(instance));
783 tab.AllowClose = false;
784 tab.AllowDetach = true;
789 /// Close tabs that make no sense when not connected
791 private void DisposeOnlineTabs()
795 ForceCloseTab("voice");
796 ForceCloseTab("map");
797 ForceCloseTab("search");
798 ForceCloseTab("inventory");
799 ForceCloseTab("groups");
800 ForceCloseTab("friends");
804 private void ForceCloseTab(string name)
806 if (!TabExists(name)) return;
808 RadegastTab tab = tabs[name];
809 if (tab.Merged) SplitTab(tab);
811 tab.AllowClose = true;
817 public void RegisterContextAction(Type libomvType, String label, EventHandler handler)
819 instance.ContextActionManager.RegisterContextAction(libomvType, label, handler);
822 public void RegisterContextAction(ContextAction handler)
824 instance.ContextActionManager.RegisterContextAction(handler);
827 public void AddTab(RadegastTab tab)
829 ToolStripButton button = (ToolStripButton)tstTabs.Items.Add(tab.Label);
830 button.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText;
832 button.AutoToolTip = false;
833 button.Tag = tab.Name;
834 button.Click += new EventHandler(TabButtonClick);
836 tabs.Add(tab.Name, tab);
838 if (OnTabAdded != null)
840 try { OnTabAdded(this, new TabEventArgs(tab)); }
841 catch (Exception) { }
845 public RadegastTab AddTab(string name, string label, Control control)
847 // WORKAROUND: one should never add tab that alrady exists
848 // but under some weird conditions disconnect/connect
849 // fire in the wrong order
852 Logger.Log("Force closing tab '" + name + "'", Helpers.LogLevel.Warning, client);
856 control.Visible = false;
857 control.Dock = DockStyle.Fill;
858 toolStripContainer1.ContentPanel.Controls.Add(control);
860 ToolStripButton button = (ToolStripButton)tstTabs.Items.Add(label);
861 button.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText;
863 button.AutoToolTip = false;
864 button.Tag = name.ToLower();
865 button.AllowDrop = true;
866 button.Click += new EventHandler(TabButtonClick);
868 RadegastTab tab = new RadegastTab(instance, button, control, name.ToLower(), label);
869 if (control is RadegastTabControl)
870 ((RadegastTabControl)control).RadegastTab = tab;
871 tab.TabAttached += new EventHandler(tab_TabAttached);
872 tab.TabDetached += new EventHandler(tab_TabDetached);
873 tab.TabSelected += new EventHandler(tab_TabSelected);
874 tab.TabClosed += new EventHandler(tab_TabClosed);
875 tab.TabHidden += new EventHandler(tab_TabHidden);
876 tabs.Add(name.ToLower(), tab);
878 if (OnTabAdded != null)
880 try { OnTabAdded(this, new TabEventArgs(tab)); }
881 catch (Exception) { }
884 button.MouseDown += (msender, margs) =>
886 if (margs.Button == MouseButtons.Middle)
892 else if (tab.AllowHide)
902 private void tab_TabAttached(object sender, EventArgs e)
904 RadegastTab tab = (RadegastTab)sender;
908 private void tab_TabDetached(object sender, EventArgs e)
910 RadegastTab tab = (RadegastTab)sender;
911 frmDetachedTab form = (frmDetachedTab)tab.Owner;
913 form.ReattachStrip = tstTabs;
914 form.ReattachContainer = toolStripContainer1.ContentPanel;
917 private void tab_TabSelected(object sender, EventArgs e)
919 RadegastTab tab = (RadegastTab)sender;
921 if (selectedTab != null &&
923 { selectedTab.Deselect(); }
927 tbtnCloseTab.Enabled = !tab.Merged && (tab.AllowClose || tab.AllowHide);
931 owner.AcceptButton = tab.DefaultControlButton;
934 if (OnTabSelected != null)
936 try { OnTabSelected(this, new TabEventArgs(selectedTab)); }
937 catch (Exception) { }
941 void tab_TabHidden(object sender, EventArgs e)
943 RadegastTab tab = (RadegastTab)sender;
945 if (selectedTab != null && selectedTab == tab)
952 private void tab_TabClosed(object sender, EventArgs e)
954 RadegastTab tab = (RadegastTab)sender;
956 if (selectedTab != null && selectedTab == tab && tab.Name != "chat")
962 tabs.Remove(tab.Name);
964 if (OnTabRemoved != null)
966 try { OnTabRemoved(this, new TabEventArgs(tab)); }
967 catch (Exception) { }
973 private void TabButtonClick(object sender, EventArgs e)
975 ToolStripButton button = (ToolStripButton)sender;
977 RadegastTab tab = tabs[button.Tag.ToString()];
981 public void RemoveTabEntry(RadegastTab tab)
983 if (tstTabs.Items.Contains(tab.Button))
985 tstTabs.Items.Remove(tab.Button);
988 tab.Button.Dispose();
989 tabs.Remove(tab.Name);
992 public void RemoveTab(string name)
994 if (tabs.ContainsKey(name))
1000 //Used for outside classes that have a reference to TabsConsole
1001 public void SelectTab(string name)
1003 if (TabExists(name.ToLower()))
1004 tabs[name.ToLower()].Select();
1007 public bool TabExists(string name)
1009 return tabs.ContainsKey(name.ToLower());
1012 public RadegastTab GetTab(string name)
1014 if (TabExists(name.ToLower()))
1015 return tabs[name.ToLower()];
1020 public List<RadegastTab> GetOtherTabs()
1022 List<RadegastTab> otherTabs = new List<RadegastTab>();
1024 foreach (ToolStripItem item in tstTabs.Items)
1026 if (item.Tag == null) continue;
1027 if ((ToolStripItem)item == selectedTab.Button) continue;
1029 RadegastTab tab = tabs[item.Tag.ToString()];
1030 if (!tab.AllowMerge) continue;
1031 if (tab.Merged) continue;
1040 /// Activates the next tab
1042 public void SelectNextTab()
1044 List<ToolStripItem> buttons = new List<ToolStripItem>();
1046 foreach (ToolStripItem item in tstTabs.Items)
1048 if (item.Tag == null || !item.Visible) continue;
1055 for (int i = 0; i < buttons.Count; i++)
1057 if (buttons[i] == selectedTab.Button)
1066 if (current == buttons.Count)
1069 SelectTab(tabs[buttons[current].Tag.ToString()].Name);
1073 /// Activates the previous tab
1075 public void SelectPreviousTab()
1077 List<ToolStripItem> buttons = new List<ToolStripItem>();
1079 foreach (ToolStripItem item in tstTabs.Items)
1081 if (item.Tag == null || !item.Visible) continue;
1088 for (int i = 0; i < buttons.Count; i++)
1090 if (buttons[i] == selectedTab.Button)
1100 current = buttons.Count - 1;
1102 SelectTab(tabs[buttons[current].Tag.ToString()].Name);
1106 public IMTabWindow AddIMTab(UUID target, UUID session, string targetName)
1108 IMTabWindow imTab = new IMTabWindow(instance, target, session, targetName);
1110 RadegastTab tab = AddTab(session.ToString(), "IM: " + targetName, imTab);
1111 imTab.SelectIMInput();
1116 public ConferenceIMTabWindow AddConferenceIMTab(UUID session, string name)
1118 ConferenceIMTabWindow imTab = new ConferenceIMTabWindow(instance, session, name);
1120 RadegastTab tab = AddTab(session.ToString(), name, imTab);
1121 imTab.SelectIMInput();
1126 public GroupIMTabWindow AddGroupIMTab(UUID session, string name)
1128 GroupIMTabWindow imTab = new GroupIMTabWindow(instance, session, name);
1130 RadegastTab tab = AddTab(session.ToString(), name, imTab);
1131 imTab.SelectIMInput();
1136 public OutfitTextures AddOTTab(Avatar avatar)
1138 OutfitTextures otTab = new OutfitTextures(instance, avatar);
1140 RadegastTab tab = AddTab("OT: " + avatar.Name, "OT: " + avatar.Name, otTab);
1141 otTab.GetTextures();
1145 public MasterTab AddMSTab(Avatar avatar)
1147 MasterTab msTab = new MasterTab(instance, avatar);
1149 RadegastTab tab = AddTab("MS: " + avatar.Name, "MS: " + avatar.Name, msTab);
1153 public AnimTab AddAnimTab(Avatar avatar)
1155 AnimTab animTab = new AnimTab(instance, avatar);
1157 RadegastTab tab = AddTab("Anim: " + avatar.Name, "Anim: " + avatar.Name, animTab);
1161 private void tbtnTabOptions_Click(object sender, EventArgs e)
1163 tmnuMergeWith.Enabled = selectedTab.AllowMerge;
1164 tmnuDetachTab.Enabled = selectedTab.AllowDetach;
1166 tmnuMergeWith.DropDown.Items.Clear();
1168 if (!selectedTab.AllowMerge) return;
1169 if (!selectedTab.Merged)
1171 tmnuMergeWith.Text = "Merge With";
1173 List<RadegastTab> otherTabs = GetOtherTabs();
1175 tmnuMergeWith.Enabled = (otherTabs.Count > 0);
1176 if (!tmnuMergeWith.Enabled) return;
1178 foreach (RadegastTab tab in otherTabs)
1180 ToolStripItem item = tmnuMergeWith.DropDown.Items.Add(tab.Label);
1181 item.Tag = tab.Name;
1182 item.Click += new EventHandler(MergeItemClick);
1187 tmnuMergeWith.Text = "Split";
1188 tmnuMergeWith.Click += new EventHandler(SplitClick);
1192 private void MergeItemClick(object sender, EventArgs e)
1194 ToolStripItem item = (ToolStripItem)sender;
1195 RadegastTab tab = tabs[item.Tag.ToString()];
1197 selectedTab.MergeWith(tab);
1199 SplitContainer container = (SplitContainer)selectedTab.Control;
1200 toolStripContainer1.ContentPanel.Controls.Add(container);
1202 selectedTab.Select();
1203 RemoveTabEntry(tab);
1205 tabs.Add(tab.Name, selectedTab);
1208 private void SplitClick(object sender, EventArgs e)
1210 SplitTab(selectedTab);
1211 selectedTab.Select();
1214 public void SplitTab(RadegastTab tab)
1216 RadegastTab otherTab = tab.Split();
1217 if (otherTab == null) return;
1219 toolStripContainer1.ContentPanel.Controls.Add(tab.Control);
1220 toolStripContainer1.ContentPanel.Controls.Add(otherTab.Control);
1222 tabs.Remove(otherTab.Name);
1226 private void tmnuDetachTab_Click(object sender, EventArgs e)
1228 if (!selectedTab.AllowDetach) return;
1229 RadegastTab tab = selectedTab;
1231 tab.Detach(instance);
1234 private void tbtnCloseTab_Click(object sender, EventArgs e)
1236 RadegastTab tab = selectedTab;
1239 else if (tab.AllowClose)
1241 else if (tab.AllowHide)
1245 private void TabsConsole_Load(object sender, EventArgs e)
1247 owner = this.FindForm();
1250 private void ctxTabs_Opening(object sender, CancelEventArgs e)
1254 Point pt = this.PointToClient(Cursor.Position);
1255 ToolStripItem stripItem = tstTabs.GetItemAt(pt);
1257 if (stripItem == null)
1263 tabs[stripItem.Tag.ToString()].Select();
1265 ctxBtnClose.Enabled = !selectedTab.Merged && (selectedTab.AllowClose || selectedTab.AllowHide);
1266 ctxBtnDetach.Enabled = selectedTab.AllowDetach;
1267 ctxBtnMerge.Enabled = selectedTab.AllowMerge;
1268 ctxBtnMerge.DropDown.Items.Clear();
1270 if (!ctxBtnClose.Enabled && !ctxBtnDetach.Enabled && !ctxBtnMerge.Enabled)
1276 if (!selectedTab.AllowMerge) return;
1277 if (!selectedTab.Merged)
1279 ctxBtnMerge.Text = "Merge With";
1281 List<RadegastTab> otherTabs = GetOtherTabs();
1283 ctxBtnMerge.Enabled = (otherTabs.Count > 0);
1284 if (!ctxBtnMerge.Enabled) return;
1286 foreach (RadegastTab tab in otherTabs)
1288 ToolStripItem item = ctxBtnMerge.DropDown.Items.Add(tab.Label);
1289 item.Tag = tab.Name;
1290 item.Click += new EventHandler(MergeItemClick);
1295 ctxBtnMerge.Text = "Split";
1296 ctxBtnMerge.Click += new EventHandler(SplitClick);
1305 /// Arguments for tab events
1307 public class TabEventArgs : EventArgs
1310 /// Tab that was manipulated in the event
1312 public RadegastTab Tab;
1314 public TabEventArgs()
1319 public TabEventArgs(RadegastTab tab)
1327 /// Argument for chat notification events
1329 public class ChatNotificationEventArgs : EventArgs
1331 public string Message;
1332 public ChatBufferTextStyle Style;
1334 public ChatNotificationEventArgs(string message, ChatBufferTextStyle style)
1342 /// Element of list of nearby avatars
1344 public class NearbyAvatar
1346 public UUID ID { get; set; }
1347 public string Name { get; set; }