OSDN Git Service

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