OSDN Git Service

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