OSDN Git Service

Added Help -> Keyboard Shortcuts
[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             // Ctl-Shift-H: Teleport Home\r
484             if (e.Modifiers == (Keys.Control | Keys.Shift) && e.KeyCode == Keys.H)\r
485             {\r
486                 e.Handled = e.SuppressKeyPress = true;\r
487                 tmnuTeleportHome.PerformClick();\r
488                 return;\r
489             }\r
490 \r
491             // Alt 1-8: Toggle various tabs\r
492             if (e.Modifiers == Keys.Alt)\r
493             {\r
494                 switch (e.KeyCode)\r
495                 {\r
496                     case Keys.D1:\r
497                         e.Handled = e.SuppressKeyPress = true;\r
498                         tabsConsole.Tabs["chat"].Select();\r
499                         break;\r
500 \r
501                     case Keys.D2:\r
502                         e.Handled = e.SuppressKeyPress = true;\r
503                         tbtnFriends.PerformClick();\r
504                         break;\r
505 \r
506                     case Keys.D3:\r
507                         e.Handled = e.SuppressKeyPress = true;\r
508                         tbtnGroups.PerformClick();\r
509                         break;\r
510 \r
511                     case Keys.D4:\r
512                         e.Handled = e.SuppressKeyPress = true;\r
513                         tbtnInventory.PerformClick();\r
514                         break;\r
515 \r
516                     case Keys.D5:\r
517                         e.Handled = e.SuppressKeyPress = true;\r
518                         tbtnSearch.PerformClick();\r
519                         break;\r
520 \r
521                     case Keys.D6:\r
522                         e.Handled = e.SuppressKeyPress = true;\r
523                         tbtnMap.PerformClick();\r
524                         break;\r
525 \r
526                     case Keys.D7:\r
527                         e.Handled = e.SuppressKeyPress = true;\r
528                         tbnObjects.PerformClick();\r
529                         break;\r
530 \r
531                     case Keys.D8:\r
532                         e.Handled = e.SuppressKeyPress = true;\r
533                         tbtnMedia.PerformClick();\r
534                         break;\r
535                 }\r
536             }\r
537 \r
538             // ctrl-g, goto slurl\r
539             if (e.Control && e.KeyCode == Keys.G)\r
540             {\r
541                 if (!ProcessLink(Clipboard.GetText(), true))\r
542                     MapToCurrentLocation();\r
543 \r
544                 e.Handled = e.SuppressKeyPress = true;\r
545                 return;\r
546             }\r
547 \r
548             // ctrl-(shift)-tab for next/previous tab\r
549             if (e.Control && e.KeyCode == Keys.Tab)\r
550             {\r
551                 if (e.Shift)\r
552                 {\r
553                     TabConsole.SelectPreviousTab();\r
554                 }\r
555                 else\r
556                 {\r
557                     TabConsole.SelectNextTab();\r
558                 }\r
559                 e.Handled = e.SuppressKeyPress = true;\r
560                 return;\r
561             }\r
562         }\r
563 \r
564         private void frmMain_KeyUp(object sender, KeyEventArgs e)\r
565         {\r
566         }\r
567 \r
568         private void frmMain_Load(object sender, EventArgs e)\r
569         {\r
570             tabsConsole.SelectTab("login");\r
571             ResourceManager rm = Properties.Resources.ResourceManager;\r
572             ResourceSet set = rm.GetResourceSet(System.Globalization.CultureInfo.CurrentCulture, true, true);\r
573             System.Collections.IDictionaryEnumerator de = set.GetEnumerator();\r
574             while (de.MoveNext() == true)\r
575             {\r
576                 if (de.Entry.Value is Image)\r
577                 {\r
578                     Bitmap bitMap = de.Entry.Value as Bitmap;\r
579                     ResourceImages.Images.Add(bitMap);\r
580                     ImageNames.Add(de.Entry.Key.ToString());\r
581                 }\r
582             }\r
583             StartUpdateCheck(false);\r
584         }\r
585         #endregion\r
586 \r
587         #region Public methods\r
588 \r
589         private Dictionary<UUID, frmProfile> shownProfiles = new Dictionary<UUID, frmProfile>();\r
590 \r
591         public void ShowAgentProfile(string name, UUID agentID)\r
592         {\r
593             lock (shownProfiles)\r
594             {\r
595                 frmProfile profile = null;\r
596                 if (shownProfiles.TryGetValue(agentID, out profile))\r
597                 {\r
598                     profile.WindowState = FormWindowState.Normal;\r
599                     profile.Focus();\r
600                 }\r
601                 else\r
602                 {\r
603                     profile = new frmProfile(instance, name, agentID);\r
604 \r
605                     profile.Disposed += (object sender, EventArgs e) =>\r
606                         {\r
607                             lock (shownProfiles)\r
608                             {\r
609                                 frmProfile agentProfile = (frmProfile)sender;\r
610                                 if (shownProfiles.ContainsKey(agentProfile.AgentID))\r
611                                     shownProfiles.Remove(agentProfile.AgentID);\r
612                             }\r
613                         };\r
614 \r
615                     profile.Show();\r
616                     profile.Focus();\r
617                     shownProfiles.Add(agentID, profile);\r
618                 }\r
619             }\r
620         }\r
621 \r
622         private Dictionary<UUID, frmGroupInfo> shownGroupProfiles = new Dictionary<UUID, frmGroupInfo>();\r
623 \r
624         public void ShowGroupProfile(OpenMetaverse.Group group)\r
625         {\r
626             lock (shownGroupProfiles)\r
627             {\r
628                 frmGroupInfo profile = null;\r
629                 if (shownGroupProfiles.TryGetValue(group.ID, out profile))\r
630                 {\r
631                     profile.WindowState = FormWindowState.Normal;\r
632                     profile.Focus();\r
633                 }\r
634                 else\r
635                 {\r
636                     profile = new frmGroupInfo(instance, group);\r
637 \r
638                     profile.Disposed += (object sender, EventArgs e) =>\r
639                         {\r
640                             lock (shownGroupProfiles)\r
641                             {\r
642                                 frmGroupInfo groupProfile = (frmGroupInfo)sender;\r
643                                 if (shownGroupProfiles.ContainsKey(groupProfile.Group.ID))\r
644                                     shownGroupProfiles.Remove(groupProfile.Group.ID);\r
645                             }\r
646                         };\r
647 \r
648                     profile.Show();\r
649                     profile.Focus();\r
650                     shownGroupProfiles.Add(group.ID, profile);\r
651                 }\r
652             }\r
653         }\r
654 \r
655         public void ProcessLink(string link)\r
656         {\r
657             ProcessLink(link, false);\r
658         }\r
659 \r
660         public bool ProcessLink(string link, bool onlyMap)\r
661         {\r
662             if (!link.Contains("://"))\r
663             {\r
664                 link = "http://" + link;\r
665             }\r
666 \r
667             Regex r = new Regex(@"^(http://slurl.com/secondlife/|secondlife://)([^/]+)/(\d+)/(\d+)(/(\d+))?");\r
668             Match m = r.Match(link);\r
669 \r
670             if (m.Success)\r
671             {\r
672                 string region = HttpUtility.UrlDecode(m.Groups[2].Value);\r
673                 int x = int.Parse(m.Groups[3].Value);\r
674                 int y = int.Parse(m.Groups[4].Value);\r
675                 int z = 0;\r
676 \r
677                 if (m.Groups.Count > 5 && m.Groups[6].Value != String.Empty)\r
678                 {\r
679                     z = int.Parse(m.Groups[6].Value);\r
680                 }\r
681 \r
682                 MapTab.Select();\r
683                 WorldMap.DisplayLocation(region, x, y, z);\r
684                 return true;\r
685             }\r
686             else if (!onlyMap)\r
687             {\r
688                 System.Diagnostics.Process.Start(link);\r
689             }\r
690             return false;\r
691         }\r
692         #endregion\r
693 \r
694         #region Notifications\r
695         CircularList<Control> notifications = new CircularList<Control>();\r
696 \r
697         public Color NotificationBackground\r
698         {\r
699             get { return pnlDialog.BackColor; }\r
700         }\r
701 \r
702         void ResizeNotificationByControl(Control active)\r
703         {\r
704             int Width = active.Size.Width + 6;\r
705             int Height = notifications.Count > 1 ? active.Size.Height + 3 + btnDialogNextControl.Size.Height : active.Size.Height + 3;\r
706             pnlDialog.Size = new Size(Width, Height);\r
707             pnlDialog.Top = 0;\r
708             pnlDialog.Left = pnlDialog.Parent.ClientSize.Width - Width;\r
709 \r
710             btnDialogNextControl.Top = btnDialogNextControl.Parent.ClientSize.Height - btnDialogNextControl.Size.Height;\r
711             btnDialogNextControl.Left = btnDialogNextControl.Parent.ClientSize.Width - btnDialogNextControl.Size.Width;\r
712 \r
713             btnDialogNextControl.BringToFront();\r
714         }\r
715 \r
716         public void AddNotification(Control control)\r
717         {\r
718             if (InvokeRequired)\r
719             {\r
720                 BeginInvoke(new MethodInvoker(delegate()\r
721                 {\r
722                     AddNotification(control);\r
723                 }\r
724                 ));\r
725                 return;\r
726             }\r
727 \r
728             FormFlash.StartFlash(this);\r
729             pnlDialog.Visible = true;\r
730             pnlDialog.BringToFront();\r
731 \r
732             foreach (Control existing in notifications)\r
733             {\r
734                 existing.Visible = false;\r
735             }\r
736 \r
737             notifications.Add(control);\r
738             control.Visible = true;\r
739             control.Anchor = AnchorStyles.Top | AnchorStyles.Left;\r
740             control.Top = 3;\r
741             control.Left = 3;\r
742             pnlDialog.Controls.Add(control);\r
743             ResizeNotificationByControl(control);\r
744 \r
745             btnDialogNextControl.Visible = notifications.Count > 1;\r
746         }\r
747 \r
748         public void RemoveNotification(Control control)\r
749         {\r
750             pnlDialog.Controls.Remove(control);\r
751             notifications.Remove(control);\r
752             control.Dispose();\r
753 \r
754             if (notifications.HasNext)\r
755             {\r
756                 pnlDialog.Visible = true;\r
757                 Control active = notifications.Next;\r
758                 active.Visible = true;\r
759                 ResizeNotificationByControl(active);\r
760             }\r
761             else\r
762             {\r
763                 pnlDialog.Visible = false;\r
764             }\r
765 \r
766             btnDialogNextControl.Visible = notifications.Count > 1;\r
767         }\r
768 \r
769         private void btnDialogNextControl_Click(object sender, EventArgs e)\r
770         {\r
771             foreach (Control existing in notifications)\r
772             {\r
773                 existing.Visible = false;\r
774             }\r
775 \r
776             if (notifications.HasNext)\r
777             {\r
778                 pnlDialog.Visible = true;\r
779                 Control active = notifications.Next;\r
780                 active.Visible = true;\r
781                 ResizeNotificationByControl(active);\r
782             }\r
783             else\r
784             {\r
785                 pnlDialog.Visible = false;\r
786             }\r
787 \r
788         }\r
789         #endregion Notifications\r
790 \r
791         #region Menu click handlers\r
792 \r
793         private void tbtnTeleport_Click(object sender, EventArgs e)\r
794         {\r
795             (new frmTeleport(instance)).ShowDialog();\r
796         }\r
797 \r
798         private void tmnuStatusAway_Click(object sender, EventArgs e)\r
799         {\r
800             instance.State.SetAway(tmnuStatusAway.Checked);\r
801         }\r
802 \r
803         private void tmnuHelpReadme_Click(object sender, EventArgs e)\r
804         {\r
805             System.Diagnostics.Process.Start(Application.StartupPath + @"\Readme.txt");\r
806         }\r
807 \r
808         private void tmnuStatusBusy_Click(object sender, EventArgs e)\r
809         {\r
810             instance.State.SetBusy(tmnuStatusBusy.Checked);\r
811         }\r
812 \r
813         private void tmnuControlFly_Click(object sender, EventArgs e)\r
814         {\r
815             instance.State.SetFlying(tmnuControlFly.Checked);\r
816         }\r
817 \r
818         private void tmnuControlAlwaysRun_Click(object sender, EventArgs e)\r
819         {\r
820             instance.State.SetAlwaysRun(tmnuControlAlwaysRun.Checked);\r
821         }\r
822 \r
823         private void tmnuPrefs_Click(object sender, EventArgs e)\r
824         {\r
825             (new frmSettings(instance)).ShowDialog();\r
826         }\r
827 \r
828         private void tbtnAppearance_Click(object sender, EventArgs e)\r
829         {\r
830             client.Appearance.RequestSetAppearance(false);\r
831         }\r
832 \r
833         private void importObjectToolStripMenuItem_Click(object sender, EventArgs e)\r
834         {\r
835             PrimDeserializer.ImportFromFile(client);\r
836         }\r
837 \r
838         private void autopilotToolStripMenuItem_Click(object sender, EventArgs e)\r
839         {\r
840             if (ap == null)\r
841             {\r
842                 ap = new AutoPilot(client);\r
843                 /*\r
844                 ap.InsertWaypoint(new Vector3(66, 163, 21));\r
845                 ap.InsertWaypoint(new Vector3(66, 98, 21));\r
846 \r
847                 ap.InsertWaypoint(new Vector3(101, 98, 21));\r
848                 ap.InsertWaypoint(new Vector3(101, 45, 21));\r
849                 ap.InsertWaypoint(new Vector3(93, 27, 21));\r
850                 ap.InsertWaypoint(new Vector3(106, 12, 21));\r
851                 ap.InsertWaypoint(new Vector3(123, 24, 21));\r
852                 ap.InsertWaypoint(new Vector3(114, 45, 21));\r
853                 ap.InsertWaypoint(new Vector3(114, 98, 21));\r
854 \r
855                 ap.InsertWaypoint(new Vector3(130, 98, 21));\r
856                 ap.InsertWaypoint(new Vector3(130, 163, 21));\r
857                  **/\r
858                 ap.InsertWaypoint(new Vector3(64, 68, 21));\r
859                 ap.InsertWaypoint(new Vector3(65, 20, 21));\r
860                 ap.InsertWaypoint(new Vector3(33, 23, 21));\r
861                 ap.InsertWaypoint(new Vector3(17, 39, 21));\r
862                 ap.InsertWaypoint(new Vector3(17, 62, 21));\r
863 \r
864 \r
865             }\r
866             if (AutoPilotActive)\r
867             {\r
868                 AutoPilotActive = false;\r
869                 ap.Stop();\r
870             }\r
871             else\r
872             {\r
873                 AutoPilotActive = true;\r
874                 ap.Start();\r
875             }\r
876 \r
877         }\r
878 \r
879         private void cleanCacheToolStripMenuItem_Click(object sender, EventArgs e)\r
880         {\r
881             client.Assets.Cache.Clear();\r
882             DirectoryInfo di = new DirectoryInfo(instance.AnimCacheDir);\r
883             FileInfo[] files = di.GetFiles();\r
884 \r
885             int num = 0;\r
886             foreach (FileInfo file in files)\r
887             {\r
888                 file.Delete();\r
889                 ++num;\r
890             }\r
891 \r
892             Logger.Log("Wiped out " + num + " files from the anim cache directory.", Helpers.LogLevel.Debug);\r
893 \r
894         }\r
895 \r
896         private void rebakeTexturesToolStripMenuItem_Click(object sender, EventArgs e)\r
897         {\r
898             client.Appearance.RequestSetAppearance(true);\r
899         }\r
900 \r
901         public void MapToCurrentLocation()\r
902         {\r
903             if (MapTab != null && client.Network.Connected)\r
904             {\r
905                 MapTab.Select();\r
906                 WorldMap.DisplayLocation(client.Network.CurrentSim.Name,\r
907                     (int)client.Self.SimPosition.X,\r
908                     (int)client.Self.SimPosition.Y,\r
909                     (int)client.Self.SimPosition.Z);\r
910             }\r
911         }\r
912 \r
913         private void standToolStripMenuItem_Click(object sender, EventArgs e)\r
914         {\r
915             client.Self.Stand();\r
916         }\r
917 \r
918         private void groundSitToolStripMenuItem_Click(object sender, EventArgs e)\r
919         {\r
920             client.Self.SitOnGround();\r
921         }\r
922 \r
923         private void newWindowToolStripMenuItem_Click(object sender, EventArgs e)\r
924         {\r
925             try { System.Diagnostics.Process.Start(Application.ExecutablePath); }\r
926             catch (Exception) { }\r
927         }\r
928 \r
929         private void tmnuExit_Click(object sender, EventArgs e)\r
930         {\r
931             Close();\r
932         }\r
933 \r
934         private void tlblRegionInfo_Click(object sender, EventArgs e)\r
935         {\r
936             if (WorldMap != null && client.Network.Connected)\r
937             {\r
938                 MapTab.Select();\r
939             }\r
940         }\r
941 \r
942         private void scriptEditorToolStripMenuItem_Click(object sender, EventArgs e)\r
943         {\r
944             ScriptEditor se = new ScriptEditor(instance);\r
945             se.Dock = DockStyle.Fill;\r
946             se.ShowDetached();\r
947         }\r
948 \r
949         private void tmnuSetHome_Click(object sender, EventArgs e)\r
950         {\r
951             client.Self.SetHome();\r
952         }\r
953 \r
954         private void tmnuCreateLandmark_Click(object sender, EventArgs e)\r
955         {\r
956             string location = string.Format(", {0} ({1}, {2}, {3})",\r
957                 client.Network.CurrentSim.Name,\r
958                 (int)client.Self.SimPosition.X,\r
959                 (int)client.Self.SimPosition.Y,\r
960                 (int)client.Self.SimPosition.Z\r
961                 );\r
962 \r
963             string name = tlblParcel.Text;\r
964             int maxLen = 63 - location.Length;\r
965 \r
966             if (name.Length > maxLen)\r
967                 name = name.Substring(0, maxLen);\r
968 \r
969             name += location;\r
970 \r
971             client.Inventory.RequestCreateItem(\r
972                 client.Inventory.FindFolderForType(AssetType.Landmark),\r
973                 name,\r
974                 tlblParcel.ToolTipText,\r
975                 AssetType.Landmark,\r
976                 UUID.Random(),\r
977                 InventoryType.Landmark,\r
978                 PermissionMask.All,\r
979                 (bool success, InventoryItem item) =>\r
980                 {\r
981                     if (success)\r
982                     {\r
983                         BeginInvoke(new MethodInvoker(() =>\r
984                             {\r
985                                 Landmark ln = new Landmark(instance, (InventoryLandmark)item);\r
986                                 ln.Dock = DockStyle.Fill;\r
987                                 ln.Detached = true;\r
988                             }));\r
989                     }\r
990                 }\r
991             );\r
992         }\r
993 \r
994         private void tmnuTeleportHome_Click(object sender, EventArgs e)\r
995         {\r
996             if (WorldMap != null)\r
997             {\r
998                 WorldMap.GoHome();\r
999             }\r
1000         }\r
1001 \r
1002         private TimeZoneInfo SLTime;\r
1003 \r
1004         private void GetSLTimeZone()\r
1005         {\r
1006             try\r
1007             {\r
1008                 foreach (TimeZoneInfo tz in TimeZoneInfo.GetSystemTimeZones())\r
1009                 {\r
1010                     if (tz.Id == "Pacific Standard Time" || tz.Id == "America/Los_Angeles")\r
1011                     {\r
1012                         SLTime = tz;\r
1013                         break;\r
1014                     }\r
1015                 }\r
1016             }\r
1017             catch (Exception) { }\r
1018         }\r
1019 \r
1020         private void timerWorldClock_Tick(object sender, EventArgs e)\r
1021         {\r
1022             DateTime now;\r
1023             try\r
1024             {\r
1025                 if (SLTime != null)\r
1026                     now = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, SLTime);\r
1027                 else\r
1028                     now = DateTime.UtcNow.AddHours(-7);\r
1029             }\r
1030             catch (Exception)\r
1031             {\r
1032                 now = DateTime.UtcNow.AddHours(-7);\r
1033             }\r
1034             lblTime.Text = now.ToString("h:mm tt", System.Globalization.CultureInfo.InvariantCulture);\r
1035         }\r
1036 \r
1037         private void reportBugsToolStripMenuItem_Click(object sender, EventArgs e)\r
1038         {\r
1039             ProcessLink("http://jira.openmetaverse.org/browse/RAD");\r
1040         }\r
1041 \r
1042         private void aboutRadegastToolStripMenuItem_Click(object sender, EventArgs e)\r
1043         {\r
1044             (new frmAbout(instance)).ShowDialog();\r
1045         }\r
1046 \r
1047         #region Update Checking\r
1048         private UpdateChecker updateChecker = null;\r
1049         private bool ManualUpdateCheck = false;\r
1050 \r
1051         public void StartUpdateCheck(bool userInitiated)\r
1052         {\r
1053             ManualUpdateCheck = userInitiated;\r
1054 \r
1055             if (updateChecker != null)\r
1056             {\r
1057                 if (ManualUpdateCheck)\r
1058                     tabsConsole.DisplayNotificationInChat("Update check already in progress.");\r
1059                 return;\r
1060             }\r
1061 \r
1062             if (ManualUpdateCheck)\r
1063                 tabsConsole.DisplayNotificationInChat("Checking for updates...", ChatBufferTextStyle.StatusBlue);\r
1064             updateChecker = new UpdateChecker();\r
1065             updateChecker.OnUpdateInfoReceived += new UpdateChecker.UpdateInfoCallback(OnUpdateInfoReceived);\r
1066             updateChecker.StartCheck();\r
1067         }\r
1068 \r
1069         private void checkForUpdatesToolStripMenuItem_Click(object sender, EventArgs e)\r
1070         {\r
1071             tabsConsole.SelectTab("chat");\r
1072             StartUpdateCheck(true);\r
1073         }\r
1074 \r
1075         void OnUpdateInfoReceived(object sender, UpdateCheckerArgs e)\r
1076         {\r
1077             if (InvokeRequired)\r
1078             {\r
1079                 BeginInvoke(new MethodInvoker(() => OnUpdateInfoReceived(sender, e)));\r
1080                 return;\r
1081             }\r
1082 \r
1083             if (!e.Success)\r
1084             {\r
1085                 if (ManualUpdateCheck)\r
1086                     tabsConsole.DisplayNotificationInChat("Error: Failed connecting to the update site.", ChatBufferTextStyle.StatusBlue);\r
1087             }\r
1088             else\r
1089             {\r
1090                 if (!ManualUpdateCheck && e.Info.DisplayMOTD)\r
1091                 {\r
1092                     tabsConsole.DisplayNotificationInChat(e.Info.MOTD, ChatBufferTextStyle.StatusBlue);\r
1093                 }\r
1094 \r
1095                 if (e.Info.UpdateAvailable)\r
1096                 {\r
1097                     tabsConsole.DisplayNotificationInChat("New version available at " + e.Info.DownloadSite, ChatBufferTextStyle.Alert);\r
1098                 }\r
1099                 else\r
1100                 {\r
1101                     if (ManualUpdateCheck)\r
1102                         tabsConsole.DisplayNotificationInChat("Your version is up to date.", ChatBufferTextStyle.StatusBlue);\r
1103                 }\r
1104             }\r
1105 \r
1106             updateChecker.Dispose();\r
1107             updateChecker = null;\r
1108         }\r
1109         #endregion\r
1110 \r
1111         private void ToggleHidden(string tabName)\r
1112         {\r
1113             if (!tabsConsole.TabExists(tabName)) return;\r
1114 \r
1115             RadegastTab tab = tabsConsole.Tabs[tabName];\r
1116 \r
1117             if (tab.Hidden)\r
1118             {\r
1119                 tab.Show();\r
1120             }\r
1121             else\r
1122             {\r
1123                 if (!tab.Selected)\r
1124                 {\r
1125                     tab.Select();\r
1126                 }\r
1127                 else\r
1128                 {\r
1129                     tab.Hide();\r
1130                 }\r
1131             }\r
1132         }\r
1133 \r
1134         private void tbtnFriends_Click(object sender, EventArgs e)\r
1135         {\r
1136             ToggleHidden("friends");\r
1137         }\r
1138 \r
1139         private void tbtnInventory_Click(object sender, EventArgs e)\r
1140         {\r
1141             ToggleHidden("inventory");\r
1142         }\r
1143 \r
1144         private void tbtnSearch_Click(object sender, EventArgs e)\r
1145         {\r
1146             ToggleHidden("search");\r
1147         }\r
1148 \r
1149         private void tbtnGroups_Click(object sender, EventArgs e)\r
1150         {\r
1151             ToggleHidden("groups");\r
1152         }\r
1153 \r
1154         private void tbtnMedia_Click(object sender, EventArgs e)\r
1155         {\r
1156             if (tabsConsole.TabExists("media"))\r
1157             {\r
1158                 ToggleHidden("media");\r
1159             }\r
1160             else\r
1161             {\r
1162                 RadegastTab tab = tabsConsole.AddTab("media", "Media", mediaConsole);\r
1163                 tab.AllowClose = false;\r
1164                 tab.AllowHide = true;\r
1165                 tab.Select();\r
1166             }\r
1167         }\r
1168 \r
1169         private void tbnObjects_Click(object sender, EventArgs e)\r
1170         {\r
1171             if (tabsConsole.TabExists("objects"))\r
1172             {\r
1173                 RadegastTab tab = tabsConsole.Tabs["objects"];\r
1174                 if (!tab.Selected)\r
1175                 {\r
1176                     tab.Select();\r
1177                     ((ObjectsConsole)tab.Control).RefreshObjectList();\r
1178                 }\r
1179                 else\r
1180                 {\r
1181                     tab.Close();\r
1182                 }\r
1183             }\r
1184             else\r
1185             {\r
1186                 RadegastTab tab = tabsConsole.AddTab("objects", "Objects", new ObjectsConsole(instance));\r
1187                 tab.AllowClose = true;\r
1188                 tab.AllowDetach = true;\r
1189                 tab.Visible = true;\r
1190                 tab.AllowHide = false;\r
1191                 tab.Select();\r
1192                 ((ObjectsConsole)tab.Control).RefreshObjectList();\r
1193             }\r
1194         }\r
1195 \r
1196         private void tbtnMap_Click(object sender, EventArgs e)\r
1197         {\r
1198             ToggleHidden("map");\r
1199             if (!MapTab.Hidden)\r
1200                 MapToCurrentLocation();\r
1201         }\r
1202 \r
1203         private void disconnectToolStripMenuItem_Click(object sender, EventArgs e)\r
1204         {\r
1205             if (client.Network.Connected)\r
1206                 client.Network.RequestLogout();\r
1207         }\r
1208 \r
1209         private void reconnectToolStripMenuItem_Click(object sender, EventArgs e)\r
1210         {\r
1211             instance.Reconnect();\r
1212         }\r
1213 \r
1214         private frmKeyboardShortcuts keyboardShortcutsForm = null;\r
1215         private void keyboardShortcutsToolStripMenuItem_Click(object sender, EventArgs e)\r
1216         {\r
1217             if (keyboardShortcutsForm != null)\r
1218             {\r
1219                 keyboardShortcutsForm.Focus();\r
1220             }\r
1221             else\r
1222             {\r
1223                 keyboardShortcutsForm = new frmKeyboardShortcuts(instance);\r
1224 \r
1225                 keyboardShortcutsForm.Disposed += (object senderx, EventArgs ex) =>\r
1226                     {\r
1227                         if (components != null)\r
1228                         {\r
1229                             components.Remove(keyboardShortcutsForm);\r
1230                         }\r
1231                         keyboardShortcutsForm = null;\r
1232                     };\r
1233 \r
1234                 keyboardShortcutsForm.Show(this);\r
1235                 keyboardShortcutsForm.Top = Top + 100;\r
1236                 keyboardShortcutsForm.Left = Left + 100;\r
1237 \r
1238                 if (components != null)\r
1239                 {\r
1240                     components.Add(keyboardShortcutsForm);\r
1241                 }\r
1242             }\r
1243         }\r
1244         #endregion\r
1245 \r
1246     }\r
1247 }