OSDN Git Service

Added auto reconnect form. RAD-58
[radegast/radegast.git] / Radegast / GUI / Dialogs / MainForm.cs
1 // \r
2 // Radegast Metaverse Client\r
3 // Copyright (c) 2009, Radegast Development Team\r
4 // All rights reserved.\r
5 // \r
6 // Redistribution and use in source and binary forms, with or without\r
7 // modification, are permitted provided that the following conditions are met:\r
8 // \r
9 //     * Redistributions of source code must retain the above copyright notice,\r
10 //       this list of conditions and the following disclaimer.\r
11 //     * Redistributions in binary form must reproduce the above copyright\r
12 //       notice, this list of conditions and the following disclaimer in the\r
13 //       documentation and/or other materials provided with the distribution.\r
14 //     * Neither the name of the application "Radegast", nor the names of its\r
15 //       contributors may be used to endorse or promote products derived from\r
16 //       this software without specific prior written permission.\r
17 // \r
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
21 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\r
22 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r
24 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
25 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
26 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
28 //\r
29 // $Id$\r
30 //\r
31 using System;\r
32 using System.Collections.Generic;\r
33 using System.Drawing;\r
34 using System.Text;\r
35 using System.Text.RegularExpressions;\r
36 using System.Timers;\r
37 using System.Threading;\r
38 using System.Windows.Forms;\r
39 using System.Resources;\r
40 using System.IO;\r
41 using System.Web;\r
42 using Radegast.Netcom;\r
43 using OpenMetaverse;\r
44 using OpenMetaverse.StructuredData;\r
45 \r
46 namespace Radegast\r
47 {\r
48     public partial class frmMain : RadegastForm\r
49     {\r
50         #region Public members\r
51         public static ImageList ResourceImages = new ImageList();\r
52         public static List<string> ImageNames = new List<string>();\r
53 \r
54         public TabsConsole TabConsole\r
55         {\r
56             get { return tabsConsole; }\r
57         }\r
58 \r
59         public MapConsole WorldMap\r
60         {\r
61             get\r
62             {\r
63                 if (MapTab != null)\r
64                 {\r
65                     return (MapConsole)MapTab.Control;\r
66                 }\r
67                 return null;\r
68             }\r
69         }\r
70 \r
71         public RadegastTab MapTab\r
72         {\r
73             get\r
74             {\r
75                 if (tabsConsole.TabExists("map"))\r
76                 {\r
77                     return tabsConsole.Tabs["map"];\r
78                 }\r
79                 else\r
80                 {\r
81                     return null;\r
82                 }\r
83             }\r
84         }\r
85 \r
86         public MediaConsole MediaConsole { get { return mediaConsole; } }\r
87 \r
88         /// <summary>\r
89         /// Drop down that contains the tools menu\r
90         /// </summary>\r
91         public ToolStripDropDownButton ToolsMenu\r
92         {\r
93             get { return tbnTools; }\r
94         }\r
95 \r
96         /// <summary>\r
97         /// Dropdown that contains the heelp menu\r
98         /// </summary>\r
99         public ToolStripDropDownButton HelpMenu\r
100         {\r
101             get { return tbtnHelp; }\r
102         }\r
103 \r
104         /// <summary>\r
105         /// Drop down that contants the plugins menu. Make sure to set it Visible if\r
106         /// you add items to this menu, it's hidden by default\r
107         /// </summary>\r
108         public ToolStripDropDownButton PluginsMenu\r
109         {\r
110             get { return tbnPlugins; }\r
111         }\r
112 \r
113         #endregion\r
114 \r
115         #region Private members\r
116         private RadegastInstance instance;\r
117         private GridClient client { get { return instance.Client; } }\r
118         private RadegastNetcom netcom { get { return instance.Netcom; } }\r
119         private TabsConsole tabsConsole;\r
120         private System.Timers.Timer statusTimer;\r
121         private AutoPilot ap;\r
122         private bool AutoPilotActive = false;\r
123         private TransparentButton btnDialogNextControl;\r
124         private MediaConsole mediaConsole;\r
125         #endregion\r
126 \r
127         #region Constructor and disposal\r
128         public frmMain(RadegastInstance instance)\r
129             : base(instance)\r
130         {\r
131             GetSLTimeZone();\r
132             InitializeComponent();\r
133             Disposed += new EventHandler(frmMain_Disposed);\r
134 \r
135             this.instance = instance;\r
136             this.instance.ClientChanged += new EventHandler<ClientChangedEventArgs>(instance_ClientChanged);\r
137             netcom.NetcomSync = this;\r
138 \r
139             pnlDialog.Visible = false;\r
140             btnDialogNextControl = new TransparentButton();\r
141             pnlDialog.Controls.Add(btnDialogNextControl);\r
142             pnlDialog.Top = 0;\r
143 \r
144             btnDialogNextControl.Size = new Size(35, 20);\r
145             btnDialogNextControl.BackColor = Color.Transparent;\r
146             btnDialogNextControl.ForeColor = Color.Gold;\r
147             btnDialogNextControl.FlatAppearance.BorderSize = 0;\r
148             btnDialogNextControl.FlatStyle = FlatStyle.Flat;\r
149             btnDialogNextControl.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;\r
150             btnDialogNextControl.Text = ">>";\r
151             btnDialogNextControl.Font = new Font(btnDialogNextControl.Font, FontStyle.Bold);\r
152             btnDialogNextControl.Margin = new Padding(0);\r
153             btnDialogNextControl.Padding = new Padding(0);\r
154             btnDialogNextControl.UseVisualStyleBackColor = false;\r
155             btnDialogNextControl.Top = btnDialogNextControl.Parent.ClientSize.Height - btnDialogNextControl.Size.Height;\r
156             btnDialogNextControl.Left = btnDialogNextControl.Parent.ClientSize.Width - btnDialogNextControl.Size.Width;\r
157             btnDialogNextControl.Click += new EventHandler(btnDialogNextControl_Click);\r
158 \r
159             if (instance.MonoRuntime)\r
160             {\r
161                 statusStrip1.LayoutStyle = ToolStripLayoutStyle.Table;\r
162             }\r
163 \r
164             // Config options\r
165             if (instance.GlobalSettings["transaction_notification_chat"].Type == OSDType.Unknown)\r
166                 instance.GlobalSettings["transaction_notification_chat"] = OSD.FromBoolean(true);\r
167 \r
168             if (instance.GlobalSettings["transaction_notification_dialog"].Type == OSDType.Unknown)\r
169                 instance.GlobalSettings["transaction_notification_dialog"] = OSD.FromBoolean(true);\r
170 \r
171             // Callbacks\r
172             netcom.ClientLoginStatus += new EventHandler<ClientLoginEventArgs>(netcom_ClientLoginStatus);\r
173             netcom.ClientLoggedOut += new EventHandler(netcom_ClientLoggedOut);\r
174             netcom.ClientDisconnected += new EventHandler<ClientDisconnectEventArgs>(netcom_ClientDisconnected);\r
175             RegisterClientEvents(client);\r
176 \r
177             InitializeStatusTimer();\r
178             RefreshWindowTitle();\r
179         }\r
180 \r
181         private void RegisterClientEvents(GridClient client)\r
182         {\r
183             client.Parcels.ParcelProperties += new EventHandler<ParcelPropertiesEventArgs>(Parcels_ParcelProperties);\r
184             client.Self.MoneyBalanceReply += new EventHandler<MoneyBalanceReplyEventArgs>(Self_MoneyBalanceReply);\r
185         }\r
186 \r
187         private void UnregisterClientEvents(GridClient client)\r
188         {\r
189             client.Parcels.ParcelProperties -= new EventHandler<ParcelPropertiesEventArgs>(Parcels_ParcelProperties);\r
190             client.Self.MoneyBalanceReply -= new EventHandler<MoneyBalanceReplyEventArgs>(Self_MoneyBalanceReply);\r
191         }\r
192 \r
193         void instance_ClientChanged(object sender, ClientChangedEventArgs e)\r
194         {\r
195             UnregisterClientEvents(e.OldClient);\r
196             RegisterClientEvents(client);\r
197         }\r
198 \r
199         void frmMain_Disposed(object sender, EventArgs e)\r
200         {\r
201             netcom.ClientLoginStatus -= new EventHandler<ClientLoginEventArgs>(netcom_ClientLoginStatus);\r
202             netcom.ClientLoggedOut -= new EventHandler(netcom_ClientLoggedOut);\r
203             netcom.ClientDisconnected -= new EventHandler<ClientDisconnectEventArgs>(netcom_ClientDisconnected);\r
204             UnregisterClientEvents(client);\r
205             this.instance.CleanUp();\r
206         }\r
207         #endregion\r
208 \r
209         #region Event handlers\r
210         void Self_MoneyBalanceReply(object sender, MoneyBalanceReplyEventArgs e)\r
211         {\r
212             if (!String.IsNullOrEmpty(e.Description))\r
213             {\r
214                 if (instance.GlobalSettings["transaction_notification_dialog"].AsBoolean())\r
215                     AddNotification(new ntfGeneric(instance, e.Description));\r
216                 if (instance.GlobalSettings["transaction_notification_chat"].AsBoolean())\r
217                     TabConsole.DisplayNotificationInChat(e.Description);\r
218             }\r
219         }\r
220 \r
221         public void InitializeControls()\r
222         {\r
223             InitializeTabsConsole();\r
224 \r
225             if (instance.MediaManager.SoundSystemAvailable)\r
226             {\r
227                 mediaConsole = new MediaConsole(instance);\r
228                 tbtnMedia.Visible = true;\r
229             }\r
230         }\r
231 \r
232         public bool InAutoReconnect { get; set; }\r
233 \r
234         private void DisplayAutoReconnectForm()\r
235         {\r
236             if (InvokeRequired)\r
237             {\r
238                 BeginInvoke(new MethodInvoker(DisplayAutoReconnectForm));\r
239                 return;\r
240             }\r
241 \r
242             InAutoReconnect = true;\r
243             frmReconnect dialog = new frmReconnect(instance, 120);\r
244             dialog.ShowDialog(this);\r
245             dialog.Dispose();\r
246             dialog = null;\r
247         }\r
248 \r
249         public void BeginAutoReconnect()\r
250         {\r
251             // Sleep for 3 seconds on a separate thread while things unwind on\r
252             // disconnect, since ShowDialog() blocks GUI thread\r
253             (new Thread(new ThreadStart(() =>\r
254                 {\r
255                     System.Threading.Thread.Sleep(3000);\r
256                     DisplayAutoReconnectForm();\r
257                 }\r
258                 ))\r
259                 {\r
260                     Name = "Reconnect Delay Thread",\r
261                     IsBackground = false\r
262                 }\r
263             ).Start();\r
264         }\r
265 \r
266         private void netcom_ClientLoginStatus(object sender, ClientLoginEventArgs e)\r
267         {\r
268             if (e.Status == LoginStatus.Failed)\r
269             {\r
270                 if (InAutoReconnect)\r
271                 {\r
272                     if (instance.GlobalSettings["auto_reconnect"].AsBoolean())\r
273                         BeginAutoReconnect();\r
274                     else\r
275                         InAutoReconnect = false;\r
276                 }\r
277             }\r
278             else if (e.Status == LoginStatus.Success)\r
279             {\r
280                 InAutoReconnect = false;\r
281                 disconnectToolStripMenuItem.Enabled =\r
282                 tbtnGroups.Enabled = tbnObjects.Enabled = tbtnWorld.Enabled = tbnTools.Enabled = tmnuImport.Enabled =\r
283                     tbtnFriends.Enabled = tbtnInventory.Enabled = tbtnSearch.Enabled = tbtnMap.Enabled = true;\r
284 \r
285                 statusTimer.Start();\r
286                 RefreshWindowTitle();\r
287             }\r
288         }\r
289 \r
290         private void netcom_ClientLoggedOut(object sender, EventArgs e)\r
291         {\r
292             disconnectToolStripMenuItem.Enabled =\r
293             tbtnGroups.Enabled = tbnObjects.Enabled = tbtnWorld.Enabled = tbnTools.Enabled = tmnuImport.Enabled =\r
294                 tbtnFriends.Enabled = tbtnInventory.Enabled = tbtnSearch.Enabled = tbtnMap.Enabled = false;\r
295 \r
296             reconnectToolStripMenuItem.Enabled = true;\r
297             InAutoReconnect = false;\r
298 \r
299             statusTimer.Stop();\r
300 \r
301             RefreshStatusBar();\r
302             RefreshWindowTitle();\r
303         }\r
304 \r
305         private void netcom_ClientDisconnected(object sender, ClientDisconnectEventArgs e)\r
306         {\r
307             if (e.Type == NetworkManager.DisconnectType.ClientInitiated) return;\r
308             netcom_ClientLoggedOut(sender, EventArgs.Empty);\r
309 \r
310             if (instance.GlobalSettings["auto_reconnect"].AsBoolean())\r
311             {\r
312                 BeginAutoReconnect();\r
313             }\r
314         }\r
315 \r
316         private void frmMain_FormClosing(object sender, FormClosingEventArgs e)\r
317         {\r
318             if (mediaConsole != null)\r
319             {\r
320                 if (tabsConsole.TabExists("media"))\r
321                 {\r
322                     tabsConsole.Tabs["media"].AllowClose = true;\r
323                     tabsConsole.Tabs["media"].Close();\r
324                 }\r
325                 else\r
326                 {\r
327                     mediaConsole.Dispose();\r
328                 }\r
329                 mediaConsole = null;\r
330             }\r
331 \r
332             if (netcom.IsLoggedIn)\r
333             {\r
334                 Thread saveInvToDisk = new Thread(new ThreadStart(\r
335                     delegate()\r
336                     {\r
337                         client.Inventory.Store.SaveToDisk(instance.InventoryCacheFileName);\r
338                     }));\r
339                 saveInvToDisk.Name = "Save inventory to disk";\r
340                 saveInvToDisk.Start();\r
341 \r
342                 netcom.Logout();\r
343             }\r
344         }\r
345         #endregion\r
346 \r
347         # region Update status\r
348 \r
349         void Parcels_ParcelProperties(object sender, ParcelPropertiesEventArgs e)\r
350         {\r
351             if (e.Result != ParcelResult.Single) return;\r
352             if (InvokeRequired)\r
353             {\r
354                 BeginInvoke(new MethodInvoker(() => Parcels_ParcelProperties(sender, e)));\r
355                 return;\r
356             }\r
357 \r
358             Parcel parcel = e.Parcel;\r
359 \r
360             tlblParcel.Text = parcel.Name;\r
361             tlblParcel.ToolTipText = parcel.Desc;\r
362 \r
363             if ((parcel.Flags & ParcelFlags.AllowFly) != ParcelFlags.AllowFly)\r
364                 icoNoFly.Visible = true;\r
365             else\r
366                 icoNoFly.Visible = false;\r
367 \r
368             if ((parcel.Flags & ParcelFlags.CreateObjects) != ParcelFlags.CreateObjects)\r
369                 icoNoBuild.Visible = true;\r
370             else\r
371                 icoNoBuild.Visible = false;\r
372 \r
373             if ((parcel.Flags & ParcelFlags.AllowOtherScripts) != ParcelFlags.AllowOtherScripts)\r
374                 icoNoScript.Visible = true;\r
375             else\r
376                 icoNoScript.Visible = false;\r
377 \r
378             if ((parcel.Flags & ParcelFlags.RestrictPushObject) == ParcelFlags.RestrictPushObject)\r
379                 icoNoPush.Visible = true;\r
380             else\r
381                 icoNoPush.Visible = false;\r
382 \r
383             if ((parcel.Flags & ParcelFlags.AllowDamage) == ParcelFlags.AllowDamage)\r
384                 icoHealth.Visible = true;\r
385             else\r
386                 icoHealth.Visible = false;\r
387 \r
388             if ((parcel.Flags & ParcelFlags.AllowVoiceChat) != ParcelFlags.AllowVoiceChat)\r
389                 icoNoVoice.Visible = true;\r
390             else\r
391                 icoNoVoice.Visible = false;\r
392         }\r
393 \r
394         private void RefreshStatusBar()\r
395         {\r
396             if (netcom.IsLoggedIn)\r
397             {\r
398                 tlblLoginName.Text = netcom.LoginOptions.FullName;\r
399                 tlblMoneyBalance.Text = client.Self.Balance.ToString();\r
400                 icoHealth.Text = client.Self.Health.ToString() + "%";\r
401 \r
402                 tlblRegionInfo.Text =\r
403                     client.Network.CurrentSim.Name +\r
404                     " (" + Math.Floor(client.Self.SimPosition.X).ToString() + ", " +\r
405                     Math.Floor(client.Self.SimPosition.Y).ToString() + ", " +\r
406                     Math.Floor(client.Self.SimPosition.Z).ToString() + ")";\r
407             }\r
408             else\r
409             {\r
410                 tlblLoginName.Text = "Offline";\r
411                 tlblMoneyBalance.Text = "0";\r
412                 icoHealth.Text = "0%";\r
413                 tlblRegionInfo.Text = "No Region";\r
414                 tlblParcel.Text = "No Parcel";\r
415 \r
416                 icoHealth.Visible = false;\r
417                 icoNoBuild.Visible = false;\r
418                 icoNoFly.Visible = false;\r
419                 icoNoPush.Visible = false;\r
420                 icoNoScript.Visible = false;\r
421                 icoNoVoice.Visible = false;\r
422             }\r
423         }\r
424 \r
425         private void RefreshWindowTitle()\r
426         {\r
427             StringBuilder sb = new StringBuilder();\r
428             sb.Append("Radegast - ");\r
429 \r
430             if (netcom.IsLoggedIn)\r
431             {\r
432                 sb.Append("[" + netcom.LoginOptions.FullName + "]");\r
433 \r
434                 if (instance.State.IsAway)\r
435                 {\r
436                     sb.Append(" - Away");\r
437                     if (instance.State.IsBusy) sb.Append(", Busy");\r
438                 }\r
439                 else if (instance.State.IsBusy)\r
440                 {\r
441                     sb.Append(" - Busy");\r
442                 }\r
443 \r
444                 if (instance.State.IsFollowing)\r
445                 {\r
446                     sb.Append(" - Following ");\r
447                     sb.Append(instance.State.FollowName);\r
448                 }\r
449             }\r
450             else\r
451             {\r
452                 sb.Append("Logged Out");\r
453             }\r
454 \r
455             this.Text = sb.ToString();\r
456             sb = null;\r
457         }\r
458 \r
459         private void InitializeStatusTimer()\r
460         {\r
461             statusTimer = new System.Timers.Timer(250);\r
462             statusTimer.SynchronizingObject = this;\r
463             statusTimer.Elapsed += new ElapsedEventHandler(statusTimer_Elapsed);\r
464         }\r
465 \r
466         private void statusTimer_Elapsed(object sender, ElapsedEventArgs e)\r
467         {\r
468             RefreshWindowTitle();\r
469             RefreshStatusBar();\r
470         }\r
471         #endregion\r
472 \r
473         #region Initialization, configuration, and key shortcuts\r
474         private void InitializeTabsConsole()\r
475         {\r
476             tabsConsole = new TabsConsole(instance);\r
477             tabsConsole.Dock = DockStyle.Fill;\r
478             toolStripContainer1.ContentPanel.Controls.Add(tabsConsole);\r
479         }\r
480 \r
481         private void frmMain_KeyDown(object sender, KeyEventArgs e)\r
482         {\r
483             if (e.Control && e.Alt && e.KeyCode == Keys.D)\r
484             {\r
485                 e.Handled = e.SuppressKeyPress = true;\r
486             }\r
487 \r
488             if (e.Control && e.KeyCode == Keys.O && client.Network.Connected)\r
489             {\r
490                 e.Handled = e.SuppressKeyPress = true;\r
491             }\r
492 \r
493             if (e.Control && e.KeyCode == Keys.G)\r
494             {\r
495                 e.Handled = e.SuppressKeyPress = true;\r
496             }\r
497 \r
498             if (e.Control && e.KeyCode == Keys.M && Clipboard.ContainsText() && client.Network.Connected)\r
499             {\r
500                 e.Handled = e.SuppressKeyPress = true;\r
501             }\r
502 \r
503             // ctrl-(shift)-tab for next/previous tab\r
504             if (e.Control && e.KeyCode == Keys.Tab)\r
505             {\r
506                 if (e.Shift)\r
507                 {\r
508                     TabConsole.SelectPreviousTab();\r
509                 }\r
510                 else\r
511                 {\r
512                     TabConsole.SelectNextTab();\r
513                 }\r
514                 e.Handled = e.SuppressKeyPress = true;\r
515             }\r
516         }\r
517 \r
518         private void frmMain_KeyUp(object sender, KeyEventArgs e)\r
519         {\r
520             // ctrl-o, open objects finder\r
521             if (e.Control && e.KeyCode == Keys.O && client.Network.Connected)\r
522             {\r
523                 tbnObjects_Click(this, EventArgs.Empty);\r
524                 e.Handled = e.SuppressKeyPress = true;\r
525             }\r
526 \r
527             // ctrl-g, goto slurl\r
528             if (e.Control && e.KeyCode == Keys.G && Clipboard.ContainsText() && client.Network.Connected)\r
529             {\r
530                 if (!ProcessLink(Clipboard.GetText(), true))\r
531                     MapToCurrentLocation();\r
532                 e.Handled = e.SuppressKeyPress = true;\r
533             }\r
534 \r
535             // ctrl-m, open map\r
536             if (e.Control && e.KeyCode == Keys.M && Clipboard.ContainsText() && client.Network.Connected)\r
537             {\r
538                 MapToCurrentLocation();\r
539                 e.Handled = e.SuppressKeyPress = true;\r
540             }\r
541         }\r
542 \r
543 \r
544         private void frmMain_Load(object sender, EventArgs e)\r
545         {\r
546             tabsConsole.SelectTab("login");\r
547             ResourceManager rm = Properties.Resources.ResourceManager;\r
548             ResourceSet set = rm.GetResourceSet(System.Globalization.CultureInfo.CurrentCulture, true, true);\r
549             System.Collections.IDictionaryEnumerator de = set.GetEnumerator();\r
550             while (de.MoveNext() == true)\r
551             {\r
552                 if (de.Entry.Value is Image)\r
553                 {\r
554                     Bitmap bitMap = de.Entry.Value as Bitmap;\r
555                     ResourceImages.Images.Add(bitMap);\r
556                     ImageNames.Add(de.Entry.Key.ToString());\r
557                 }\r
558             }\r
559             StartUpdateCheck(false);\r
560         }\r
561         #endregion\r
562 \r
563         #region Public methods\r
564 \r
565         private Dictionary<UUID, frmProfile> shownProfiles = new Dictionary<UUID, frmProfile>();\r
566 \r
567         public void ShowAgentProfile(string name, UUID agentID)\r
568         {\r
569             lock (shownProfiles)\r
570             {\r
571                 frmProfile profile = null;\r
572                 if (shownProfiles.TryGetValue(agentID, out profile))\r
573                 {\r
574                     profile.WindowState = FormWindowState.Normal;\r
575                     profile.Focus();\r
576                 }\r
577                 else\r
578                 {\r
579                     profile = new frmProfile(instance, name, agentID);\r
580 \r
581                     profile.Disposed += (object sender, EventArgs e) =>\r
582                         {\r
583                             lock (shownProfiles)\r
584                             {\r
585                                 frmProfile agentProfile = (frmProfile)sender;\r
586                                 if (shownProfiles.ContainsKey(agentProfile.AgentID))\r
587                                     shownProfiles.Remove(agentProfile.AgentID);\r
588                             }\r
589                         };\r
590 \r
591                     profile.Show();\r
592                     profile.Focus();\r
593                     shownProfiles.Add(agentID, profile);\r
594                 }\r
595             }\r
596         }\r
597 \r
598         private Dictionary<UUID, frmGroupInfo> shownGroupProfiles = new Dictionary<UUID, frmGroupInfo>();\r
599 \r
600         public void ShowGroupProfile(OpenMetaverse.Group group)\r
601         {\r
602             lock (shownGroupProfiles)\r
603             {\r
604                 frmGroupInfo profile = null;\r
605                 if (shownGroupProfiles.TryGetValue(group.ID, out profile))\r
606                 {\r
607                     profile.WindowState = FormWindowState.Normal;\r
608                     profile.Focus();\r
609                 }\r
610                 else\r
611                 {\r
612                     profile = new frmGroupInfo(instance, group);\r
613 \r
614                     profile.Disposed += (object sender, EventArgs e) =>\r
615                         {\r
616                             lock (shownGroupProfiles)\r
617                             {\r
618                                 frmGroupInfo groupProfile = (frmGroupInfo)sender;\r
619                                 if (shownGroupProfiles.ContainsKey(groupProfile.Group.ID))\r
620                                     shownGroupProfiles.Remove(groupProfile.Group.ID);\r
621                             }\r
622                         };\r
623 \r
624                     profile.Show();\r
625                     profile.Focus();\r
626                     shownGroupProfiles.Add(group.ID, profile);\r
627                 }\r
628             }\r
629         }\r
630 \r
631         public void ProcessLink(string link)\r
632         {\r
633             ProcessLink(link, false);\r
634         }\r
635 \r
636         public bool ProcessLink(string link, bool onlyMap)\r
637         {\r
638             if (!link.Contains("://"))\r
639             {\r
640                 link = "http://" + link;\r
641             }\r
642 \r
643             Regex r = new Regex(@"^(http://slurl.com/secondlife/|secondlife://)([^/]+)/(\d+)/(\d+)(/(\d+))?");\r
644             Match m = r.Match(link);\r
645 \r
646             if (m.Success)\r
647             {\r
648                 string region = HttpUtility.UrlDecode(m.Groups[2].Value);\r
649                 int x = int.Parse(m.Groups[3].Value);\r
650                 int y = int.Parse(m.Groups[4].Value);\r
651                 int z = 0;\r
652 \r
653                 if (m.Groups.Count > 5 && m.Groups[6].Value != String.Empty)\r
654                 {\r
655                     z = int.Parse(m.Groups[6].Value);\r
656                 }\r
657 \r
658                 MapTab.Select();\r
659                 WorldMap.DisplayLocation(region, x, y, z);\r
660                 return true;\r
661             }\r
662             else if (!onlyMap)\r
663             {\r
664                 System.Diagnostics.Process.Start(link);\r
665             }\r
666             return false;\r
667         }\r
668         #endregion\r
669 \r
670         #region Notifications\r
671         CircularList<Control> notifications = new CircularList<Control>();\r
672 \r
673         public Color NotificationBackground\r
674         {\r
675             get { return pnlDialog.BackColor; }\r
676         }\r
677 \r
678         void ResizeNotificationByControl(Control active)\r
679         {\r
680             int Width = active.Size.Width + 6;\r
681             int Height = notifications.Count > 1 ? active.Size.Height + 3 + btnDialogNextControl.Size.Height : active.Size.Height + 3;\r
682             pnlDialog.Size = new Size(Width, Height);\r
683             pnlDialog.Top = 0;\r
684             pnlDialog.Left = pnlDialog.Parent.ClientSize.Width - Width;\r
685 \r
686             btnDialogNextControl.Top = btnDialogNextControl.Parent.ClientSize.Height - btnDialogNextControl.Size.Height;\r
687             btnDialogNextControl.Left = btnDialogNextControl.Parent.ClientSize.Width - btnDialogNextControl.Size.Width;\r
688 \r
689             btnDialogNextControl.BringToFront();\r
690         }\r
691 \r
692         public void AddNotification(Control control)\r
693         {\r
694             if (InvokeRequired)\r
695             {\r
696                 BeginInvoke(new MethodInvoker(delegate()\r
697                 {\r
698                     AddNotification(control);\r
699                 }\r
700                 ));\r
701                 return;\r
702             }\r
703 \r
704             FormFlash.StartFlash(this);\r
705             pnlDialog.Visible = true;\r
706             pnlDialog.BringToFront();\r
707 \r
708             foreach (Control existing in notifications)\r
709             {\r
710                 existing.Visible = false;\r
711             }\r
712 \r
713             notifications.Add(control);\r
714             control.Visible = true;\r
715             control.Anchor = AnchorStyles.Top | AnchorStyles.Left;\r
716             control.Top = 3;\r
717             control.Left = 3;\r
718             pnlDialog.Controls.Add(control);\r
719             ResizeNotificationByControl(control);\r
720 \r
721             btnDialogNextControl.Visible = notifications.Count > 1;\r
722         }\r
723 \r
724         public void RemoveNotification(Control control)\r
725         {\r
726             pnlDialog.Controls.Remove(control);\r
727             notifications.Remove(control);\r
728             control.Dispose();\r
729 \r
730             if (notifications.HasNext)\r
731             {\r
732                 pnlDialog.Visible = true;\r
733                 Control active = notifications.Next;\r
734                 active.Visible = true;\r
735                 ResizeNotificationByControl(active);\r
736             }\r
737             else\r
738             {\r
739                 pnlDialog.Visible = false;\r
740             }\r
741 \r
742             btnDialogNextControl.Visible = notifications.Count > 1;\r
743         }\r
744 \r
745         private void btnDialogNextControl_Click(object sender, EventArgs e)\r
746         {\r
747             foreach (Control existing in notifications)\r
748             {\r
749                 existing.Visible = false;\r
750             }\r
751 \r
752             if (notifications.HasNext)\r
753             {\r
754                 pnlDialog.Visible = true;\r
755                 Control active = notifications.Next;\r
756                 active.Visible = true;\r
757                 ResizeNotificationByControl(active);\r
758             }\r
759             else\r
760             {\r
761                 pnlDialog.Visible = false;\r
762             }\r
763 \r
764         }\r
765         #endregion Notifications\r
766 \r
767         #region Menu click handlers\r
768 \r
769         private void tbtnTeleport_Click(object sender, EventArgs e)\r
770         {\r
771             (new frmTeleport(instance)).ShowDialog();\r
772         }\r
773 \r
774         private void tmnuStatusAway_Click(object sender, EventArgs e)\r
775         {\r
776             instance.State.SetAway(tmnuStatusAway.Checked);\r
777         }\r
778 \r
779         private void tmnuHelpReadme_Click(object sender, EventArgs e)\r
780         {\r
781             System.Diagnostics.Process.Start(Application.StartupPath + @"\Readme.txt");\r
782         }\r
783 \r
784         private void tmnuStatusBusy_Click(object sender, EventArgs e)\r
785         {\r
786             instance.State.SetBusy(tmnuStatusBusy.Checked);\r
787         }\r
788 \r
789         private void tmnuControlFly_Click(object sender, EventArgs e)\r
790         {\r
791             instance.State.SetFlying(tmnuControlFly.Checked);\r
792         }\r
793 \r
794         private void tmnuControlAlwaysRun_Click(object sender, EventArgs e)\r
795         {\r
796             instance.State.SetAlwaysRun(tmnuControlAlwaysRun.Checked);\r
797         }\r
798 \r
799         private void tmnuPrefs_Click(object sender, EventArgs e)\r
800         {\r
801             (new frmSettings(instance)).ShowDialog();\r
802         }\r
803 \r
804         private void tbtnAppearance_Click(object sender, EventArgs e)\r
805         {\r
806             client.Appearance.RequestSetAppearance(false);\r
807         }\r
808 \r
809         private void importObjectToolStripMenuItem_Click(object sender, EventArgs e)\r
810         {\r
811             PrimDeserializer.ImportFromFile(client);\r
812         }\r
813 \r
814         private void autopilotToolStripMenuItem_Click(object sender, EventArgs e)\r
815         {\r
816             if (ap == null)\r
817             {\r
818                 ap = new AutoPilot(client);\r
819                 /*\r
820                 ap.InsertWaypoint(new Vector3(66, 163, 21));\r
821                 ap.InsertWaypoint(new Vector3(66, 98, 21));\r
822 \r
823                 ap.InsertWaypoint(new Vector3(101, 98, 21));\r
824                 ap.InsertWaypoint(new Vector3(101, 45, 21));\r
825                 ap.InsertWaypoint(new Vector3(93, 27, 21));\r
826                 ap.InsertWaypoint(new Vector3(106, 12, 21));\r
827                 ap.InsertWaypoint(new Vector3(123, 24, 21));\r
828                 ap.InsertWaypoint(new Vector3(114, 45, 21));\r
829                 ap.InsertWaypoint(new Vector3(114, 98, 21));\r
830 \r
831                 ap.InsertWaypoint(new Vector3(130, 98, 21));\r
832                 ap.InsertWaypoint(new Vector3(130, 163, 21));\r
833                  **/\r
834                 ap.InsertWaypoint(new Vector3(64, 68, 21));\r
835                 ap.InsertWaypoint(new Vector3(65, 20, 21));\r
836                 ap.InsertWaypoint(new Vector3(33, 23, 21));\r
837                 ap.InsertWaypoint(new Vector3(17, 39, 21));\r
838                 ap.InsertWaypoint(new Vector3(17, 62, 21));\r
839 \r
840 \r
841             }\r
842             if (AutoPilotActive)\r
843             {\r
844                 AutoPilotActive = false;\r
845                 ap.Stop();\r
846             }\r
847             else\r
848             {\r
849                 AutoPilotActive = true;\r
850                 ap.Start();\r
851             }\r
852 \r
853         }\r
854 \r
855         private void cleanCacheToolStripMenuItem_Click(object sender, EventArgs e)\r
856         {\r
857             client.Assets.Cache.Clear();\r
858             DirectoryInfo di = new DirectoryInfo(instance.AnimCacheDir);\r
859             FileInfo[] files = di.GetFiles();\r
860 \r
861             int num = 0;\r
862             foreach (FileInfo file in files)\r
863             {\r
864                 file.Delete();\r
865                 ++num;\r
866             }\r
867 \r
868             Logger.Log("Wiped out " + num + " files from the anim cache directory.", Helpers.LogLevel.Debug);\r
869 \r
870         }\r
871 \r
872         private void rebakeTexturesToolStripMenuItem_Click(object sender, EventArgs e)\r
873         {\r
874             client.Appearance.RequestSetAppearance(true);\r
875         }\r
876 \r
877         public void MapToCurrentLocation()\r
878         {\r
879             if (MapTab != null && client.Network.Connected)\r
880             {\r
881                 MapTab.Select();\r
882                 WorldMap.DisplayLocation(client.Network.CurrentSim.Name,\r
883                     (int)client.Self.SimPosition.X,\r
884                     (int)client.Self.SimPosition.Y,\r
885                     (int)client.Self.SimPosition.Z);\r
886             }\r
887         }\r
888 \r
889         private void standToolStripMenuItem_Click(object sender, EventArgs e)\r
890         {\r
891             client.Self.Stand();\r
892         }\r
893 \r
894         private void groundSitToolStripMenuItem_Click(object sender, EventArgs e)\r
895         {\r
896             client.Self.SitOnGround();\r
897         }\r
898 \r
899         private void newWindowToolStripMenuItem_Click(object sender, EventArgs e)\r
900         {\r
901             try { System.Diagnostics.Process.Start(Application.ExecutablePath); }\r
902             catch (Exception) { }\r
903         }\r
904 \r
905         private void tmnuExit_Click(object sender, EventArgs e)\r
906         {\r
907             Close();\r
908         }\r
909 \r
910         private void tlblRegionInfo_Click(object sender, EventArgs e)\r
911         {\r
912             if (WorldMap != null && client.Network.Connected)\r
913             {\r
914                 MapTab.Select();\r
915             }\r
916         }\r
917 \r
918         private void scriptEditorToolStripMenuItem_Click(object sender, EventArgs e)\r
919         {\r
920             ScriptEditor se = new ScriptEditor(instance);\r
921             se.Dock = DockStyle.Fill;\r
922             se.ShowDetached();\r
923         }\r
924 \r
925         private void tmnuSetHome_Click(object sender, EventArgs e)\r
926         {\r
927             client.Self.SetHome();\r
928         }\r
929 \r
930         private void tmnuCreateLandmark_Click(object sender, EventArgs e)\r
931         {\r
932             string location = string.Format(", {0} ({1}, {2}, {3})",\r
933                 client.Network.CurrentSim.Name,\r
934                 (int)client.Self.SimPosition.X,\r
935                 (int)client.Self.SimPosition.Y,\r
936                 (int)client.Self.SimPosition.Z\r
937                 );\r
938 \r
939             string name = tlblParcel.Text;\r
940             int maxLen = 63 - location.Length;\r
941 \r
942             if (name.Length > maxLen)\r
943                 name = name.Substring(0, maxLen);\r
944 \r
945             name += location;\r
946 \r
947             client.Inventory.RequestCreateItem(\r
948                 client.Inventory.FindFolderForType(AssetType.Landmark),\r
949                 name,\r
950                 tlblParcel.ToolTipText,\r
951                 AssetType.Landmark,\r
952                 UUID.Random(),\r
953                 InventoryType.Landmark,\r
954                 PermissionMask.All,\r
955                 (bool success, InventoryItem item) =>\r
956                 {\r
957                     if (success)\r
958                     {\r
959                         BeginInvoke(new MethodInvoker(() =>\r
960                             {\r
961                                 Landmark ln = new Landmark(instance, (InventoryLandmark)item);\r
962                                 ln.Dock = DockStyle.Fill;\r
963                                 ln.Detached = true;\r
964                             }));\r
965                     }\r
966                 }\r
967             );\r
968         }\r
969 \r
970         private void tmnuTeleportHome_Click(object sender, EventArgs e)\r
971         {\r
972             if (WorldMap != null)\r
973             {\r
974                 WorldMap.GoHome();\r
975             }\r
976         }\r
977 \r
978         private TimeZoneInfo SLTime;\r
979 \r
980         private void GetSLTimeZone()\r
981         {\r
982             try\r
983             {\r
984                 foreach (TimeZoneInfo tz in TimeZoneInfo.GetSystemTimeZones())\r
985                 {\r
986                     if (tz.Id == "Pacific Standard Time" || tz.Id == "America/Los_Angeles")\r
987                     {\r
988                         SLTime = tz;\r
989                         break;\r
990                     }\r
991                 }\r
992             }\r
993             catch (Exception) { }\r
994         }\r
995 \r
996         private void timerWorldClock_Tick(object sender, EventArgs e)\r
997         {\r
998             DateTime now;\r
999             try\r
1000             {\r
1001                 if (SLTime != null)\r
1002                     now = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, SLTime);\r
1003                 else\r
1004                     now = DateTime.UtcNow.AddHours(-7);\r
1005             }\r
1006             catch (Exception)\r
1007             {\r
1008                 now = DateTime.UtcNow.AddHours(-7);\r
1009             }\r
1010             lblTime.Text = now.ToString("h:mm tt", System.Globalization.CultureInfo.InvariantCulture);\r
1011         }\r
1012 \r
1013         private void reportBugsToolStripMenuItem_Click(object sender, EventArgs e)\r
1014         {\r
1015             ProcessLink("http://jira.openmetaverse.org/browse/RAD");\r
1016         }\r
1017 \r
1018         private void aboutRadegastToolStripMenuItem_Click(object sender, EventArgs e)\r
1019         {\r
1020             (new frmAbout(instance)).ShowDialog();\r
1021         }\r
1022 \r
1023         #region Update Checking\r
1024         private UpdateChecker updateChecker = null;\r
1025         private bool ManualUpdateCheck = false;\r
1026 \r
1027         public void StartUpdateCheck(bool userInitiated)\r
1028         {\r
1029             ManualUpdateCheck = userInitiated;\r
1030 \r
1031             if (updateChecker != null)\r
1032             {\r
1033                 if (ManualUpdateCheck)\r
1034                     tabsConsole.DisplayNotificationInChat("Update check already in progress.");\r
1035                 return;\r
1036             }\r
1037 \r
1038             if (ManualUpdateCheck)\r
1039                 tabsConsole.DisplayNotificationInChat("Checking for updates...", ChatBufferTextStyle.StatusBlue);\r
1040             updateChecker = new UpdateChecker();\r
1041             updateChecker.OnUpdateInfoReceived += new UpdateChecker.UpdateInfoCallback(OnUpdateInfoReceived);\r
1042             updateChecker.StartCheck();\r
1043         }\r
1044 \r
1045         private void checkForUpdatesToolStripMenuItem_Click(object sender, EventArgs e)\r
1046         {\r
1047             tabsConsole.SelectTab("chat");\r
1048             StartUpdateCheck(true);\r
1049         }\r
1050 \r
1051         void OnUpdateInfoReceived(object sender, UpdateCheckerArgs e)\r
1052         {\r
1053             if (InvokeRequired)\r
1054             {\r
1055                 BeginInvoke(new MethodInvoker(() => OnUpdateInfoReceived(sender, e)));\r
1056                 return;\r
1057             }\r
1058 \r
1059             if (!e.Success)\r
1060             {\r
1061                 if (ManualUpdateCheck)\r
1062                     tabsConsole.DisplayNotificationInChat("Error: Failed connecting to the update site.", ChatBufferTextStyle.StatusBlue);\r
1063             }\r
1064             else\r
1065             {\r
1066                 if (!ManualUpdateCheck && e.Info.DisplayMOTD)\r
1067                 {\r
1068                     tabsConsole.DisplayNotificationInChat(e.Info.MOTD, ChatBufferTextStyle.StatusBlue);\r
1069                 }\r
1070 \r
1071                 if (e.Info.UpdateAvailable)\r
1072                 {\r
1073                     tabsConsole.DisplayNotificationInChat("New version available at " + e.Info.DownloadSite, ChatBufferTextStyle.Alert);\r
1074                 }\r
1075                 else\r
1076                 {\r
1077                     if (ManualUpdateCheck)\r
1078                         tabsConsole.DisplayNotificationInChat("Your version is up to date.", ChatBufferTextStyle.StatusBlue);\r
1079                 }\r
1080             }\r
1081 \r
1082             updateChecker.Dispose();\r
1083             updateChecker = null;\r
1084         }\r
1085         #endregion\r
1086 \r
1087         private void ToggleHidden(string tabName)\r
1088         {\r
1089             if (!tabsConsole.TabExists(tabName)) return;\r
1090 \r
1091             RadegastTab tab = tabsConsole.Tabs[tabName];\r
1092 \r
1093             if (tab.Hidden)\r
1094             {\r
1095                 tab.Show();\r
1096             }\r
1097             else\r
1098             {\r
1099                 if (!tab.Selected)\r
1100                 {\r
1101                     tab.Select();\r
1102                 }\r
1103                 else\r
1104                 {\r
1105                     tab.Hide();\r
1106                 }\r
1107             }\r
1108         }\r
1109 \r
1110         private void tbtnFriends_Click(object sender, EventArgs e)\r
1111         {\r
1112             ToggleHidden("friends");\r
1113         }\r
1114 \r
1115         private void tbtnInventory_Click(object sender, EventArgs e)\r
1116         {\r
1117             ToggleHidden("inventory");\r
1118         }\r
1119 \r
1120         private void tbtnSearch_Click(object sender, EventArgs e)\r
1121         {\r
1122             ToggleHidden("search");\r
1123         }\r
1124 \r
1125         private void tbtnGroups_Click(object sender, EventArgs e)\r
1126         {\r
1127             ToggleHidden("groups");\r
1128         }\r
1129 \r
1130         private void tbtnMedia_Click(object sender, EventArgs e)\r
1131         {\r
1132             if (tabsConsole.TabExists("media"))\r
1133             {\r
1134                 ToggleHidden("media");\r
1135             }\r
1136             else\r
1137             {\r
1138                 RadegastTab tab = tabsConsole.AddTab("media", "Media", mediaConsole);\r
1139                 tab.AllowClose = false;\r
1140                 tab.AllowHide = true;\r
1141                 tab.Select();\r
1142             }\r
1143         }\r
1144 \r
1145         private void tbnObjects_Click(object sender, EventArgs e)\r
1146         {\r
1147             if (tabsConsole.TabExists("objects"))\r
1148             {\r
1149                 RadegastTab tab = tabsConsole.Tabs["objects"];\r
1150                 if (!tab.Selected)\r
1151                 {\r
1152                     tab.Select();\r
1153                     ((ObjectsConsole)tab.Control).RefreshObjectList();\r
1154                 }\r
1155                 else\r
1156                 {\r
1157                     tab.Close();\r
1158                 }\r
1159             }\r
1160             else\r
1161             {\r
1162                 RadegastTab tab = tabsConsole.AddTab("objects", "Objects", new ObjectsConsole(instance));\r
1163                 tab.AllowClose = true;\r
1164                 tab.AllowDetach = true;\r
1165                 tab.Visible = true;\r
1166                 tab.AllowHide = false;\r
1167                 tab.Select();\r
1168                 ((ObjectsConsole)tab.Control).RefreshObjectList();\r
1169             }\r
1170         }\r
1171 \r
1172         private void tbtnMap_Click(object sender, EventArgs e)\r
1173         {\r
1174             ToggleHidden("map");\r
1175             if (!MapTab.Hidden)\r
1176                 MapToCurrentLocation();\r
1177         }\r
1178 \r
1179         private void disconnectToolStripMenuItem_Click(object sender, EventArgs e)\r
1180         {\r
1181             if (client.Network.Connected)\r
1182                 client.Network.RequestLogout();\r
1183         }\r
1184 \r
1185         private void reconnectToolStripMenuItem_Click(object sender, EventArgs e)\r
1186         {\r
1187             instance.Reconnect();\r
1188         }\r
1189         #endregion\r
1190     }\r
1191 }