OSDN Git Service

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