OSDN Git Service

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