OSDN Git Service

RAD-497 minimize to tray
[radegast/radegast.git] / Radegast / GUI / Dialogs / MainForm.cs
index 6dbd0e1..d4be299 100644 (file)
@@ -1,6 +1,6 @@
 // 
 // Radegast Metaverse Client
-// Copyright (c) 2009-2010, Radegast Development Team
+// Copyright (c) 2009-2014, Radegast Development Team
 // All rights reserved.
 // 
 // Redistribution and use in source and binary forms, with or without
@@ -34,7 +34,14 @@ using System.Drawing;
 using System.Text;
 using System.Text.RegularExpressions;
 using System.Timers;
+#if (COGBOT_LIBOMV || USE_STHREADS)
+using ThreadPoolUtil;
+using Thread = ThreadPoolUtil.Thread;
+using ThreadPool = ThreadPoolUtil.ThreadPool;
+using Monitor = ThreadPoolUtil.Monitor;
+#endif
 using System.Threading;
+
 using System.Windows.Forms;
 using System.Resources;
 using System.IO;
@@ -51,6 +58,9 @@ namespace Radegast
         #region Public members
         public static ImageList ResourceImages = new ImageList();
         public static List<string> ImageNames = new List<string>();
+        public bool PreventParcelUpdate = false;
+        public delegate void ProfileHandlerDelegate(string agentName, UUID agentID);
+        public ProfileHandlerDelegate ShowAgentProfile;
 
         public TabsConsole TabConsole
         {
@@ -123,19 +133,20 @@ namespace Radegast
         private bool AutoPilotActive = false;
         private TransparentButton btnDialogNextControl;
         private MediaConsole mediaConsole;
+        private SlUriParser uriParser;
         #endregion
 
         #region Constructor and disposal
         public frmMain(RadegastInstance instance)
             : base(instance)
         {
-            GetSLTimeZone();
             InitializeComponent();
             Disposed += new EventHandler(frmMain_Disposed);
 
             this.instance = instance;
             this.instance.ClientChanged += new EventHandler<ClientChangedEventArgs>(instance_ClientChanged);
             netcom.NetcomSync = this;
+            ShowAgentProfile = ShowAgentProfileInternal;
 
             pnlDialog.Visible = false;
             btnDialogNextControl = new TransparentButton();
@@ -162,20 +173,11 @@ namespace Radegast
                 statusStrip1.LayoutStyle = ToolStripLayoutStyle.Table;
             }
 
-            // Config options
-            if (instance.GlobalSettings["transaction_notification_chat"].Type == OSDType.Unknown)
-                instance.GlobalSettings["transaction_notification_chat"] = OSD.FromBoolean(true);
-
-            if (instance.GlobalSettings["transaction_notification_dialog"].Type == OSDType.Unknown)
-                instance.GlobalSettings["transaction_notification_dialog"] = OSD.FromBoolean(true);
-
-            if (!instance.GlobalSettings.ContainsKey("minimize_to_tray"))
-                instance.GlobalSettings["minimize_to_tray"] = OSD.FromBoolean(false);
-
             // Callbacks
             netcom.ClientLoginStatus += new EventHandler<LoginProgressEventArgs>(netcom_ClientLoginStatus);
             netcom.ClientLoggedOut += new EventHandler(netcom_ClientLoggedOut);
             netcom.ClientDisconnected += new EventHandler<DisconnectedEventArgs>(netcom_ClientDisconnected);
+            instance.Names.NameUpdated += new EventHandler<UUIDNameReplyEventArgs>(Names_NameUpdated);
             RegisterClientEvents(client);
 
             InitializeStatusTimer();
@@ -186,12 +188,14 @@ namespace Radegast
         {
             client.Parcels.ParcelProperties += new EventHandler<ParcelPropertiesEventArgs>(Parcels_ParcelProperties);
             client.Self.MoneyBalanceReply += new EventHandler<MoneyBalanceReplyEventArgs>(Self_MoneyBalanceReply);
+            client.Self.MoneyBalance += new EventHandler<BalanceEventArgs>(Self_MoneyBalance);
         }
 
         private void UnregisterClientEvents(GridClient client)
         {
             client.Parcels.ParcelProperties -= new EventHandler<ParcelPropertiesEventArgs>(Parcels_ParcelProperties);
             client.Self.MoneyBalanceReply -= new EventHandler<MoneyBalanceReplyEventArgs>(Self_MoneyBalanceReply);
+            client.Self.MoneyBalance -= new EventHandler<BalanceEventArgs>(Self_MoneyBalance);
         }
 
         void instance_ClientChanged(object sender, ClientChangedEventArgs e)
@@ -209,15 +213,66 @@ namespace Radegast
                 netcom.ClientLoggedOut -= new EventHandler(netcom_ClientLoggedOut);
                 netcom.ClientDisconnected -= new EventHandler<DisconnectedEventArgs>(netcom_ClientDisconnected);
             }
