OSDN Git Service

RAD-348: Don't steal typing focus on new chat session
[radegast/radegast.git] / Radegast / GUI / Dialogs / MainForm.cs
1 // 
2 // Radegast Metaverse Client
3 // Copyright (c) 2009-2012, Radegast Development Team
4 // All rights reserved.
5 // 
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
8 // 
9 //     * Redistributions of source code must retain the above copyright notice,
10 //       this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above copyright
12 //       notice, this list of conditions and the following disclaimer in the
13 //       documentation and/or other materials provided with the distribution.
14 //     * Neither the name of the application "Radegast", nor the names of its
15 //       contributors may be used to endorse or promote products derived from
16 //       this software without specific prior written permission.
17 // 
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 //
29 // $Id$
30 //
31 using System;
32 using System.Collections.Generic;
33 using System.Drawing;
34 using System.Text;
35 using System.Text.RegularExpressions;
36 using System.Timers;
37 using System.Threading;
38 using System.Windows.Forms;
39 using System.Resources;
40 using System.IO;
41 using System.Web;
42 using Radegast.Netcom;
43 using OpenMetaverse;
44 using OpenMetaverse.StructuredData;
45 using OpenMetaverse.Assets;
46
47 namespace Radegast
48 {
49     public partial class frmMain : RadegastForm
50     {
51         #region Public members
52         public static ImageList ResourceImages = new ImageList();
53         public static List<string> ImageNames = new List<string>();
54         public bool PreventParcelUpdate = false;
55         public delegate void ProfileHandlerDelegate(string agentName, UUID agentID);
56         public ProfileHandlerDelegate ShowAgentProfile;
57
58         public TabsConsole TabConsole
59         {
60             get { return tabsConsole; }
61         }
62
63         public MapConsole WorldMap
64         {
65             get
66             {
67                 if (MapTab != null)
68                 {
69                     return (MapConsole)MapTab.Control;
70                 }
71                 return null;
72             }
73         }
74
75         public RadegastTab MapTab
76         {
77             get
78             {
79                 if (tabsConsole.TabExists("map"))
80                 {
81                     return tabsConsole.Tabs["map"];
82                 }
83                 else
84                 {
85                     return null;
86                 }
87             }
88         }
89
90         public MediaConsole MediaConsole { get { return mediaConsole; } }
91
92         /// <summary>
93         /// Drop down that contains the tools menu
94         /// </summary>
95         public ToolStripDropDownButton ToolsMenu
96         {
97             get { return tbnTools; }
98         }
99
100         /// <summary>
101         /// Dropdown that contains the heelp menu
102         /// </summary>
103         public ToolStripDropDownButton HelpMenu
104         {
105             get { return tbtnHelp; }
106         }
107
108         /// <summary>
109         /// Drop down that contants the plugins menu. Make sure to set it Visible if
110         /// you add items to this menu, it's hidden by default
111         /// </summary>
112         public ToolStripDropDownButton PluginsMenu
113         {
114             get { return tbnPlugins; }
115         }
116
117         #endregion
118
119         #region Private members
120         private RadegastInstance instance;
121         private GridClient client { get { return instance.Client; } }
122         private RadegastNetcom netcom { get { return instance.Netcom; } }
123         private TabsConsole tabsConsole;
124         private System.Timers.Timer statusTimer;
125         private AutoPilot ap;
126         private bool AutoPilotActive = false;
127         private TransparentButton btnDialogNextControl;
128         private MediaConsole mediaConsole;
129         #endregion
130
131         #region Constructor and disposal
132         public frmMain(RadegastInstance instance)
133             : base(instance)
134         {
135             InitializeComponent();
136             Disposed += new EventHandler(frmMain_Disposed);
137
138             this.instance = instance;
139             this.instance.ClientChanged += new EventHandler<ClientChangedEventArgs>(instance_ClientChanged);
140             netcom.NetcomSync = this;
141             ShowAgentProfile = ShowAgentProfileInternal;
142
143             pnlDialog.Visible = false;
144             btnDialogNextControl = new TransparentButton();
145             pnlDialog.Controls.Add(btnDialogNextControl);
146             pnlDialog.Top = 0;
147
148             btnDialogNextControl.Size = new Size(35, 20);
149             btnDialogNextControl.BackColor = Color.Transparent;
150             btnDialogNextControl.ForeColor = Color.Gold;
151             btnDialogNextControl.FlatAppearance.BorderSize = 0;
152             btnDialogNextControl.FlatStyle = FlatStyle.Flat;
153             btnDialogNextControl.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
154             btnDialogNextControl.Text = ">>";
155             btnDialogNextControl.Font = new Font(btnDialogNextControl.Font, FontStyle.Bold);
156             btnDialogNextControl.Margin = new Padding(0);
157             btnDialogNextControl.Padding = new Padding(0);
158             btnDialogNextControl.UseVisualStyleBackColor = false;
159             btnDialogNextControl.Top = btnDialogNextControl.Parent.ClientSize.Height - btnDialogNextControl.Size.Height;
160             btnDialogNextControl.Left = btnDialogNextControl.Parent.ClientSize.Width - btnDialogNextControl.Size.Width;
161             btnDialogNextControl.Click += new EventHandler(btnDialogNextControl_Click);
162
163             if (instance.MonoRuntime)
164             {
165                 statusStrip1.LayoutStyle = ToolStripLayoutStyle.Table;
166             }
167
168             // Callbacks
169             netcom.ClientLoginStatus += new EventHandler<LoginProgressEventArgs>(netcom_ClientLoginStatus);
170             netcom.ClientLoggedOut += new EventHandler(netcom_ClientLoggedOut);
171             netcom.ClientDisconnected += new EventHandler<DisconnectedEventArgs>(netcom_ClientDisconnected);
172             instance.Names.NameUpdated += new EventHandler<UUIDNameReplyEventArgs>(Names_NameUpdated);
173             RegisterClientEvents(client);
174
175             InitializeStatusTimer();
176             RefreshWindowTitle();
177         }
178
179         private void RegisterClientEvents(GridClient client)
180         {
181             client.Parcels.ParcelProperties += new EventHandler<ParcelPropertiesEventArgs>(Parcels_ParcelProperties);
182             client.Self.MoneyBalanceReply += new EventHandler<MoneyBalanceReplyEventArgs>(Self_MoneyBalanceReply);
183             client.Self.MoneyBalance += new EventHandler<BalanceEventArgs>(Self_MoneyBalance);
184         }
185
186         private void UnregisterClientEvents(GridClient client)
187         {
188             client.Parcels.ParcelProperties -= new EventHandler<ParcelPropertiesEventArgs>(Parcels_ParcelProperties);
189             client.Self.MoneyBalanceReply -= new EventHandler<MoneyBalanceReplyEventArgs>(Self_MoneyBalanceReply);
190             client.Self.MoneyBalance -= new EventHandler<BalanceEventArgs>(Self_MoneyBalance);
191         }
192
193         void instance_ClientChanged(object sender, ClientChangedEventArgs e)
194         {
195             UnregisterClientEvents(e.OldClient);
196             RegisterClientEvents(client);
197         }
198
199         void frmMain_Disposed(object sender, EventArgs e)
200         {
201             if (netcom != null)
202             {
203                 netcom.NetcomSync = null;
204                 netcom.ClientLoginStatus -= new EventHandler<LoginProgressEventArgs>(netcom_ClientLoginStatus);
205                 netcom.ClientLoggedOut -= new EventHandler(netcom_ClientLoggedOut);
206                 netcom.ClientDisconnected -= new EventHandler<DisconnectedEventArgs>(netcom_ClientDisconnected);
207             }
208
209             if (client != null)
210             {
211                 UnregisterClientEvents(client);
212             }
213
214             if (instance != null && instance.Names != null)
215             {
216                 instance.Names.NameUpdated -= new EventHandler<UUIDNameReplyEventArgs>(Names_NameUpdated);
217             }
218
219             this.instance.CleanUp();
220         }
221         #endregion
222
223         #region Event handlers
224         bool firstMoneyNotification = true;
225         void Self_MoneyBalance(object sender, BalanceEventArgs e)
226         {
227             int oldBalance = 0;
228             int.TryParse(tlblMoneyBalance.Text, out oldBalance);
229             int delta = Math.Abs(oldBalance - e.Balance);
230
231             if (firstMoneyNotification)
232             {
233                 firstMoneyNotification = false;
234             }
235             else
236             {
237                 if (delta > 50)
238                 {
239                     if (oldBalance > e.Balance)
240                     {
241                         instance.MediaManager.PlayUISound(UISounds.MoneyIn);
242                     }
243                     else
244                     {
245                         instance.MediaManager.PlayUISound(UISounds.MoneyOut);
246                     }
247                 }
248             }
249         }
250
251         void Names_NameUpdated(object sender, UUIDNameReplyEventArgs e)
252         {
253             if (!e.Names.ContainsKey(client.Self.AgentID)) return;
254
255             if (InvokeRequired)
256             {
257                 if (IsHandleCreated || !instance.MonoRuntime)
258                 {
259                     BeginInvoke(new MethodInvoker(() => Names_NameUpdated(sender, e)));
260                 }
261                 return;
262             }
263
264             RefreshWindowTitle();
265             RefreshStatusBar();
266         }
267
268         void Self_MoneyBalanceReply(object sender, MoneyBalanceReplyEventArgs e)
269         {
270             if (!String.IsNullOrEmpty(e.Description))
271             {
272                 if (instance.GlobalSettings["transaction_notification_dialog"].AsBoolean())
273                     AddNotification(new ntfGeneric(instance, e.Description));
274                 if (instance.GlobalSettings["transaction_notification_chat"].AsBoolean())
275                     TabConsole.DisplayNotificationInChat(e.Description);
276             }
277         }
278
279         public void InitializeControls()
280         {
281             InitializeTabsConsole();
282
283             if (instance.MediaManager.SoundSystemAvailable)
284             {
285                 mediaConsole = new MediaConsole(instance);
286                 tbtnMedia.Visible = true;
287             }
288         }
289
290         public bool InAutoReconnect { get; set; }
291
292         private void DisplayAutoReconnectForm()
293         {
294             if (IsDisposed) return;
295
296             if (InvokeRequired)
297             {
298                 BeginInvoke(new MethodInvoker(DisplayAutoReconnectForm));
299                 return;
300             }
301
302             InAutoReconnect = true;
303             frmReconnect dialog = new frmReconnect(instance, instance.GlobalSettings["reconnect_time"]);
304             dialog.ShowDialog(this);
305             dialog.Dispose();
306             dialog = null;
307         }
308
309         public void BeginAutoReconnect()
310         {
311             // Sleep for 3 seconds on a separate thread while things unwind on
312             // disconnect, since ShowDialog() blocks GUI thread
313             (new Thread(new ThreadStart(() =>
314                 {
315                     System.Threading.Thread.Sleep(3000);
316                     DisplayAutoReconnectForm();
317                 }
318                 ))
319                 {
320                     Name = "Reconnect Delay Thread",
321                     IsBackground = true
322                 }
323             ).Start();
324         }
325
326         private void netcom_ClientLoginStatus(object sender, LoginProgressEventArgs e)
327         {
328             if (e.Status == LoginStatus.Failed)
329             {
330                 if (InAutoReconnect)
331                 {
332                     if (instance.GlobalSettings["auto_reconnect"].AsBoolean())
333                         BeginAutoReconnect();
334                     else
335                         InAutoReconnect = false;
336                 }
337             }
338             else if (e.Status == LoginStatus.Success)
339             {
340                 InAutoReconnect = false;
341                 reconnectToolStripMenuItem.Enabled = false;
342                 tsb3D.Enabled = tbtnVoice.Enabled = disconnectToolStripMenuItem.Enabled =
343                 tbtnGroups.Enabled = tbnObjects.Enabled = tbtnWorld.Enabled = tbnTools.Enabled = tmnuImport.Enabled =
344                     tbtnFriends.Enabled = tbtnInventory.Enabled = tbtnSearch.Enabled = tbtnMap.Enabled = true;
345
346                 statusTimer.Start();
347                 RefreshWindowTitle();
348             }
349         }
350
351         private void netcom_ClientLoggedOut(object sender, EventArgs e)
352         {
353             tsb3D.Enabled = tbtnVoice.Enabled = disconnectToolStripMenuItem.Enabled =
354             tbtnGroups.Enabled = tbnObjects.Enabled = tbtnWorld.Enabled = tbnTools.Enabled = tmnuImport.Enabled =
355                 tbtnFriends.Enabled = tbtnInventory.Enabled = tbtnSearch.Enabled = tbtnMap.Enabled = false;
356
357             reconnectToolStripMenuItem.Enabled = true;
358             InAutoReconnect = false;
359
360             if (statusTimer != null)
361                 statusTimer.Stop();
362
363             RefreshStatusBar();
364             RefreshWindowTitle();
365         }
366
367         private void netcom_ClientDisconnected(object sender, DisconnectedEventArgs e)
368         {
369             firstMoneyNotification = true;
370
371             if (e.Reason == NetworkManager.DisconnectType.ClientInitiated) return;
372             netcom_ClientLoggedOut(sender, EventArgs.Empty);
373
374             if (instance.GlobalSettings["auto_reconnect"].AsBoolean())
375             {
376                 BeginAutoReconnect();
377             }
378         }
379
380         private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
381         {
382             if (statusTimer != null)
383             {
384                 statusTimer.Stop();
385                 statusTimer.Dispose();
386                 statusTimer = null;
387             }
388
389             if (mediaConsole != null)
390             {
391                 if (tabsConsole.TabExists("media"))
392                 {
393                     tabsConsole.Tabs["media"].AllowClose = true;
394                     tabsConsole.Tabs["media"].Close();
395                 }
396                 else
397                 {
398                     mediaConsole.Dispose();
399                 }
400                 mediaConsole = null;
401             }
402
403             if (netcom.IsLoggedIn)
404             {
405                 Thread saveInvToDisk = new Thread(new ThreadStart(
406                     delegate()
407                     {
408                         client.Inventory.Store.SaveToDisk(instance.InventoryCacheFileName);
409                     }));
410                 saveInvToDisk.Name = "Save inventory to disk";
411                 saveInvToDisk.Start();
412
413                 netcom.Logout();
414             }
415         }
416         #endregion
417
418         # region Update status
419
420         void Parcels_ParcelProperties(object sender, ParcelPropertiesEventArgs e)
421         {
422             if (PreventParcelUpdate || e.Result != ParcelResult.Single) return;
423             if (InvokeRequired)
424             {
425                 BeginInvoke(new MethodInvoker(() => Parcels_ParcelProperties(sender, e)));
426                 return;
427             }
428
429             Parcel parcel = instance.State.Parcel = e.Parcel;
430
431             tlblParcel.Text = parcel.Name;
432             tlblParcel.ToolTipText = parcel.Desc;
433
434             if ((parcel.Flags & ParcelFlags.AllowFly) != ParcelFlags.AllowFly)
435                 icoNoFly.Visible = true;
436             else
437                 icoNoFly.Visible = false;
438
439             if ((parcel.Flags & ParcelFlags.CreateObjects) != ParcelFlags.CreateObjects)
440                 icoNoBuild.Visible = true;
441             else
442                 icoNoBuild.Visible = false;
443
444             if ((parcel.Flags & ParcelFlags.AllowOtherScripts) != ParcelFlags.AllowOtherScripts)
445                 icoNoScript.Visible = true;
446             else
447                 icoNoScript.Visible = false;
448
449             if ((parcel.Flags & ParcelFlags.RestrictPushObject) == ParcelFlags.RestrictPushObject)
450                 icoNoPush.Visible = true;
451             else
452                 icoNoPush.Visible = false;
453
454             if ((parcel.Flags & ParcelFlags.AllowDamage) == ParcelFlags.AllowDamage)
455                 icoHealth.Visible = true;
456             else
457                 icoHealth.Visible = false;
458
459             if ((parcel.Flags & ParcelFlags.AllowVoiceChat) != ParcelFlags.AllowVoiceChat)
460                 icoNoVoice.Visible = true;
461             else
462                 icoNoVoice.Visible = false;
463         }
464
465         private void RefreshStatusBar()
466         {
467             if (netcom.IsLoggedIn)
468             {
469                 tlblLoginName.Text = instance.Names.Get(client.Self.AgentID, client.Self.Name);
470                 tlblMoneyBalance.Text = client.Self.Balance.ToString();
471                 icoHealth.Text = client.Self.Health.ToString() + "%";
472
473                 var cs = client.Network.CurrentSim;
474                 tlblRegionInfo.Text =
475                     (cs == null ? "No region" : cs.Name) +
476                     " (" + Math.Floor(client.Self.SimPosition.X).ToString() + ", " +
477                     Math.Floor(client.Self.SimPosition.Y).ToString() + ", " +
478                     Math.Floor(client.Self.SimPosition.Z).ToString() + ")";
479             }
480             else
481             {
482                 tlblLoginName.Text = "Offline";
483                 tlblMoneyBalance.Text = "0";
484                 icoHealth.Text = "0%";
485                 tlblRegionInfo.Text = "No Region";
486                 tlblParcel.Text = "No Parcel";
487
488                 icoHealth.Visible = false;
489                 icoNoBuild.Visible = false;
490                 icoNoFly.Visible = false;
491                 icoNoPush.Visible = false;
492                 icoNoScript.Visible = false;
493                 icoNoVoice.Visible = false;
494             }
495         }
496
497         private void RefreshWindowTitle()
498         {
499             string name = instance.Names.Get(client.Self.AgentID, client.Self.Name);
500             StringBuilder sb = new StringBuilder();
501             sb.Append("Radegast - ");
502
503             if (netcom.IsLoggedIn)
504             {
505                 sb.Append("[" + name + "]");
506
507                 if (instance.State.IsAway)
508                 {
509                     sb.Append(" - Away");
510                     if (instance.State.IsBusy) sb.Append(", Busy");
511                 }
512                 else if (instance.State.IsBusy)
513                 {
514                     sb.Append(" - Busy");
515                 }
516
517                 if (instance.State.IsFollowing)
518                 {
519                     sb.Append(" - Following ");
520                     sb.Append(instance.State.FollowName);
521                 }
522             }
523             else
524             {
525                 sb.Append("Logged Out");
526             }
527
528             this.Text = sb.ToString();
529
530             // When minimized to tray, update tray tool tip also
531             if (WindowState == FormWindowState.Minimized && instance.GlobalSettings["minimize_to_tray"])
532             {
533                 trayIcon.Text = sb.ToString();
534                 ctxTrayMenuLabel.Text = sb.ToString();
535             }
536
537             sb = null;
538         }
539
540         private void InitializeStatusTimer()
541         {
542             statusTimer = new System.Timers.Timer(250);
543             statusTimer.SynchronizingObject = this;
544             statusTimer.Elapsed += new ElapsedEventHandler(statusTimer_Elapsed);
545         }
546
547         private void statusTimer_Elapsed(object sender, ElapsedEventArgs e)
548         {
549             // Mono sometimes fires timer after is's disposed
550             try
551             {
552                 RefreshWindowTitle();
553                 RefreshStatusBar();
554             }
555             catch { }
556         }
557         #endregion
558
559         #region Initialization, configuration, and key shortcuts
560         private void InitializeTabsConsole()
561         {
562             tabsConsole = new TabsConsole(instance);
563             tabsConsole.Dock = DockStyle.Fill;
564             toolStripContainer1.ContentPanel.Controls.Add(tabsConsole);
565         }
566
567         private void frmMain_KeyDown(object sender, KeyEventArgs e)
568         {
569             // Ctrl-Alt-Shift-H Say "Hippos!" in chat
570             if (e.Modifiers == (Keys.Control | Keys.Shift | Keys.Alt) && e.KeyCode == Keys.H)
571             {
572                 e.Handled = e.SuppressKeyPress = true;
573                 netcom.ChatOut("Hippos!", ChatType.Normal, 0);
574                 return;
575             }
576
577             // Ctrl-Shift-1 (sim/parcel info)
578             if (e.Modifiers == (Keys.Control | Keys.Shift) && e.KeyCode == Keys.D1)
579             {
580                 e.Handled = e.SuppressKeyPress = true;
581                 DisplayRegionParcelConsole();
582                 return;
583             }
584
585             // Ctrl-W: Close tab
586             if (e.Modifiers == Keys.Control && e.KeyCode == Keys.W)
587             {
588                 e.Handled = e.SuppressKeyPress = true;
589                 RadegastTab tab = tabsConsole.SelectedTab;
590
591                 if (tab.AllowClose)
592                 {
593                     tab.Close();
594                 }
595                 else if (tab.AllowHide)
596                 {
597                     tab.Hide();
598                 }
599
600                 return;
601             }
602
603             // Ctl-Shift-H: Teleport Home
604             if (e.Modifiers == (Keys.Control | Keys.Shift) && e.KeyCode == Keys.H)
605             {
606                 e.Handled = e.SuppressKeyPress = true;
607                 tmnuTeleportHome.PerformClick();
608                 return;
609             }
610
611             // Alt-Ctrl-D Open debug console
612             if (e.Modifiers == (Keys.Control | Keys.Alt) && e.KeyCode == Keys.D)
613             {
614                 e.Handled = e.SuppressKeyPress = true;
615                 debugConsoleToolStripMenuItem.PerformClick();
616                 return;
617             }
618
619             // Alt 1-8: Toggle various tabs
620             if (e.Modifiers == Keys.Alt)
621             {
622                 switch (e.KeyCode)
623                 {
624                     case Keys.D1:
625                         e.Handled = e.SuppressKeyPress = true;
626                         tabsConsole.Tabs["chat"].Select();
627                         return;
628
629                     case Keys.D2:
630                         e.Handled = e.SuppressKeyPress = true;
631                         tbtnFriends.PerformClick();
632                         return;
633
634                     case Keys.D3:
635                         e.Handled = e.SuppressKeyPress = true;
636                         tbtnGroups.PerformClick();
637                         return;
638
639                     case Keys.D4:
640                         e.Handled = e.SuppressKeyPress = true;
641                         tbtnInventory.PerformClick();
642                         return;
643
644                     case Keys.D5:
645                         e.Handled = e.SuppressKeyPress = true;
646                         tbtnSearch.PerformClick();
647                         return;
648
649                     case Keys.D6:
650                         e.Handled = e.SuppressKeyPress = true;
651                         tbtnMap.PerformClick();
652                         return;
653
654                     case Keys.D7:
655                         e.Handled = e.SuppressKeyPress = true;
656                         tbnObjects.PerformClick();
657                         return;
658
659                     case Keys.D8:
660                         e.Handled = e.SuppressKeyPress = true;
661                         tbtnMedia.PerformClick();
662                         return;
663
664                     case Keys.D9:
665                         e.Handled = e.SuppressKeyPress = true;
666                         tbtnVoice.PerformClick();
667                         return;
668                 }
669             }
670
671             // ctrl-g, goto slurl
672             if (e.Control && e.KeyCode == Keys.G)
673             {
674                 if (!ProcessLink(Clipboard.GetText(), true))
675                     MapToCurrentLocation();
676
677                 e.Handled = e.SuppressKeyPress = true;
678                 return;
679             }
680
681             // ctrl-(shift)-tab for next/previous tab
682             if (e.Control && e.KeyCode == Keys.Tab)
683             {
684                 if (e.Shift)
685                 {
686                     TabConsole.SelectPreviousTab();
687                 }
688                 else
689                 {
690                     TabConsole.SelectNextTab();
691                 }
692                 e.Handled = e.SuppressKeyPress = true;
693                 return;
694             }
695         }
696
697         bool firstLoad = true;
698
699         private void frmMain_Load(object sender, EventArgs e)
700         {
701             if (firstLoad)
702             {
703                 firstLoad = false;
704                 tabsConsole.SelectTab("login");
705                 ResourceManager rm = Properties.Resources.ResourceManager;
706                 ResourceSet set = rm.GetResourceSet(System.Globalization.CultureInfo.CurrentCulture, true, true);
707                 System.Collections.IDictionaryEnumerator de = set.GetEnumerator();
708                 while (de.MoveNext() == true)
709                 {
710                     if (de.Entry.Value is Image)
711                     {
712                         Bitmap bitMap = de.Entry.Value as Bitmap;
713                         ResourceImages.Images.Add(bitMap);
714                         ImageNames.Add(de.Entry.Key.ToString());
715                     }
716                 }
717                 StartUpdateCheck(false);
718
719                 if (instance.PlainColors)
720                 {
721                     pnlDialog.BackColor = System.Drawing.Color.FromArgb(120, 220, 255);
722                 }
723
724             }
725         }
726         #endregion
727
728         #region Public methods
729
730         private Dictionary<UUID, frmProfile> shownProfiles = new Dictionary<UUID, frmProfile>();
731
732         void ShowAgentProfileInternal(string name, UUID agentID)
733         {
734             lock (shownProfiles)
735             {
736                 frmProfile profile = null;
737                 if (shownProfiles.TryGetValue(agentID, out profile))
738                 {
739                     profile.WindowState = FormWindowState.Normal;
740                     profile.Focus();
741                 }
742                 else
743                 {
744                     profile = new frmProfile(instance, name, agentID);
745
746                     profile.Disposed += (object sender, EventArgs e) =>
747                         {
748                             lock (shownProfiles)
749                             {
750                                 frmProfile agentProfile = (frmProfile)sender;
751                                 if (shownProfiles.ContainsKey(agentProfile.AgentID))
752                                     shownProfiles.Remove(agentProfile.AgentID);
753                             }
754                         };
755
756                     profile.Show();
757                     profile.Focus();
758                     shownProfiles.Add(agentID, profile);
759                 }
760             }
761         }
762
763         public void ShowGroupProfile(AvatarGroup group)
764         {
765             ShowGroupProfile(new OpenMetaverse.Group()
766             {
767                 ID = group.GroupID,
768                 InsigniaID = group.GroupInsigniaID,
769                 Name = group.GroupName
770             }
771             );
772         }
773
774         private Dictionary<UUID, frmGroupInfo> shownGroupProfiles = new Dictionary<UUID, frmGroupInfo>();
775
776         public void ShowGroupProfile(OpenMetaverse.Group group)
777         {
778             lock (shownGroupProfiles)
779             {
780                 frmGroupInfo profile = null;
781                 if (shownGroupProfiles.TryGetValue(group.ID, out profile))
782                 {
783                     profile.WindowState = FormWindowState.Normal;
784                     profile.Focus();
785                 }
786                 else
787                 {
788                     profile = new frmGroupInfo(instance, group);
789
790                     profile.Disposed += (object sender, EventArgs e) =>
791                         {
792                             lock (shownGroupProfiles)
793                             {
794                                 frmGroupInfo groupProfile = (frmGroupInfo)sender;
795                                 if (shownGroupProfiles.ContainsKey(groupProfile.Group.ID))
796                                     shownGroupProfiles.Remove(groupProfile.Group.ID);
797                             }
798                         };
799
800                     profile.Show();
801                     profile.Focus();
802                     shownGroupProfiles.Add(group.ID, profile);
803                 }
804             }
805         }
806
807         public void ProcessLink(string link)
808         {
809             ProcessLink(link, false);
810         }
811
812         public bool ProcessLink(string link, bool onlyMap)
813         {
814             if (!link.Contains("://"))
815             {
816                 link = "http://" + link;
817             }
818
819             Regex r = new Regex(@"^(http://(slurl\.com|maps\.secondlife\.com)/secondlife/|secondlife://)(?<region>[^/]+)/(?<x>\d+)/(?<y>\d+)(/(?<z>\d+))?",
820                 RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase
821                 );
822             Match m = r.Match(link);
823
824             if (m.Success)
825             {
826                 string region = HttpUtility.UrlDecode(m.Groups["region"].Value);
827                 int x = int.Parse(m.Groups["x"].Value);
828                 int y = int.Parse(m.Groups["y"].Value);
829                 int z = 0;
830
831                 if (!string.IsNullOrEmpty(m.Groups["z"].Value))
832                 {
833                     z = int.Parse(m.Groups["z"].Value);
834                 }
835
836                 MapTab.Select();
837                 WorldMap.DisplayLocation(region, x, y, z);
838                 return true;
839             }
840             else if (!onlyMap)
841             {
842                 System.Diagnostics.Process.Start(link);
843             }
844             return false;
845         }
846         #endregion
847
848         #region Notifications
849         CircularList<Control> notifications = new CircularList<Control>();
850
851         public Color NotificationBackground
852         {
853             get { return pnlDialog.BackColor; }
854         }
855
856         void ResizeNotificationByControl(Control active)
857         {
858             int Width = active.Size.Width + 6;
859             int Height = notifications.Count > 1 ? active.Size.Height + 3 + btnDialogNextControl.Size.Height : active.Size.Height + 3;
860             pnlDialog.Size = new Size(Width, Height);
861             pnlDialog.Top = 0;
862             pnlDialog.Left = pnlDialog.Parent.ClientSize.Width - Width;
863
864             btnDialogNextControl.Top = btnDialogNextControl.Parent.ClientSize.Height - btnDialogNextControl.Size.Height;
865             btnDialogNextControl.Left = btnDialogNextControl.Parent.ClientSize.Width - btnDialogNextControl.Size.Width;
866
867             btnDialogNextControl.BringToFront();
868         }
869
870         public void AddNotification(Control control)
871         {
872             if (InvokeRequired)
873             {
874                 BeginInvoke(new MethodInvoker(delegate()
875                 {
876                     AddNotification(control);
877                 }
878                 ));
879                 return;
880             }
881
882             Control active = TabsConsole.FindFocusedControl(this);
883
884             FormFlash.StartFlash(this);
885             pnlDialog.Visible = true;
886             pnlDialog.BringToFront();
887
888             foreach (Control existing in notifications)
889             {
890                 existing.Visible = false;
891             }
892
893             notifications.Add(control);
894             control.Visible = true;
895             control.Anchor = AnchorStyles.Top | AnchorStyles.Left;
896             control.Top = 3;
897             control.Left = 3;
898             pnlDialog.Controls.Add(control);
899             ResizeNotificationByControl(control);
900
901             btnDialogNextControl.Visible = notifications.Count > 1;
902
903             if (active != null)
904             {
905                 active.Focus();
906             }
907         }
908
909         public void RemoveNotification(Control control)
910         {
911             pnlDialog.Controls.Remove(control);
912             notifications.Remove(control);
913             control.Dispose();
914
915             if (notifications.HasNext)
916             {
917                 pnlDialog.Visible = true;
918                 Control active = notifications.Next;
919                 active.Visible = true;
920                 ResizeNotificationByControl(active);
921             }
922             else
923             {
924                 pnlDialog.Visible = false;
925             }
926
927             btnDialogNextControl.Visible = notifications.Count > 1;
928         }
929
930         private void btnDialogNextControl_Click(object sender, EventArgs e)
931         {
932             foreach (Control existing in notifications)
933             {
934                 existing.Visible = false;
935             }
936
937             if (notifications.HasNext)
938             {
939                 pnlDialog.Visible = true;
940                 Control active = notifications.Next;
941                 active.Visible = true;
942                 ResizeNotificationByControl(active);
943             }
944             else
945             {
946                 pnlDialog.Visible = false;
947             }
948
949         }
950         #endregion Notifications
951
952         #region Menu click handlers
953
954         private void tmnuStatusAway_Click(object sender, EventArgs e)
955         {
956             instance.State.SetAway(tmnuStatusAway.Checked);
957         }
958
959         private void tmnuHelpReadme_Click(object sender, EventArgs e)
960         {
961             System.Diagnostics.Process.Start(Application.StartupPath + @"\Readme.txt");
962         }
963
964         private void tmnuStatusBusy_Click(object sender, EventArgs e)
965         {
966             instance.State.SetBusy(tmnuStatusBusy.Checked);
967         }
968
969         private void tmnuControlFly_Click(object sender, EventArgs e)
970         {
971             instance.State.SetFlying(tmnuControlFly.Checked);
972         }
973
974         private void tmnuControlAlwaysRun_Click(object sender, EventArgs e)
975         {
976             instance.State.SetAlwaysRun(tmnuControlAlwaysRun.Checked);
977         }
978
979         private void tmnuPrefs_Click(object sender, EventArgs e)
980         {
981             (new frmSettings(instance)).ShowDialog();
982         }
983
984         private void tbtnAppearance_Click(object sender, EventArgs e)
985         {
986             client.Appearance.RequestSetAppearance(false);
987         }
988
989         private void importObjectToolStripMenuItem_Click(object sender, EventArgs e)
990         {
991             PrimDeserializer.ImportFromFile(client);
992         }
993
994         private void autopilotToolStripMenuItem_Click(object sender, EventArgs e)
995         {
996             if (ap == null)
997             {
998                 ap = new AutoPilot(client);
999                 /*
1000                 ap.InsertWaypoint(new Vector3(66, 163, 21));
1001                 ap.InsertWaypoint(new Vector3(66, 98, 21));
1002
1003                 ap.InsertWaypoint(new Vector3(101, 98, 21));
1004                 ap.InsertWaypoint(new Vector3(101, 45, 21));
1005                 ap.InsertWaypoint(new Vector3(93, 27, 21));
1006                 ap.InsertWaypoint(new Vector3(106, 12, 21));
1007                 ap.InsertWaypoint(new Vector3(123, 24, 21));
1008                 ap.InsertWaypoint(new Vector3(114, 45, 21));
1009                 ap.InsertWaypoint(new Vector3(114, 98, 21));
1010
1011                 ap.InsertWaypoint(new Vector3(130, 98, 21));
1012                 ap.InsertWaypoint(new Vector3(130, 163, 21));
1013                  **/
1014                 ap.InsertWaypoint(new Vector3(64, 68, 21));
1015                 ap.InsertWaypoint(new Vector3(65, 20, 21));
1016                 ap.InsertWaypoint(new Vector3(33, 23, 21));
1017                 ap.InsertWaypoint(new Vector3(17, 39, 21));
1018                 ap.InsertWaypoint(new Vector3(17, 62, 21));
1019
1020
1021             }
1022             if (AutoPilotActive)
1023             {
1024                 AutoPilotActive = false;
1025                 ap.Stop();
1026             }
1027             else
1028             {
1029                 AutoPilotActive = true;
1030                 ap.Start();
1031             }
1032
1033         }
1034
1035         private void cleanCacheToolStripMenuItem_Click(object sender, EventArgs e)
1036         {
1037             ThreadPool.QueueUserWorkItem(sync => client.Assets.Cache.Clear());
1038         }
1039
1040         private void rebakeTexturesToolStripMenuItem_Click(object sender, EventArgs e)
1041         {
1042             client.Appearance.RequestSetAppearance(true);
1043         }
1044
1045         public void MapToCurrentLocation()
1046         {
1047             if (MapTab != null && client.Network.Connected)
1048             {
1049                 MapTab.Select();
1050                 WorldMap.DisplayLocation(client.Network.CurrentSim.Name,
1051                     (int)client.Self.SimPosition.X,
1052                     (int)client.Self.SimPosition.Y,
1053                     (int)client.Self.SimPosition.Z);
1054             }
1055         }
1056
1057         private void standToolStripMenuItem_Click(object sender, EventArgs e)
1058         {
1059             instance.State.SetSitting(false, UUID.Zero);
1060         }
1061
1062         private void groundSitToolStripMenuItem_Click(object sender, EventArgs e)
1063         {
1064             client.Self.SitOnGround();
1065         }
1066
1067         private void newWindowToolStripMenuItem_Click(object sender, EventArgs e)
1068         {
1069             try { System.Diagnostics.Process.Start(Application.ExecutablePath); }
1070             catch (Exception) { }
1071         }
1072
1073         private void tmnuExit_Click(object sender, EventArgs e)
1074         {
1075             Close();
1076         }
1077
1078         private void tlblRegionInfo_Click(object sender, EventArgs e)
1079         {
1080             if (WorldMap != null && client.Network.Connected)
1081             {
1082                 MapTab.Select();
1083             }
1084         }
1085
1086         private void scriptEditorToolStripMenuItem_Click(object sender, EventArgs e)
1087         {
1088             ScriptEditor se = new ScriptEditor(instance);
1089             se.Dock = DockStyle.Fill;
1090             se.ShowDetached();
1091         }
1092
1093         private void tmnuSetHome_Click(object sender, EventArgs e)
1094         {
1095             client.Self.SetHome();
1096         }
1097
1098         private void tmnuCreateLandmark_Click(object sender, EventArgs e)
1099         {
1100             string location = string.Format(", {0} ({1}, {2}, {3})",
1101                 client.Network.CurrentSim.Name,
1102                 (int)client.Self.SimPosition.X,
1103                 (int)client.Self.SimPosition.Y,
1104                 (int)client.Self.SimPosition.Z
1105                 );
1106
1107             string name = tlblParcel.Text;
1108             int maxLen = 63 - location.Length;
1109
1110             if (name.Length > maxLen)
1111                 name = name.Substring(0, maxLen);
1112
1113             name += location;
1114
1115             client.Inventory.RequestCreateItem(
1116                 client.Inventory.FindFolderForType(AssetType.Landmark),
1117                 name,
1118                 tlblParcel.ToolTipText,
1119                 AssetType.Landmark,
1120                 UUID.Random(),
1121                 InventoryType.Landmark,
1122                 PermissionMask.All,
1123                 (bool success, InventoryItem item) =>
1124                 {
1125                     if (success)
1126                     {
1127                         BeginInvoke(new MethodInvoker(() =>
1128                             {
1129                                 Landmark ln = new Landmark(instance, (InventoryLandmark)item);
1130                                 ln.Dock = DockStyle.Fill;
1131                                 ln.Detached = true;
1132                             }));
1133                     }
1134                 }
1135             );
1136         }
1137
1138
1139         private void timerWorldClock_Tick(object sender, EventArgs e)
1140         {
1141             lblTime.Text = instance.GetWorldTime().ToString("h:mm tt", System.Globalization.CultureInfo.InvariantCulture);
1142         }
1143
1144         private void reportBugsToolStripMenuItem_Click(object sender, EventArgs e)
1145         {
1146             ProcessLink("http://jira.openmetaverse.org/browse/RAD");
1147         }
1148
1149         private void aboutRadegastToolStripMenuItem_Click(object sender, EventArgs e)
1150         {
1151             (new frmAbout(instance)).ShowDialog();
1152         }
1153
1154         #region Update Checking
1155         private UpdateChecker updateChecker = null;
1156         private bool ManualUpdateCheck = false;
1157
1158         public void StartUpdateCheck(bool userInitiated)
1159         {
1160             ManualUpdateCheck = userInitiated;
1161
1162             if (updateChecker != null)
1163             {
1164                 if (ManualUpdateCheck)
1165                     tabsConsole.DisplayNotificationInChat("Update check already in progress.");
1166                 return;
1167             }
1168
1169             if (ManualUpdateCheck)
1170                 tabsConsole.DisplayNotificationInChat("Checking for updates...", ChatBufferTextStyle.StatusBlue);
1171             updateChecker = new UpdateChecker();
1172             updateChecker.OnUpdateInfoReceived += new UpdateChecker.UpdateInfoCallback(OnUpdateInfoReceived);
1173             updateChecker.StartCheck();
1174         }
1175
1176         private void checkForUpdatesToolStripMenuItem_Click(object sender, EventArgs e)
1177         {
1178             tabsConsole.SelectTab("chat");
1179             StartUpdateCheck(true);
1180         }
1181
1182         void OnUpdateInfoReceived(object sender, UpdateCheckerArgs e)
1183         {
1184             if (InvokeRequired)
1185             {
1186                 BeginInvoke(new MethodInvoker(() => OnUpdateInfoReceived(sender, e)));
1187                 return;
1188             }
1189
1190             if (!e.Success)
1191             {
1192                 if (ManualUpdateCheck)
1193                     tabsConsole.DisplayNotificationInChat("Error: Failed connecting to the update site.", ChatBufferTextStyle.StatusBlue);
1194             }
1195             else
1196             {
1197                 if (!ManualUpdateCheck && e.Info.DisplayMOTD)
1198                 {
1199                     tabsConsole.DisplayNotificationInChat(e.Info.MOTD, ChatBufferTextStyle.StatusBlue);
1200                 }
1201
1202                 if (e.Info.UpdateAvailable)
1203                 {
1204                     tabsConsole.DisplayNotificationInChat("New version available at " + e.Info.DownloadSite, ChatBufferTextStyle.Alert);
1205                 }
1206                 else
1207                 {
1208                     if (ManualUpdateCheck)
1209                         tabsConsole.DisplayNotificationInChat("Your version is up to date.", ChatBufferTextStyle.StatusBlue);
1210                 }
1211             }
1212
1213             updateChecker.Dispose();
1214             updateChecker = null;
1215         }
1216         #endregion
1217
1218         private void ToggleHidden(string tabName)
1219         {
1220             if (!tabsConsole.TabExists(tabName)) return;
1221
1222             RadegastTab tab = tabsConsole.Tabs[tabName];
1223
1224             if (tab.Hidden)
1225             {
1226                 tab.Show();
1227             }
1228             else
1229             {
1230                 if (!tab.Selected)
1231                 {
1232                     tab.Select();
1233                 }
1234                 else
1235                 {
1236                     tab.Hide();
1237                 }
1238             }
1239         }
1240
1241         private void tbtnFriends_Click(object sender, EventArgs e)
1242         {
1243             ToggleHidden("friends");
1244         }
1245
1246         private void tbtnInventory_Click(object sender, EventArgs e)
1247         {
1248             ToggleHidden("inventory");
1249         }
1250
1251         private void tbtnSearch_Click(object sender, EventArgs e)
1252         {
1253             ToggleHidden("search");
1254         }
1255
1256         private void tbtnGroups_Click(object sender, EventArgs e)
1257         {
1258             ToggleHidden("groups");
1259         }
1260
1261         private void tbtnVoice_Click(object sender, EventArgs e)
1262         {
1263             ToggleHidden("voice");
1264         }
1265
1266         private void tbtnMedia_Click(object sender, EventArgs e)
1267         {
1268             if (tabsConsole.TabExists("media"))
1269             {
1270                 ToggleHidden("media");
1271             }
1272             else
1273             {
1274                 RadegastTab tab = tabsConsole.AddTab("media", "Media", mediaConsole);
1275                 tab.AllowClose = false;
1276                 tab.AllowHide = true;
1277                 tab.Select();
1278             }
1279         }
1280
1281         private void debugConsoleToolStripMenuItem_Click(object sender, EventArgs e)
1282         {
1283             if (tabsConsole.TabExists("debug"))
1284             {
1285                 ToggleHidden("debug");
1286             }
1287             else
1288             {
1289                 RadegastTab tab = tabsConsole.AddTab("debug", "Debug", new DebugConsole(instance));
1290                 tab.AllowClose = false;
1291                 tab.AllowHide = true;
1292                 tab.Select();
1293             }
1294         }
1295
1296         private void tbnObjects_Click(object sender, EventArgs e)
1297         {
1298             if (tabsConsole.TabExists("objects"))
1299             {
1300                 RadegastTab tab = tabsConsole.Tabs["objects"];
1301                 if (!tab.Selected)
1302                 {
1303                     tab.Select();
1304                     ((ObjectsConsole)tab.Control).RefreshObjectList();
1305                 }
1306                 else
1307                 {
1308                     tab.Close();
1309                 }
1310             }
1311             else
1312             {
1313                 RadegastTab tab = tabsConsole.AddTab("objects", "Objects", new ObjectsConsole(instance));
1314                 tab.AllowClose = true;
1315                 tab.AllowDetach = true;
1316                 tab.Visible = true;
1317                 tab.AllowHide = false;
1318                 tab.Select();
1319                 ((ObjectsConsole)tab.Control).RefreshObjectList();
1320             }
1321         }
1322
1323         private void tbtnMap_Click(object sender, EventArgs e)
1324         {
1325             if (MapTab == null) return; // too soon!
1326
1327             ToggleHidden("map");
1328             if (!MapTab.Hidden)
1329                 MapToCurrentLocation();
1330         }
1331
1332         private void disconnectToolStripMenuItem_Click(object sender, EventArgs e)
1333         {
1334             if (client.Network.Connected)
1335                 client.Network.RequestLogout();
1336         }
1337
1338         private void reconnectToolStripMenuItem_Click(object sender, EventArgs e)
1339         {
1340             if (!client.Network.Connected)
1341             {
1342                 instance.Reconnect();
1343             }
1344         }
1345
1346         private frmKeyboardShortcuts keyboardShortcutsForm = null;
1347         private void keyboardShortcutsToolStripMenuItem_Click(object sender, EventArgs e)
1348         {
1349             if (keyboardShortcutsForm != null)
1350             {
1351                 keyboardShortcutsForm.Focus();
1352             }
1353             else
1354             {
1355                 keyboardShortcutsForm = new frmKeyboardShortcuts(instance);
1356
1357                 keyboardShortcutsForm.Disposed += (object senderx, EventArgs ex) =>
1358                     {
1359                         if (components != null)
1360                         {
1361                             components.Remove(keyboardShortcutsForm);
1362                         }
1363                         keyboardShortcutsForm = null;
1364                     };
1365
1366                 keyboardShortcutsForm.Show(this);
1367                 keyboardShortcutsForm.Top = Top + 100;
1368                 keyboardShortcutsForm.Left = Left + 100;
1369
1370                 if (components != null)
1371                 {
1372                     components.Add(keyboardShortcutsForm);
1373                 }
1374             }
1375         }
1376
1377         // Menu item for testing out stuff
1378         private void testToolStripMenuItem_Click(object sender, EventArgs e)
1379         {
1380         }
1381
1382         private void reloadInventoryToolStripMenuItem_Click(object sender, EventArgs e)
1383         {
1384             if (tabsConsole.TabExists("inventory"))
1385             {
1386                 ((InventoryConsole)tabsConsole.Tabs["inventory"].Control).ReloadInventory();
1387                 tabsConsole.Tabs["inventory"].Select();
1388             }
1389         }
1390
1391         private void btnLoadScript_Click(object sender, EventArgs e)
1392         {
1393             if (!TabConsole.TabExists("plugin_manager"))
1394             {
1395                 TabConsole.AddTab("plugin_manager", "Plugins", new PluginsTab(instance));
1396             }
1397             TabConsole.Tabs["plugin_manager"].Select();
1398         }
1399
1400         private void frmMain_Resize(object sender, EventArgs e)
1401         {
1402             if (WindowState == FormWindowState.Minimized && instance.GlobalSettings["minimize_to_tray"].AsBoolean())
1403             {
1404                 if (TabConsole.TabExists("scene_window") && !TabConsole.Tabs["scene_window"].Detached)
1405                 {
1406                     TabConsole.Tabs["scene_window"].Close();
1407                 }
1408                 ShowInTaskbar = false;
1409                 trayIcon.Visible = true;
1410                 FormBorderStyle = FormBorderStyle.SizableToolWindow;
1411             }
1412         }
1413
1414         private void treyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
1415         {
1416             WindowState = FormWindowState.Normal;
1417             ShowInTaskbar = true;
1418             trayIcon.Visible = false;
1419             FormBorderStyle = FormBorderStyle.Sizable;
1420         }
1421
1422         private void ctxTreyRestore_Click(object sender, EventArgs e)
1423         {
1424             treyIcon_MouseDoubleClick(this, null);
1425         }
1426
1427         private void ctxTreyExit_Click(object sender, EventArgs e)
1428         {
1429             tmnuExit_Click(this, EventArgs.Empty);
1430         }
1431
1432         private void tmnuTeleportHome_Click(object sender, EventArgs e)
1433         {
1434             TabConsole.DisplayNotificationInChat("Teleporting home...");
1435             client.Self.RequestTeleport(UUID.Zero);
1436         }
1437
1438         private void stopAllAnimationsToolStripMenuItem_Click(object sender, EventArgs e)
1439         {
1440             instance.State.StopAllAnimations();
1441         }
1442
1443         public void DisplayRegionParcelConsole()
1444         {
1445             if (tabsConsole.TabExists("current region info"))
1446             {
1447                 tabsConsole.Tabs["current region info"].Select();
1448                 (tabsConsole.Tabs["current region info"].Control as RegionInfo).UpdateDisplay();
1449             }
1450             else
1451             {
1452                 tabsConsole.AddTab("current region info", "Region info", new RegionInfo(instance));
1453                 tabsConsole.Tabs["current region info"].Select();
1454             }
1455         }
1456
1457         private void regionParcelToolStripMenuItem_Click(object sender, EventArgs e)
1458         {
1459             DisplayRegionParcelConsole();
1460         }
1461
1462         private void tlblParcel_Click(object sender, EventArgs e)
1463         {
1464             DisplayRegionParcelConsole();
1465         }
1466
1467         private void changeMyDisplayNameToolStripMenuItem_Click(object sender, EventArgs e)
1468         {
1469             if (!client.Avatars.DisplayNamesAvailable())
1470             {
1471                 tabsConsole.DisplayNotificationInChat("This grid does not support display names.", ChatBufferTextStyle.Error);
1472                 return;
1473             }
1474
1475             var dlg = new DisplayNameChange(instance);
1476             dlg.ShowDialog();
1477         }
1478
1479         private void muteListToolStripMenuItem_Click(object sender, EventArgs e)
1480         {
1481             if (!tabsConsole.TabExists("mute list console"))
1482             {
1483                 tabsConsole.AddTab("mute list console", "Mute list", new MuteList(instance));
1484             }
1485             tabsConsole.Tabs["mute list console"].Select();
1486         }
1487
1488         private void uploadImageToolStripMenuItem_Click(object sender, EventArgs e)
1489         {
1490             if (!tabsConsole.TabExists("image upload console"))
1491             {
1492                 tabsConsole.AddTab("image upload console", "Upload image", new ImageUploadConsole(instance));
1493             }
1494             tabsConsole.Tabs["image upload console"].Select();
1495         }
1496         #endregion
1497
1498         private void myAttachmentsToolStripMenuItem_Click(object sender, EventArgs e)
1499         {
1500             Avatar av = client.Network.CurrentSim.ObjectsAvatars.Find((Avatar a) => { return a.ID == client.Self.AgentID; });
1501
1502             if (av == null)
1503             {
1504                 tabsConsole.DisplayNotificationInChat("Unable to find my avatar!", ChatBufferTextStyle.Error);
1505                 return;
1506             }
1507
1508             if (!instance.TabConsole.TabExists("AT: " + av.ID.ToString()))
1509             {
1510                 instance.TabConsole.AddTab("AT: " + av.ID.ToString(), "My Attachments", new AttachmentTab(instance, av));
1511             }
1512             instance.TabConsole.SelectTab("AT: " + av.ID.ToString());
1513
1514         }
1515
1516         private void tsb3D_Click(object sender, EventArgs e)
1517         {
1518             if (instance.TabConsole.TabExists("scene_window"))
1519             {
1520                 instance.TabConsole.Tabs["scene_window"].Select();
1521             }
1522             else
1523             {
1524                 var control = new Rendering.SceneWindow(instance);
1525                 control.Dock = DockStyle.Fill;
1526                 instance.TabConsole.AddTab("scene_window", "Scene Viewer", control);
1527                 instance.TabConsole.Tabs["scene_window"].Floater = false;
1528                 instance.TabConsole.Tabs["scene_window"].CloseOnDetachedClose = true;
1529                 control.RegisterTabEvents();
1530
1531                 if (instance.GlobalSettings["scene_window_docked"])
1532                 {
1533                     instance.TabConsole.Tabs["scene_window"].Select();
1534                 }
1535                 else
1536                 {
1537                     instance.TabConsole.Tabs["scene_window"].Detach(instance);
1538                 }
1539             }
1540         }
1541     }
1542 }