OSDN Git Service

Made media into a tab.
[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 RadegastNetcom netcom;\r
118         private GridClient client;\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             client = this.instance.Client;\r
137             netcom = this.instance.Netcom;\r
138             netcom.NetcomSync = this;\r
139 \r
140             pnlDialog.Visible = false;\r
141             btnDialogNextControl = new TransparentButton();\r
142             pnlDialog.Controls.Add(btnDialogNextControl);\r
143             pnlDialog.Top = 0;\r
144 \r
145             btnDialogNextControl.Size = new Size(35, 20);\r
146             btnDialogNextControl.BackColor = Color.Transparent;\r
147             btnDialogNextControl.ForeColor = Color.Gold;\r
148             btnDialogNextControl.FlatAppearance.BorderSize = 0;\r
149             btnDialogNextControl.FlatStyle = FlatStyle.Flat;\r
150             btnDialogNextControl.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;\r
151             btnDialogNextControl.Text = ">>";\r
152             btnDialogNextControl.Font = new Font(btnDialogNextControl.Font, FontStyle.Bold);\r
153             btnDialogNextControl.Margin = new Padding(0);\r
154             btnDialogNextControl.Padding = new Padding(0);\r
155             btnDialogNextControl.UseVisualStyleBackColor = false;\r
156             btnDialogNextControl.Top = btnDialogNextControl.Parent.ClientSize.Height - btnDialogNextControl.Size.Height;\r
157             btnDialogNextControl.Left = btnDialogNextControl.Parent.ClientSize.Width - btnDialogNextControl.Size.Width;\r
158             btnDialogNextControl.Click += new EventHandler(btnDialogNextControl_Click);\r
159 \r
160             if (instance.MonoRuntime)\r
161             {\r
162                 statusStrip1.LayoutStyle = ToolStripLayoutStyle.Table;\r
163             }\r
164 \r
165             // Config options\r
166             if (instance.GlobalSettings["transaction_notification_chat"].Type == OSDType.Unknown)\r
167                 instance.GlobalSettings["transaction_notification_chat"] = OSD.FromBoolean(true);\r
168 \r
169             if (instance.GlobalSettings["transaction_notification_dialog"].Type == OSDType.Unknown)\r
170                 instance.GlobalSettings["transaction_notification_dialog"] = OSD.FromBoolean(true);\r
171 \r
172             // Callbacks\r
173             netcom.ClientLoginStatus += new EventHandler<ClientLoginEventArgs>(netcom_ClientLoginStatus);\r
174             netcom.ClientLoggedOut += new EventHandler(netcom_ClientLoggedOut);\r
175             netcom.ClientDisconnected += new EventHandler<ClientDisconnectEventArgs>(netcom_ClientDisconnected);\r
176             client.Parcels.OnParcelProperties += new ParcelManager.ParcelPropertiesCallback(Parcels_OnParcelProperties);\r
177             client.Self.OnMoneyBalanceReplyReceived += new AgentManager.MoneyBalanceReplyCallback(Self_OnMoneyBalanceReplyReceived);\r
178 \r
179             InitializeStatusTimer();\r
180             RefreshWindowTitle();\r
181         }\r
182 \r
183         void frmMain_Disposed(object sender, EventArgs e)\r
184         {\r
185             netcom.ClientLoginStatus -= new EventHandler<ClientLoginEventArgs>(netcom_ClientLoginStatus);\r
186             netcom.ClientLoggedOut -= new EventHandler(netcom_ClientLoggedOut);\r
187             netcom.ClientDisconnected -= new EventHandler<ClientDisconnectEventArgs>(netcom_ClientDisconnected);\r
188             client.Parcels.OnParcelProperties -= new ParcelManager.ParcelPropertiesCallback(Parcels_OnParcelProperties);\r
189             client.Self.OnMoneyBalanceReplyReceived -= new AgentManager.MoneyBalanceReplyCallback(Self_OnMoneyBalanceReplyReceived);\r
190             this.instance.CleanUp();\r
191         }\r
192         #endregion\r
193 \r
194         #region Event handlers\r
195         void Self_OnMoneyBalanceReplyReceived(UUID transactionID, bool transactionSuccess, int balance, int metersCredit, int metersCommitted, string description)\r
196         {\r
197             if (!String.IsNullOrEmpty(description))\r
198             {\r
199                 if (instance.GlobalSettings["transaction_notification_dialog"].AsBoolean())\r
200                     AddNotification(new ntfGeneric(instance, description));\r
201                 if (instance.GlobalSettings["transaction_notification_chat"].AsBoolean())\r
202                     TabConsole.DisplayNotificationInChat(description);\r
203             }\r
204         }\r
205 \r
206         public void InitializeControls()\r
207         {\r
208             InitializeTabsConsole();\r
209 \r
210             if (instance.MediaManager.SoundSystemAvailable)\r
211             {\r
212                 mediaConsole = new MediaConsole(instance);\r
213                 tbtnMedia.Visible = true;\r
214             }\r
215         }\r
216 \r
217         private void netcom_ClientLoginStatus(object sender, ClientLoginEventArgs e)\r
218         {\r
219             if (e.Status != LoginStatus.Success) return;\r
220 \r
221             tbtnGroups.Enabled = tbnObjects.Enabled = tbtnWorld.Enabled = tbnTools.Enabled = tmnuImport.Enabled =\r
222                 tbtnFriends.Enabled = tbtnInventory.Enabled = tbtnSearch.Enabled = tbtnMap.Enabled = true;\r
223 \r
224             statusTimer.Start();\r
225             RefreshWindowTitle();\r
226         }\r
227 \r
228         private void netcom_ClientLoggedOut(object sender, EventArgs e)\r
229         {\r
230             tbtnGroups.Enabled = tbnObjects.Enabled = tbtnWorld.Enabled = tbnTools.Enabled = tmnuImport.Enabled =\r
231                 tbtnFriends.Enabled = tbtnInventory.Enabled = tbtnSearch.Enabled = tbtnMap.Enabled = false;\r
232 \r
233             statusTimer.Stop();\r
234 \r
235             RefreshStatusBar();\r
236             RefreshWindowTitle();\r
237         }\r
238 \r
239         private void netcom_ClientDisconnected(object sender, ClientDisconnectEventArgs e)\r
240         {\r
241             if (e.Type == NetworkManager.DisconnectType.ClientInitiated) return;\r
242             netcom_ClientLoggedOut(sender, EventArgs.Empty);\r
243         }\r
244 \r
245         private void frmMain_FormClosing(object sender, FormClosingEventArgs e)\r
246         {\r
247             if (mediaConsole != null)\r
248             {\r
249                 if (tabsConsole.TabExists("media"))\r
250                 {\r
251                     tabsConsole.Tabs["media"].AllowClose = true;\r
252                     tabsConsole.Tabs["media"].Close();\r
253                 }\r
254                 else\r
255                 {\r
256                     mediaConsole.Dispose();\r
257                 }\r
258                 mediaConsole = null;\r
259             }\r
260 \r
261             if (netcom.IsLoggedIn)\r
262             {\r
263                 Thread saveInvToDisk = new Thread(new ThreadStart(\r
264                     delegate()\r
265                     {\r
266                         client.Inventory.Store.SaveToDisk(instance.InventoryCacheFileName);\r
267                     }));\r
268                 saveInvToDisk.Name = "Save inventory to disk";\r
269                 saveInvToDisk.Start();\r
270 \r
271                 netcom.Logout();\r
272             }\r
273         }\r
274         #endregion\r
275 \r
276         # region Update status\r
277 \r
278         private void Parcels_OnParcelProperties(Simulator simulator, Parcel parcel, ParcelResult result, int selectedPrims,\r
279     int sequenceID, bool snapSelection)\r
280         {\r
281             if (result != ParcelResult.Single) return;\r
282             if (InvokeRequired)\r
283             {\r
284                 BeginInvoke(new MethodInvoker(delegate()\r
285                 {\r
286                     Parcels_OnParcelProperties(simulator, parcel, result, selectedPrims, sequenceID, snapSelection);\r
287                 }\r
288                 ));\r
289                 return;\r
290             }\r
291 \r
292             tlblParcel.Text = parcel.Name;\r
293             tlblParcel.ToolTipText = parcel.Desc;\r
294 \r
295             if ((parcel.Flags & ParcelFlags.AllowFly) != ParcelFlags.AllowFly)\r
296                 icoNoFly.Visible = true;\r
297             else\r
298                 icoNoFly.Visible = false;\r
299 \r
300             if ((parcel.Flags & ParcelFlags.CreateObjects) != ParcelFlags.CreateObjects)\r
301                 icoNoBuild.Visible = true;\r
302             else\r
303                 icoNoBuild.Visible = false;\r
304 \r
305             if ((parcel.Flags & ParcelFlags.AllowOtherScripts) != ParcelFlags.AllowOtherScripts)\r
306                 icoNoScript.Visible = true;\r
307             else\r
308                 icoNoScript.Visible = false;\r
309 \r
310             if ((parcel.Flags & ParcelFlags.RestrictPushObject) == ParcelFlags.RestrictPushObject)\r
311                 icoNoPush.Visible = true;\r
312             else\r
313                 icoNoPush.Visible = false;\r
314 \r
315             if ((parcel.Flags & ParcelFlags.AllowDamage) == ParcelFlags.AllowDamage)\r
316                 icoHealth.Visible = true;\r
317             else\r
318                 icoHealth.Visible = false;\r
319 \r
320             if ((parcel.Flags & ParcelFlags.AllowVoiceChat) != ParcelFlags.AllowVoiceChat)\r
321                 icoNoVoice.Visible = true;\r
322             else\r
323                 icoNoVoice.Visible = false;\r
324         }\r
325 \r
326         private void RefreshStatusBar()\r
327         {\r
328             if (netcom.IsLoggedIn)\r
329             {\r
330                 tlblLoginName.Text = netcom.LoginOptions.FullName;\r
331                 tlblMoneyBalance.Text = client.Self.Balance.ToString();\r
332                 icoHealth.Text = client.Self.Health.ToString() + "%";\r
333 \r
334                 tlblRegionInfo.Text =\r
335                     client.Network.CurrentSim.Name +\r
336                     " (" + Math.Floor(client.Self.SimPosition.X).ToString() + ", " +\r
337                     Math.Floor(client.Self.SimPosition.Y).ToString() + ", " +\r
338                     Math.Floor(client.Self.SimPosition.Z).ToString() + ")";\r
339             }\r
340             else\r
341             {\r
342                 tlblLoginName.Text = "Offline";\r
343                 tlblMoneyBalance.Text = "0";\r
344                 icoHealth.Text = "0%";\r
345                 tlblRegionInfo.Text = "No Region";\r
346                 tlblParcel.Text = "No Parcel";\r
347 \r
348                 icoHealth.Visible = false;\r
349                 icoNoBuild.Visible = false;\r
350                 icoNoFly.Visible = false;\r
351                 icoNoPush.Visible = false;\r
352                 icoNoScript.Visible = false;\r
353                 icoNoVoice.Visible = false;\r
354             }\r
355         }\r
356 \r
357         private void RefreshWindowTitle()\r
358         {\r
359             StringBuilder sb = new StringBuilder();\r
360             sb.Append("Radegast - ");\r
361 \r
362             if (netcom.IsLoggedIn)\r
363             {\r
364                 sb.Append("[" + netcom.LoginOptions.FullName + "]");\r
365 \r
366                 if (instance.State.IsAway)\r
367                 {\r
368                     sb.Append(" - Away");\r
369                     if (instance.State.IsBusy) sb.Append(", Busy");\r
370                 }\r
371                 else if (instance.State.IsBusy)\r
372                 {\r
373                     sb.Append(" - Busy");\r
374                 }\r
375 \r
376                 if (instance.State.IsFollowing)\r
377                 {\r
378                     sb.Append(" - Following ");\r
379                     sb.Append(instance.State.FollowName);\r
380                 }\r
381             }\r
382             else\r
383             {\r
384                 sb.Append("Logged Out");\r
385             }\r
386 \r
387             this.Text = sb.ToString();\r
388             sb = null;\r
389         }\r
390 \r
391         private void InitializeStatusTimer()\r
392         {\r
393             statusTimer = new System.Timers.Timer(250);\r
394             statusTimer.SynchronizingObject = this;\r
395             statusTimer.Elapsed += new ElapsedEventHandler(statusTimer_Elapsed);\r
396         }\r
397 \r
398         private void statusTimer_Elapsed(object sender, ElapsedEventArgs e)\r
399         {\r
400             RefreshWindowTitle();\r
401             RefreshStatusBar();\r
402         }\r
403         #endregion\r
404 \r
405         #region Initialization, configuration, and key shortcuts\r
406         private void InitializeTabsConsole()\r
407         {\r
408             tabsConsole = new TabsConsole(instance);\r
409             tabsConsole.Dock = DockStyle.Fill;\r
410             toolStripContainer1.ContentPanel.Controls.Add(tabsConsole);\r
411         }\r
412 \r
413         private void frmMain_KeyDown(object sender, KeyEventArgs e)\r
414         {\r
415             if (e.Control && e.Alt && e.KeyCode == Keys.D)\r
416             {\r
417                 e.Handled = e.SuppressKeyPress = true;\r
418             }\r
419 \r
420             if (e.Control && e.KeyCode == Keys.O && client.Network.Connected)\r
421             {\r
422                 e.Handled = e.SuppressKeyPress = true;\r
423             }\r
424 \r
425             if (e.Control && e.KeyCode == Keys.G)\r
426             {\r
427                 e.Handled = e.SuppressKeyPress = true;\r
428             }\r
429 \r
430             if (e.Control && e.KeyCode == Keys.M && Clipboard.ContainsText() && client.Network.Connected)\r
431             {\r
432                 e.Handled = e.SuppressKeyPress = true;\r
433             }\r
434 \r
435             if (e.Control && e.KeyCode == Keys.Right)\r
436             {\r
437                 e.Handled = e.SuppressKeyPress = true;\r
438             }\r
439 \r
440             if (e.Control && e.KeyCode == Keys.Left)\r
441             {\r
442                 e.Handled = e.SuppressKeyPress = true;\r
443             }\r
444         }\r
445 \r
446 \r
447         private void frmMain_KeyUp(object sender, KeyEventArgs e)\r
448         {\r
449             // ctrl-o, open objects finder\r
450             if (e.Control && e.KeyCode == Keys.O && client.Network.Connected)\r
451             {\r
452                 tbnObjects_Click(this, EventArgs.Empty);\r
453                 e.Handled = e.SuppressKeyPress = true;\r
454             }\r
455 \r
456             // ctrl-g, goto slurl\r
457             if (e.Control && e.KeyCode == Keys.G && Clipboard.ContainsText() && client.Network.Connected)\r
458             {\r
459                 if (!ProcessLink(Clipboard.GetText(), true))\r
460                     MapToCurrentLocation();\r
461                 e.Handled = e.SuppressKeyPress = true;\r
462             }\r
463 \r
464             // ctrl-m, open map\r
465             if (e.Control && e.KeyCode == Keys.M && Clipboard.ContainsText() && client.Network.Connected)\r
466             {\r
467                 MapToCurrentLocation();\r
468                 e.Handled = e.SuppressKeyPress = true;\r
469             }\r
470 \r
471             // ctrl-right_arrow, select next tab\r
472             if (e.Control && e.KeyCode == Keys.Right)\r
473             {\r
474                 TabConsole.SelectNextTab();\r
475                 e.Handled = e.SuppressKeyPress = true;\r
476             }\r
477 \r
478             // ctrl-right_arrow, select previous tab\r
479             if (e.Control && e.KeyCode == Keys.Left)\r
480             {\r
481                 TabConsole.SelectPreviousTab();\r
482                 e.Handled = e.SuppressKeyPress = true;\r
483             }\r
484         }\r
485 \r
486 \r
487         private void frmMain_Load(object sender, EventArgs e)\r
488         {\r
489             tabsConsole.SelectTab("login");\r
490             ResourceManager rm = Properties.Resources.ResourceManager;\r
491             ResourceSet set = rm.GetResourceSet(System.Globalization.CultureInfo.CurrentCulture, true, true);\r
492             System.Collections.IDictionaryEnumerator de = set.GetEnumerator();\r
493             while (de.MoveNext() == true)\r
494             {\r
495                 if (de.Entry.Value is Image)\r
496                 {\r
497                     Bitmap bitMap = de.Entry.Value as Bitmap;\r
498                     ResourceImages.Images.Add(bitMap);\r
499                     ImageNames.Add(de.Entry.Key.ToString());\r
500                 }\r
501             }\r
502             StartUpdateCheck(false);\r
503         }\r
504         #endregion\r
505 \r
506         #region Public methods\r
507 \r
508         private Dictionary<UUID, frmProfile> shownProfiles = new Dictionary<UUID, frmProfile>();\r
509         \r
510         public void ShowAgentProfile(string name, UUID agentID)\r
511         {\r
512             lock (shownProfiles)\r
513             {\r
514                 frmProfile profile = null;\r
515                 if (shownProfiles.TryGetValue(agentID, out profile))\r
516                 {\r
517                     profile.WindowState = FormWindowState.Normal;\r
518                     profile.Focus();\r
519                 }\r
520                 else\r
521                 {\r
522                     profile = new frmProfile(instance, name, agentID);\r
523                     \r
524                     profile.Disposed += (object sender, EventArgs e) =>\r
525                         {\r
526                             lock (shownProfiles)\r
527                             {\r
528                                 frmProfile agentProfile = (frmProfile)sender;\r
529                                 if (shownProfiles.ContainsKey(agentProfile.AgentID))\r
530                                     shownProfiles.Remove(agentProfile.AgentID);\r
531                             }\r
532                         };\r
533 \r
534                     profile.Show();\r
535                     profile.Focus();\r
536                     shownProfiles.Add(agentID, profile);\r
537                 }\r
538             }\r
539         }\r
540 \r
541         private Dictionary<UUID, frmGroupInfo> shownGroupProfiles = new Dictionary<UUID, frmGroupInfo>();\r
542 \r
543         public void ShowGroupProfile(OpenMetaverse.Group group)\r
544         {\r
545             lock (shownGroupProfiles)\r
546             {\r
547                 frmGroupInfo profile = null;\r
548                 if (shownGroupProfiles.TryGetValue(group.ID, out profile))\r
549                 {\r
550                     profile.WindowState = FormWindowState.Normal;\r
551                     profile.Focus();\r
552                 }\r
553                 else\r
554                 {\r
555                     profile = new frmGroupInfo(instance, group);\r
556                     \r
557                     profile.Disposed += (object sender, EventArgs e) =>\r
558                         {\r
559                             lock (shownGroupProfiles)\r
560                             {\r
561                                 frmGroupInfo groupProfile = (frmGroupInfo)sender;\r
562                                 if (shownGroupProfiles.ContainsKey(groupProfile.Group.ID))\r
563                                     shownGroupProfiles.Remove(groupProfile.Group.ID);\r
564                             }\r
565                         };\r
566 \r
567                     profile.Show();\r
568                     profile.Focus();\r
569                     shownGroupProfiles.Add(group.ID, profile);\r
570                 }\r
571             }\r
572         }\r
573 \r
574         public void ProcessLink(string link)\r
575         {\r
576             ProcessLink(link, false);\r
577         }\r
578 \r
579         public bool ProcessLink(string link, bool onlyMap)\r
580         {\r
581             if (!link.Contains("://"))\r
582             {\r
583                 link = "http://" + link;\r
584             }\r
585 \r
586             Regex r = new Regex(@"^(http://slurl.com/secondlife/|secondlife://)([^/]+)/(\d+)/(\d+)(/(\d+))?");\r
587             Match m = r.Match(link);\r
588 \r
589             if (m.Success)\r
590             {\r
591                 string region = HttpUtility.UrlDecode(m.Groups[2].Value);\r
592                 int x = int.Parse(m.Groups[3].Value);\r
593                 int y = int.Parse(m.Groups[4].Value);\r
594                 int z = 0;\r
595 \r
596                 if (m.Groups.Count > 5 && m.Groups[6].Value != String.Empty)\r
597                 {\r
598                     z = int.Parse(m.Groups[6].Value);\r
599                 }\r
600 \r
601                 MapTab.Select();\r
602                 WorldMap.DisplayLocation(region, x, y, z);\r
603                 return true;\r
604             }\r
605             else if (!onlyMap)\r
606             {\r
607                 System.Diagnostics.Process.Start(link);\r
608             }\r
609             return false;\r
610         }\r
611         #endregion\r
612 \r
613         #region Notifications\r
614         CircularList<Control> notifications = new CircularList<Control>();\r
615 \r
616         public Color NotificationBackground\r
617         {\r
618             get { return pnlDialog.BackColor; }\r
619         }\r
620 \r
621         void ResizeNotificationByControl(Control active)\r
622         {\r
623             int Width = active.Size.Width + 6;\r
624             int Height = notifications.Count > 1 ? active.Size.Height + 3 + btnDialogNextControl.Size.Height : active.Size.Height + 3;\r
625             pnlDialog.Size = new Size(Width, Height);\r
626             pnlDialog.Top = 0;\r
627             pnlDialog.Left = pnlDialog.Parent.ClientSize.Width - Width;\r
628 \r
629             btnDialogNextControl.Top = btnDialogNextControl.Parent.ClientSize.Height - btnDialogNextControl.Size.Height;\r
630             btnDialogNextControl.Left = btnDialogNextControl.Parent.ClientSize.Width - btnDialogNextControl.Size.Width;\r
631 \r
632             btnDialogNextControl.BringToFront();\r
633         }\r
634 \r
635         public void AddNotification(Control control)\r
636         {\r
637             if (InvokeRequired)\r
638             {\r
639                 BeginInvoke(new MethodInvoker(delegate()\r
640                 {\r
641                     AddNotification(control);\r
642                 }\r
643                 ));\r
644                 return;\r
645             }\r
646 \r
647             FormFlash.StartFlash(this);\r
648             pnlDialog.Visible = true;\r
649             pnlDialog.BringToFront();\r
650 \r
651             foreach (Control existing in notifications)\r
652             {\r
653                 existing.Visible = false;\r
654             }\r
655 \r
656             notifications.Add(control);\r
657             control.Visible = true;\r
658             control.Anchor = AnchorStyles.Top | AnchorStyles.Left;\r
659             control.Top = 3;\r
660             control.Left = 3;\r
661             pnlDialog.Controls.Add(control);\r
662             ResizeNotificationByControl(control);\r
663 \r
664             btnDialogNextControl.Visible = notifications.Count > 1;\r
665         }\r
666 \r
667         public void RemoveNotification(Control control)\r
668         {\r
669             pnlDialog.Controls.Remove(control);\r
670             notifications.Remove(control);\r
671             control.Dispose();\r
672 \r
673             if (notifications.HasNext)\r
674             {\r
675                 pnlDialog.Visible = true;\r
676                 Control active = notifications.Next;\r
677                 active.Visible = true;\r
678                 ResizeNotificationByControl(active);\r
679             }\r
680             else\r
681             {\r
682                 pnlDialog.Visible = false;\r
683             }\r
684 \r
685             btnDialogNextControl.Visible = notifications.Count > 1;\r
686         }\r
687 \r
688         private void btnDialogNextControl_Click(object sender, EventArgs e)\r
689         {\r
690             foreach (Control existing in notifications)\r
691             {\r
692                 existing.Visible = false;\r
693             }\r
694 \r
695             if (notifications.HasNext)\r
696             {\r
697                 pnlDialog.Visible = true;\r
698                 Control active = notifications.Next;\r
699                 active.Visible = true;\r
700                 ResizeNotificationByControl(active);\r
701             }\r
702             else\r
703             {\r
704                 pnlDialog.Visible = false;\r
705             }\r
706 \r
707         }\r
708         #endregion Notifications\r
709 \r
710         #region Menu click handlers\r
711 \r
712         private void tbtnTeleport_Click(object sender, EventArgs e)\r
713         {\r
714             (new frmTeleport(instance)).ShowDialog();\r
715         }\r
716 \r
717         private void tmnuStatusAway_Click(object sender, EventArgs e)\r
718         {\r
719             instance.State.SetAway(tmnuStatusAway.Checked);\r
720         }\r
721 \r
722         private void tmnuHelpReadme_Click(object sender, EventArgs e)\r
723         {\r
724             System.Diagnostics.Process.Start(Application.StartupPath + @"\Readme.txt");\r
725         }\r
726 \r
727         private void tmnuStatusBusy_Click(object sender, EventArgs e)\r
728         {\r
729             instance.State.SetBusy(tmnuStatusBusy.Checked);\r
730         }\r
731 \r
732         private void tmnuControlFly_Click(object sender, EventArgs e)\r
733         {\r
734             instance.State.SetFlying(tmnuControlFly.Checked);\r
735         }\r
736 \r
737         private void tmnuControlAlwaysRun_Click(object sender, EventArgs e)\r
738         {\r
739             instance.State.SetAlwaysRun(tmnuControlAlwaysRun.Checked);\r
740         }\r
741 \r
742         private void tmnuPrefs_Click(object sender, EventArgs e)\r
743         {\r
744             (new frmSettings(instance)).ShowDialog();\r
745         }\r
746 \r
747         private void tbtnAppearance_Click(object sender, EventArgs e)\r
748         {\r
749             client.Appearance.RequestSetAppearance(false);\r
750         }\r
751 \r
752         private void importObjectToolStripMenuItem_Click(object sender, EventArgs e)\r
753         {\r
754             PrimDeserializer.ImportFromFile(client);\r
755         }\r
756 \r
757         private void autopilotToolStripMenuItem_Click(object sender, EventArgs e)\r
758         {\r
759             if (ap == null)\r
760             {\r
761                 ap = new AutoPilot(client);\r
762                 /*\r
763                 ap.InsertWaypoint(new Vector3(66, 163, 21));\r
764                 ap.InsertWaypoint(new Vector3(66, 98, 21));\r
765 \r
766                 ap.InsertWaypoint(new Vector3(101, 98, 21));\r
767                 ap.InsertWaypoint(new Vector3(101, 45, 21));\r
768                 ap.InsertWaypoint(new Vector3(93, 27, 21));\r
769                 ap.InsertWaypoint(new Vector3(106, 12, 21));\r
770                 ap.InsertWaypoint(new Vector3(123, 24, 21));\r
771                 ap.InsertWaypoint(new Vector3(114, 45, 21));\r
772                 ap.InsertWaypoint(new Vector3(114, 98, 21));\r
773 \r
774                 ap.InsertWaypoint(new Vector3(130, 98, 21));\r
775                 ap.InsertWaypoint(new Vector3(130, 163, 21));\r
776                  **/\r
777                 ap.InsertWaypoint(new Vector3(64, 68, 21));\r
778                 ap.InsertWaypoint(new Vector3(65, 20, 21));\r
779                 ap.InsertWaypoint(new Vector3(33, 23, 21));\r
780                 ap.InsertWaypoint(new Vector3(17, 39, 21));\r
781                 ap.InsertWaypoint(new Vector3(17, 62, 21));\r
782 \r
783 \r
784             }\r
785             if (AutoPilotActive)\r
786             {\r
787                 AutoPilotActive = false;\r
788                 ap.Stop();\r
789             }\r
790             else\r
791             {\r
792                 AutoPilotActive = true;\r
793                 ap.Start();\r
794             }\r
795 \r
796         }\r
797 \r
798         private void cleanCacheToolStripMenuItem_Click(object sender, EventArgs e)\r
799         {\r
800             client.Assets.Cache.Clear();\r
801             DirectoryInfo di = new DirectoryInfo(instance.AnimCacheDir);\r
802             FileInfo[] files = di.GetFiles();\r
803 \r
804             int num = 0;\r
805             foreach (FileInfo file in files)\r
806             {\r
807                 file.Delete();\r
808                 ++num;\r
809             }\r
810 \r
811             Logger.Log("Wiped out " + num + " files from the anim cache directory.", Helpers.LogLevel.Debug);\r
812 \r
813         }\r
814 \r
815         private void rebakeTexturesToolStripMenuItem_Click(object sender, EventArgs e)\r
816         {\r
817             client.Appearance.RequestSetAppearance(true);\r
818         }\r
819 \r
820         public void MapToCurrentLocation()\r
821         {\r
822             if (MapTab != null && client.Network.Connected)\r
823             {\r
824                 MapTab.Select();\r
825                 WorldMap.DisplayLocation(client.Network.CurrentSim.Name,\r
826                     (int)client.Self.SimPosition.X,\r
827                     (int)client.Self.SimPosition.Y,\r
828                     (int)client.Self.SimPosition.Z);\r
829             }\r
830         }\r
831 \r
832         private void standToolStripMenuItem_Click(object sender, EventArgs e)\r
833         {\r
834             client.Self.Stand();\r
835         }\r
836 \r
837         private void groundSitToolStripMenuItem_Click(object sender, EventArgs e)\r
838         {\r
839             client.Self.SitOnGround();\r
840         }\r
841 \r
842         private void newWindowToolStripMenuItem_Click(object sender, EventArgs e)\r
843         {\r
844             try { System.Diagnostics.Process.Start(Application.ExecutablePath); }\r
845             catch (Exception) { }\r
846         }\r
847 \r
848         private void tmnuExit_Click(object sender, EventArgs e)\r
849         {\r
850             Close();\r
851         }\r
852 \r
853         private void tlblRegionInfo_Click(object sender, EventArgs e)\r
854         {\r
855             if (WorldMap != null && client.Network.Connected)\r
856             {\r
857                 MapTab.Select();\r
858             }\r
859         }\r
860 \r
861         private void scriptEditorToolStripMenuItem_Click(object sender, EventArgs e)\r
862         {\r
863             ScriptEditor se = new ScriptEditor(instance);\r
864             se.Dock = DockStyle.Fill;\r
865             se.ShowDetached();\r
866         }\r
867 \r
868         private void tmnuSetHome_Click(object sender, EventArgs e)\r
869         {\r
870             client.Self.SetHome();\r
871         }\r
872 \r
873         private void tmnuCreateLandmark_Click(object sender, EventArgs e)\r
874         {\r
875             string location = string.Format(", {0} ({1}, {2}, {3})",\r
876                 client.Network.CurrentSim.Name,\r
877                 (int)client.Self.SimPosition.X,\r
878                 (int)client.Self.SimPosition.Y,\r
879                 (int)client.Self.SimPosition.Z\r
880                 );\r
881 \r
882             string name = tlblParcel.Text;\r
883             int maxLen = 63 - location.Length;\r
884 \r
885             if (name.Length > maxLen)\r
886                 name = name.Substring(0, maxLen);\r
887 \r
888             name += location;\r
889 \r
890             client.Inventory.RequestCreateItem(\r
891                 client.Inventory.FindFolderForType(AssetType.Landmark),\r
892                 name,\r
893                 tlblParcel.ToolTipText,\r
894                 AssetType.Landmark,\r
895                 UUID.Random(),\r
896                 InventoryType.Landmark,\r
897                 PermissionMask.All,\r
898                 (bool success, InventoryItem item) =>\r
899                 {\r
900                     if (success)\r
901                     {\r
902                         BeginInvoke(new MethodInvoker(() =>\r
903                             {\r
904                                 Landmark ln = new Landmark(instance, (InventoryLandmark)item);\r
905                                 ln.Dock = DockStyle.Fill;\r
906                                 ln.Detached = true;\r
907                             }));\r
908                     }\r
909                 }\r
910             );\r
911         }\r
912 \r
913         private void tmnuTeleportHome_Click(object sender, EventArgs e)\r
914         {\r
915             if (WorldMap != null)\r
916             {\r
917                 WorldMap.GoHome();\r
918             }\r
919         }\r
920 \r
921         private TimeZoneInfo SLTime;\r
922 \r
923         private void GetSLTimeZone()\r
924         {\r
925             try\r
926             {\r
927                 foreach (TimeZoneInfo tz in TimeZoneInfo.GetSystemTimeZones())\r
928                 {\r
929                     if (tz.Id == "Pacific Standard Time" || tz.Id == "America/Los_Angeles")\r
930                     {\r
931                         SLTime = tz;\r
932                         break;\r
933                     }\r
934                 }\r
935             }\r
936             catch (Exception) { }\r
937         }\r
938 \r
939         private void timerWorldClock_Tick(object sender, EventArgs e)\r
940         {\r
941             DateTime now;\r
942             try\r
943             {\r
944                 if (SLTime != null)\r
945                     now = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, SLTime);\r
946                 else\r
947                     now = DateTime.UtcNow.AddHours(-7);\r
948             }\r
949             catch (Exception)\r
950             {\r
951                 now = DateTime.UtcNow.AddHours(-7);\r
952             }\r
953             lblTime.Text = now.ToString("h:mm tt", System.Globalization.CultureInfo.InvariantCulture);\r
954         }\r
955 \r
956         private void reportBugsToolStripMenuItem_Click(object sender, EventArgs e)\r
957         {\r
958             ProcessLink("http://jira.openmetaverse.org/browse/RAD");\r
959         }\r
960 \r
961         private void aboutRadegastToolStripMenuItem_Click(object sender, EventArgs e)\r
962         {\r
963             (new frmAbout(instance)).ShowDialog();\r
964         }\r
965 \r
966         #region Update Checking\r
967         private UpdateChecker updateChecker = null;\r
968         private bool ManualUpdateCheck = false;\r
969 \r
970         public void StartUpdateCheck(bool userInitiated)\r
971         {\r
972             ManualUpdateCheck = userInitiated;\r
973 \r
974             if (updateChecker != null)\r
975             {\r
976                 if (ManualUpdateCheck)\r
977                     tabsConsole.DisplayNotificationInChat("Update check already in progress.");\r
978                 return;\r
979             }\r
980 \r
981             if (ManualUpdateCheck)\r
982                 tabsConsole.DisplayNotificationInChat("Checking for updates...", ChatBufferTextStyle.StatusBlue);\r
983             updateChecker = new UpdateChecker();\r
984             updateChecker.OnUpdateInfoReceived += new UpdateChecker.UpdateInfoCallback(OnUpdateInfoReceived);\r
985             updateChecker.StartCheck();\r
986         }\r
987 \r
988         private void checkForUpdatesToolStripMenuItem_Click(object sender, EventArgs e)\r
989         {\r
990             tabsConsole.SelectTab("chat");\r
991             StartUpdateCheck(true);\r
992         }\r
993 \r
994         void OnUpdateInfoReceived(object sender, UpdateCheckerArgs e)\r
995         {\r
996             if (InvokeRequired)\r
997             {\r
998                 BeginInvoke(new MethodInvoker(() => OnUpdateInfoReceived(sender, e)));\r
999                 return;\r
1000             }\r
1001 \r
1002             if (!e.Success)\r
1003             {\r
1004                 if (ManualUpdateCheck)\r
1005                     tabsConsole.DisplayNotificationInChat("Error: Failed connecting to the update site.", ChatBufferTextStyle.StatusBlue);\r
1006             }\r
1007             else\r
1008             {\r
1009                 if (!ManualUpdateCheck && e.Info.DisplayMOTD)\r
1010                 {\r
1011                     tabsConsole.DisplayNotificationInChat(e.Info.MOTD, ChatBufferTextStyle.StatusBlue);\r
1012                 }\r
1013 \r
1014                 if (e.Info.UpdateAvailable)\r
1015                 {\r
1016                     tabsConsole.DisplayNotificationInChat("New version available at " + e.Info.DownloadSite, ChatBufferTextStyle.Alert);\r
1017                 }\r
1018                 else\r
1019                 {\r
1020                     if (ManualUpdateCheck)\r
1021                         tabsConsole.DisplayNotificationInChat("Your version is up to date.", ChatBufferTextStyle.StatusBlue);\r
1022                 }\r
1023             }\r
1024 \r
1025             updateChecker.Dispose();\r
1026             updateChecker = null;\r
1027         }\r
1028         #endregion\r
1029 \r
1030         private void ToggleHidden(string tabName)\r
1031         {\r
1032             if (!tabsConsole.TabExists(tabName)) return;\r
1033 \r
1034             RadegastTab tab = tabsConsole.Tabs[tabName];\r
1035 \r
1036             if (tab.Hidden)\r
1037             {\r
1038                 tab.Show();\r
1039             }\r
1040             else\r
1041             {\r
1042                 if (!tab.Selected)\r
1043                 {\r
1044                     tab.Select();\r
1045                 }\r
1046                 else\r
1047                 {\r
1048                     tab.Hide();\r
1049                 }\r
1050             }\r
1051         }\r
1052 \r
1053         private void tbtnFriends_Click(object sender, EventArgs e)\r
1054         {\r
1055             ToggleHidden("friends");\r
1056         }\r
1057 \r
1058         private void tbtnInventory_Click(object sender, EventArgs e)\r
1059         {\r
1060             ToggleHidden("inventory");\r
1061         }\r
1062 \r
1063         private void tbtnSearch_Click(object sender, EventArgs e)\r
1064         {\r
1065             ToggleHidden("search");\r
1066         }\r
1067 \r
1068         private void tbtnGroups_Click(object sender, EventArgs e)\r
1069         {\r
1070             ToggleHidden("groups");\r
1071         }\r
1072 \r
1073         private void tbtnMedia_Click(object sender, EventArgs e)\r
1074         {\r
1075             if (tabsConsole.TabExists("media"))\r
1076             {\r
1077                 ToggleHidden("media");\r
1078             }\r
1079             else\r
1080             {\r
1081                 RadegastTab tab = tabsConsole.AddTab("media", "Media", mediaConsole);\r
1082                 tab.AllowClose = false;\r
1083                 tab.AllowHide = true;\r
1084                 tab.Select();\r
1085             }\r
1086         }\r
1087 \r
1088         private void tbnObjects_Click(object sender, EventArgs e)\r
1089         {\r
1090             if (tabsConsole.TabExists("objects"))\r
1091             {\r
1092                 RadegastTab tab = tabsConsole.Tabs["objects"];\r
1093                 if (!tab.Selected)\r
1094                 {\r
1095                     tab.Select();\r
1096                     ((ObjectsConsole)tab.Control).RefreshObjectList();\r
1097                 }\r
1098                 else\r
1099                 {\r
1100                     tab.Close();\r
1101                 }\r
1102             }\r
1103             else\r
1104             {\r
1105                 RadegastTab tab = tabsConsole.AddTab("objects", "Objects", new ObjectsConsole(instance));\r
1106                 tab.AllowClose = true;\r
1107                 tab.AllowDetach = true;\r
1108                 tab.Visible = true;\r
1109                 tab.AllowHide = false;\r
1110                 tab.Select();\r
1111                 ((ObjectsConsole)tab.Control).RefreshObjectList();\r
1112             }\r
1113         }\r
1114         \r
1115         private void tbtnMap_Click(object sender, EventArgs e)\r
1116         {\r
1117             ToggleHidden("map");\r
1118             if (!MapTab.Hidden)\r
1119                 MapToCurrentLocation();\r
1120         }\r
1121 \r
1122         #endregion\r
1123     }\r
1124 }