OSDN Git Service

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