+
             if (client != null)
             {
                 UnregisterClientEvents(client);
             }
+
+            if (instance != null && instance.Names != null)
+            {
+                instance.Names.NameUpdated -= new EventHandler<UUIDNameReplyEventArgs>(Names_NameUpdated);
+            }
+
             this.instance.CleanUp();
         }
         #endregion
 
         #region Event handlers
+        bool firstMoneyNotification = true;
+        void Self_MoneyBalance(object sender, BalanceEventArgs e)
+        {
+            int oldBalance = 0;
+            int.TryParse(tlblMoneyBalance.Text, out oldBalance);
+            int delta = Math.Abs(oldBalance - e.Balance);
+
+            if (firstMoneyNotification)
+            {
+                firstMoneyNotification = false;
+            }
+            else
+            {
+                if (delta > 50)
+                {
+                    if (oldBalance > e.Balance)
+                    {
+                        instance.MediaManager.PlayUISound(UISounds.MoneyIn);
+                    }
+                    else
+                    {
+                        instance.MediaManager.PlayUISound(UISounds.MoneyOut);
+                    }
+                }
+            }
+        }
+
+        void Names_NameUpdated(object sender, UUIDNameReplyEventArgs e)
+        {
+            if (!e.Names.ContainsKey(client.Self.AgentID)) return;
+
+            if (InvokeRequired)
+            {
+                if (IsHandleCreated || !instance.MonoRuntime)
+                {
+                    BeginInvoke(new MethodInvoker(() => Names_NameUpdated(sender, e)));
+                }
+                return;
+            }
+
+            RefreshWindowTitle();
+            RefreshStatusBar();
+        }
+
         void Self_MoneyBalanceReply(object sender, MoneyBalanceReplyEventArgs e)
         {
             if (!String.IsNullOrEmpty(e.Description))
@@ -232,6 +287,7 @@ namespace Radegast
         public void InitializeControls()
         {
             InitializeTabsConsole();
+            uriParser = new SlUriParser();
 
             if (instance.MediaManager.SoundSystemAvailable)
             {
@@ -253,7 +309,7 @@ namespace Radegast
             }
 
             InAutoReconnect = true;
-            frmReconnect dialog = new frmReconnect(instance, 120);
+            frmReconnect dialog = new frmReconnect(instance, instance.GlobalSettings["reconnect_time"]);
             dialog.ShowDialog(this);
             dialog.Dispose();
             dialog = null;
@@ -282,7 +338,7 @@ namespace Radegast
             {
                 if (InAutoReconnect)
                 {
-                    if (instance.GlobalSettings["auto_reconnect"].AsBoolean())
+                    if (instance.GlobalSettings["auto_reconnect"].AsBoolean() && e.FailReason != "tos")
                         BeginAutoReconnect();
                     else
                         InAutoReconnect = false;
@@ -291,7 +347,9 @@ namespace Radegast
             else if (e.Status == LoginStatus.Success)
             {
                 InAutoReconnect = false;
-                tbtnVoice.Enabled = disconnectToolStripMenuItem.Enabled =
+                reconnectToolStripMenuItem.Enabled = false;
+                loginToolStripMenuItem.Enabled = false;
+                tsb3D.Enabled = tbtnVoice.Enabled = disconnectToolStripMenuItem.Enabled =
                 tbtnGroups.Enabled = tbnObjects.Enabled = tbtnWorld.Enabled = tbnTools.Enabled = tmnuImport.Enabled =
                     tbtnFriends.Enabled = tbtnInventory.Enabled = tbtnSearch.Enabled = tbtnMap.Enabled = true;
 
@@ -302,11 +360,12 @@ namespace Radegast
 
         private void netcom_ClientLoggedOut(object sender, EventArgs e)
         {
-            tbtnVoice.Enabled = disconnectToolStripMenuItem.Enabled =
+            tsb3D.Enabled = tbtnVoice.Enabled = disconnectToolStripMenuItem.Enabled =
             tbtnGroups.Enabled = tbnObjects.Enabled = tbtnWorld.Enabled = tbnTools.Enabled = tmnuImport.Enabled =
                 tbtnFriends.Enabled = tbtnInventory.Enabled = tbtnSearch.Enabled = tbtnMap.Enabled = false;
 
             reconnectToolStripMenuItem.Enabled = true;
+            loginToolStripMenuItem.Enabled = true;
             InAutoReconnect = false;
 
             if (statusTimer != null)
@@ -318,6 +377,8 @@ namespace Radegast
 
         private void netcom_ClientDisconnected(object sender, DisconnectedEventArgs e)
         {
+            firstMoneyNotification = true;
+
             if (e.Reason == NetworkManager.DisconnectType.ClientInitiated) return;
             netcom_ClientLoggedOut(sender, EventArgs.Empty);
 
@@ -369,7 +430,7 @@ namespace Radegast
 
         void Parcels_ParcelProperties(object sender, ParcelPropertiesEventArgs e)
         {
-            if (e.Result != ParcelResult.Single) return;
+            if (PreventParcelUpdate || e.Result != ParcelResult.Single) return;
             if (InvokeRequired)
             {
                 BeginInvoke(new MethodInvoker(() => Parcels_ParcelProperties(sender, e)));
@@ -416,12 +477,13 @@ namespace Radegast
         {
             if (netcom.IsLoggedIn)
             {
-                tlblLoginName.Text = netcom.LoginOptions.FullName;
+                tlblLoginName.Text = instance.Names.Get(client.Self.AgentID, client.Self.Name);
                 tlblMoneyBalance.Text = client.Self.Balance.ToString();
                 icoHealth.Text = client.Self.Health.ToString() + "%";
 
+                var cs = client.Network.CurrentSim;
                 tlblRegionInfo.Text =
-                    client.Network.CurrentSim.Name +
+                    (cs == null ? "No region" : cs.Name) +
                     " (" + Math.Floor(client.Self.SimPosition.X).ToString() + ", " +
                     Math.Floor(client.Self.SimPosition.Y).ToString() + ", " +
                     Math.Floor(client.Self.SimPosition.Z).ToString() + ")";
@@ -445,12 +507,13 @@ namespace Radegast
 
         private void RefreshWindowTitle()
         {
+            string name = instance.Names.Get(client.Self.AgentID, client.Self.Name);
             StringBuilder sb = new StringBuilder();
             sb.Append("Radegast - ");
 
             if (netcom.IsLoggedIn)
             {
-                sb.Append("[" + netcom.LoginOptions.FullName + "]");
+                sb.Append("[" + name + "]");
 
                 if (instance.State.IsAway)
                 {
@@ -474,6 +537,14 @@ namespace Radegast
             }
 
             this.Text = sb.ToString();
+
+            // When minimized to tray, update tray tool tip also
+            if (WindowState == FormWindowState.Minimized && instance.GlobalSettings["minimize_to_tray"])
+            {
+                trayIcon.Text = sb.ToString();
+                ctxTrayMenuLabel.Text = sb.ToString();
+            }
+
             sb = null;
         }
 
@@ -506,6 +577,22 @@ namespace Radegast
 
         private void frmMain_KeyDown(object sender, KeyEventArgs e)
         {
+            // Ctrl-Alt-Shift-H Say "Hippos!" in chat
+            if (e.Modifiers == (Keys.Control | Keys.Shift | Keys.Alt) && e.KeyCode == Keys.H)
+            {
+                e.Handled = e.SuppressKeyPress = true;
+                netcom.ChatOut("Hippos!", ChatType.Normal, 0);
+                return;
+            }
+
+            // Ctrl-Shift-1 (sim/parcel info)
+            if (e.Modifiers == (Keys.Control | Keys.Shift) && e.KeyCode == Keys.D1)
+            {
+                e.Handled = e.SuppressKeyPress = true;
+                DisplayRegionParcelConsole();
+                return;
+            }
+
             // Ctrl-W: Close tab
             if (e.Modifiers == Keys.Control && e.KeyCode == Keys.W)
             {
@@ -639,6 +726,12 @@ namespace Radegast
                     }
                 }
                 StartUpdateCheck(false);
+
+                if (instance.PlainColors)
+                {
+                    pnlDialog.BackColor = System.Drawing.Color.FromArgb(120, 220, 255);
+                }
+
             }
         }
         #endregion
@@ -647,7 +740,7 @@ namespace Radegast
 
         private Dictionary<UUID, frmProfile> shownProfiles = new Dictionary<UUID, frmProfile>();
 
-        public void ShowAgentProfile(string name, UUID agentID)
+        void ShowAgentProfileInternal(string name, UUID agentID)
         {
             lock (shownProfiles)
             {
@@ -680,6 +773,14 @@ namespace Radegast
 
         private Dictionary<UUID, frmGroupInfo> shownGroupProfiles = new Dictionary<UUID, frmGroupInfo>();
 
+        public void ShowGroupProfile(UUID id)
+        {
+            ShowGroupProfile(new OpenMetaverse.Group()
+            {
+                ID = id,
+            });
+        }
+
         public void ShowGroupProfile(AvatarGroup group)
         {
             ShowGroupProfile(new OpenMetaverse.Group()
@@ -693,6 +794,12 @@ namespace Radegast
 
         public void ShowGroupProfile(OpenMetaverse.Group group)
         {
+            if (InvokeRequired)
+            {
+                BeginInvoke(new MethodInvoker(() => ShowGroupProfile(group)));
+                return;
+            }
+
             lock (shownGroupProfiles)
             {
                 frmGroupInfo profile = null;
@@ -722,6 +829,12 @@ namespace Radegast
             }
         }
 
+        public bool ProcessSecondlifeURI(string link)
+        {
+            uriParser.ExecuteLink(link);
+            return true;
+        }
+
         public void ProcessLink(string link)
         {
             ProcessLink(link, false);
@@ -729,6 +842,17 @@ namespace Radegast
 
         public bool ProcessLink(string link, bool onlyMap)
         {
+            var pos = link.IndexOf(RRichTextBox.LinkSeparator);
+            if (pos > 0)
+            {
+                link = link.Substring(pos + 1);
+            }
+
+            if (link.StartsWith("secondlife://") || link.StartsWith("[secondlife://"))
+            {
+                return ProcessSecondlifeURI(link);
+            }
+
             if (!link.Contains("://"))
             {
                 link = "http://" + link;
@@ -797,6 +921,8 @@ namespace Radegast
                 return;
             }
 
+            Control active = TabsConsole.FindFocusedControl(this);
+
             FormFlash.StartFlash(this);
             pnlDialog.Visible = true;
             pnlDialog.BringToFront();
@@ -815,6 +941,11 @@ namespace Radegast
             ResizeNotificationByControl(control);
 
             btnDialogNextControl.Visible = notifications.Count > 1;
+
+            if (active != null)
+            {
+                active.Focus();
+            }
         }
 
         public void RemoveNotification(Control control)
@@ -899,7 +1030,8 @@ namespace Radegast
 
         private void importObjectToolStripMenuItem_Click(object sender, EventArgs e)
         {
-            PrimDeserializer.ImportFromFile(client);
+            //PrimDeserializer.ImportFromFile(client);
+            DisplayImportConsole();
         }
 
         private void autopilotToolStripMenuItem_Click(object sender, EventArgs e)
@@ -943,14 +1075,44 @@ namespace Radegast
 
         }
 
+        int filesDeleted;
+
+        private void deleteFolder(DirectoryInfo dir)
+        {
+            foreach (var file in dir.GetFiles())
+            {
+                try 
+                {
+                    file.Delete();
+                    filesDeleted++;
+                }
+                catch { }
+            }
+
+            foreach (var subDir in dir.GetDirectories())
+            {
+                deleteFolder(subDir);
+            }
+
+            try { dir.Delete(); }
+            catch { }
+        }
+
         private void cleanCacheToolStripMenuItem_Click(object sender, EventArgs e)
         {
-            client.Assets.Cache.Clear();
+            WorkPool.QueueUserWorkItem(sync =>
+            {
+                filesDeleted = 0;
+                try { deleteFolder(new DirectoryInfo(client.Settings.ASSET_CACHE_DIR)); }
+                catch { }
+                Logger.DebugLog("Wiped out " + filesDeleted + " files from the cache directory.");
+            });
+            instance.Names.CleanCache();
         }
 
         private void rebakeTexturesToolStripMenuItem_Click(object sender, EventArgs e)
         {
-            client.Appearance.RequestSetAppearance(true);
+            instance.COF.RebakeTextures();
         }
 
         public void MapToCurrentLocation()
@@ -1046,39 +1208,10 @@ namespace Radegast
             );
         }
 
-        private TimeZoneInfo SLTime;
-
-        private void GetSLTimeZone()
-        {
-            try
-            {
-                foreach (TimeZoneInfo tz in TimeZoneInfo.GetSystemTimeZones())
-                {
-                    if (tz.Id == "Pacific Standard Time" || tz.Id == "America/Los_Angeles")
-                    {
-                        SLTime = tz;
-                        break;
-                    }
-                }
-            }
-            catch (Exception) { }
-        }
 
         private void timerWorldClock_Tick(object sender, EventArgs e)
         {
-            DateTime now;
-            try
-            {
-                if (SLTime != null)
-                    now = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, SLTime);
-                else
-                    now = DateTime.UtcNow.AddHours(-7);
-            }
-            catch (Exception)
-            {
-                now = DateTime.UtcNow.AddHours(-7);
-            }
-            lblTime.Text = now.ToString("h:mm tt", System.Globalization.CultureInfo.InvariantCulture);
+            lblTime.Text = instance.GetWorldTime().ToString("h:mm tt", System.Globalization.CultureInfo.InvariantCulture);
         }
 
         private void reportBugsToolStripMenuItem_Click(object sender, EventArgs e)
@@ -1086,6 +1219,11 @@ namespace Radegast
             ProcessLink("http://jira.openmetaverse.org/browse/RAD");
         }
 
+        private void accessibilityGuideToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            ProcessLink("http://radegast.org/wiki/Accessibility_Guide");
+        }
+
         private void aboutRadegastToolStripMenuItem_Click(object sender, EventArgs e)
         {
             (new frmAbout(instance)).ShowDialog();
@@ -1262,6 +1400,8 @@ namespace Radegast
 
         private void tbtnMap_Click(object sender, EventArgs e)
         {
+            if (MapTab == null) return; // too soon!
+
             ToggleHidden("map");
             if (!MapTab.Hidden)
                 MapToCurrentLocation();
@@ -1275,7 +1415,10 @@ namespace Radegast
 
         private void reconnectToolStripMenuItem_Click(object sender, EventArgs e)
         {
-            instance.Reconnect();
+            if (!client.Network.Connected)
+            {
+                instance.Reconnect();
+            }
         }
 
         private frmKeyboardShortcuts keyboardShortcutsForm = null;
@@ -1309,33 +1452,9 @@ namespace Radegast
             }
         }
 
-        int nr_reg = 0;
-        int nr_agent = 0;
-
         // Menu item for testing out stuff
         private void testToolStripMenuItem_Click(object sender, EventArgs e)
         {
-            if (nr_reg > 0)
-            {
-                Logger.Log("Number of regions: " + nr_reg.ToString() + " agents: " + nr_agent.ToString(), Helpers.LogLevel.Info);
-                nr_reg = 0;
-                nr_agent = 0;
-                client.Grid.GridRegion -= new EventHandler<GridRegionEventArgs>(Grid_GridRegion);
-                return;
-            }
-
-            client.Grid.GridRegion += new EventHandler<GridRegionEventArgs>(Grid_GridRegion);
-            client.Grid.RequestMainlandSims(GridLayerType.Objects);
-        }
-
-        void Grid_GridRegion(object sender, GridRegionEventArgs e)
-        {
-            nr_reg++;
-            if ((nr_reg % 100) == 0)
-            {
-                nr_agent += e.Region.Agents;
-                Logger.Log("Number of regions: " + nr_reg.ToString() + " agents: " + nr_agent.ToString(), Helpers.LogLevel.Info);
-            }
         }
 
         private void reloadInventoryToolStripMenuItem_Click(object sender, EventArgs e)
@@ -1360,8 +1479,14 @@ namespace Radegast
         {
             if (WindowState == FormWindowState.Minimized && instance.GlobalSettings["minimize_to_tray"].AsBoolean())
             {
+                if (TabConsole.TabExists("scene_window") && !TabConsole.Tabs["scene_window"].Detached)
+                {
+                    TabConsole.Tabs["scene_window"].Close();
+                }
                 ShowInTaskbar = false;
                 trayIcon.Visible = true;
+                trayIcon.BalloonTipText = "Radegast is runnig in the background";
+                trayIcon.ShowBalloonTip(2000);
             }
         }
 
@@ -1387,7 +1512,208 @@ namespace Radegast
             TabConsole.DisplayNotificationInChat("Teleporting home...");
             client.Self.RequestTeleport(UUID.Zero);
         }
+
+        private void stopAllAnimationsToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            instance.State.StopAllAnimations();
+        }
+
+        public void DisplayRegionParcelConsole()
+        {
+            if (tabsConsole.TabExists("current region info"))
+            {
+                tabsConsole.Tabs["current region info"].Select();
+                (tabsConsole.Tabs["current region info"].Control as RegionInfo).UpdateDisplay();
+            }
+            else
+            {
+                tabsConsole.AddTab("current region info", "Region info", new RegionInfo(instance));
+                tabsConsole.Tabs["current region info"].Select();
+            }
+        }
+
+        public void DisplayExportConsole(uint localID)
+        {
+            if (InvokeRequired)
+            {
+                if (IsHandleCreated || !instance.MonoRuntime)
+                    BeginInvoke(new MethodInvoker(() => DisplayExportConsole(localID)));
+                return;
+            }
+
+            if (tabsConsole.TabExists("export console"))
+            {
+                tabsConsole.Tabs["export console"].Close();
+            }
+            RadegastTab tab = tabsConsole.AddTab("export console", "Export Object", new ExportConsole(client, localID));
+            tab.Select();
+        }
+
+        public void DisplayImportConsole()
+        {
+            if (TabConsole.TabExists("import console"))
+            {
+                TabConsole.Tabs["import console"].Select();
+            }
+            else
+            {
+                RadegastTab tab = tabsConsole.AddTab("import console", "Import Object", new ImportConsole(client));
+                tab.AllowClose = false;
+                tab.AllowHide = true;
+                tab.Select();
+            }
+        }
+
+        public void DisplayColladaConsole(Primitive prim)
+        {
+            if (InvokeRequired)
+            {
+                if (IsHandleCreated || !instance.MonoRuntime)
+                    BeginInvoke(new MethodInvoker(() => DisplayColladaConsole(prim)));
+                return;
+            }
+
+            if (tabsConsole.TabExists("collada console"))
+            {
+                tabsConsole.Tabs["collada console"].Close();
+            }
+            RadegastTab tab = tabsConsole.AddTab("collada console", "Export Collada", new ExportCollada(instance, prim));
+            tab.Select();
+        }
+
+        private void regionParcelToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            DisplayRegionParcelConsole();
+        }
+
+        private void tlblParcel_Click(object sender, EventArgs e)
+        {
+            if (!client.Network.Connected) return;
+            DisplayRegionParcelConsole();
+        }
+
+        private void changeMyDisplayNameToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            if (!client.Avatars.DisplayNamesAvailable())
+            {
+                tabsConsole.DisplayNotificationInChat("This grid does not support display names.", ChatBufferTextStyle.Error);
+                return;
+            }
+
+            var dlg = new DisplayNameChange(instance);
+            dlg.ShowDialog();
+        }
+
+        private void muteListToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            if (!tabsConsole.TabExists("mute list console"))
+            {
+                tabsConsole.AddTab("mute list console", "Mute list", new MuteList(instance));
+            }
+            tabsConsole.Tabs["mute list console"].Select();
+        }
+
+        private void uploadImageToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            if (!tabsConsole.TabExists("image upload console"))
+            {
+                tabsConsole.AddTab("image upload console", "Upload image", new ImageUploadConsole(instance));
+            }
+            tabsConsole.Tabs["image upload console"].Select();
+        }
         #endregion
 
+        private void myAttachmentsToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            Avatar av = client.Network.CurrentSim.ObjectsAvatars.Find((Avatar a) => { return a.ID == client.Self.AgentID; });
+
+            if (av == null)
+            {
+                tabsConsole.DisplayNotificationInChat("Unable to find my avatar!", ChatBufferTextStyle.Error);
+                return;
+            }
+
+            if (!instance.TabConsole.TabExists("AT: " + av.ID.ToString()))
+            {
+                instance.TabConsole.AddTab("AT: " + av.ID.ToString(), "My Attachments", new AttachmentTab(instance, av));
+            }
+            instance.TabConsole.SelectTab("AT: " + av.ID.ToString());
+
+        }
+
+        private void tsb3D_Click(object sender, EventArgs e)
+        {
+            if (instance.TabConsole.TabExists("scene_window"))
+            {
+                instance.TabConsole.Tabs["scene_window"].Select();
+            }
+            else
+            {
+                var control = new Rendering.SceneWindow(instance);
+                control.Dock = DockStyle.Fill;
+                instance.TabConsole.AddTab("scene_window", "Scene Viewer", control);
+                instance.TabConsole.Tabs["scene_window"].Floater = false;
+                instance.TabConsole.Tabs["scene_window"].CloseOnDetachedClose = true;
+                control.RegisterTabEvents();
+
+                if (instance.GlobalSettings["scene_window_docked"])
+                {
+                    instance.TabConsole.Tabs["scene_window"].Select();
+                }
+                else
+                {
+                    instance.TabConsole.Tabs["scene_window"].Detach(instance);
+                }
+            }
+        }
+
+        private void loginToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            // We are logging in without exiting the client
+            // Mark last run as successful
+            instance.MarkEndExecution();
+            TabConsole.InitializeMainTab();
+            TabConsole.Tabs["login"].Select();
+        }
+
+        private void setMaturityLevel(string level)
+        {
+            client.Self.SetAgentAccess(level, res =>
+            {
+                if (res.Success)
+                {
+                    tabsConsole.DisplayNotificationInChat("Successfully changed maturity access level to " + res.NewLevel);
+                }
+                else
+                {
+                    tabsConsole.DisplayNotificationInChat("Failed to change maturity access level.", ChatBufferTextStyle.Error);
+                }
+            });
+        }
+
+        private void pGToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            setMaturityLevel("PG");
+        }
+
+        private void matureToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            setMaturityLevel("M");
+        }
+
+        private void adultToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            setMaturityLevel("A");
+        }
+
+        private void uploadmeshToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            if (!tabsConsole.TabExists("mesh upload console"))
+            {
+                tabsConsole.AddTab("mesh upload console", "Upload mesh", new MeshUploadConsole(instance));
+            }
+            tabsConsole.Tabs["mesh upload console"].Select();
+        }
+
     }
 }
\ No newline at end of file