/SparkleShare/Mac/SparkleSetup.cs

http://github.com/hbons/SparkleShare · C# · 878 lines · 632 code · 228 blank · 18 comment · 63 complexity · e8caed08f4f348107f7b9cf6f8fd7711 MD5 · raw file

  1. // SparkleShare, a collaboration and sharing tool.
  2. // Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. using System;
  17. using System.Collections.Generic;
  18. using System.Drawing;
  19. using System.IO;
  20. using MonoMac.Foundation;
  21. using MonoMac.AppKit;
  22. using MonoMac.WebKit;
  23. using Mono.Unix;
  24. namespace SparkleShare {
  25. public class SparkleSetup : SparkleSetupWindow {
  26. public SparkleSetupController Controller = new SparkleSetupController ();
  27. private NSButton ContinueButton, AddButton, CopyButton, TryAgainButton, CancelButton,
  28. SkipTutorialButton, FinishButton, ShowFilesButton;
  29. private NSTextField FullNameTextField, FullNameLabel, EmailLabel, EmailTextField,
  30. LinkCodeTextField, AddressTextField, AddressLabel, AddressHelpLabel, PathTextField, PathLabel,
  31. PathHelpLabel, ProgressLabel, PasswordTextField, VisiblePasswordTextField, PasswordLabel, WarningTextField;
  32. private NSButton StartupCheckButton, HistoryCheckButton, ShowPasswordCheckButton;
  33. private NSProgressIndicator ProgressIndicator;
  34. private NSImage WarningImage, SlideImage;
  35. private NSImageView WarningImageView, SlideImageView;
  36. private NSTableColumn IconColumn, DescriptionColumn;
  37. private NSTableView TableView;
  38. private NSScrollView ScrollView;
  39. private SparkleDataSource DataSource;
  40. public SparkleSetup () : base ()
  41. {
  42. Controller.HideWindowEvent += delegate {
  43. Program.Controller.Invoke (() => PerformClose (this));
  44. };
  45. Controller.ShowWindowEvent += delegate {
  46. Program.Controller.Invoke (() => OrderFrontRegardless ());
  47. };
  48. Controller.ChangePageEvent += delegate (PageType type, string [] warnings) {
  49. Program.Controller.Invoke (() => {
  50. Reset ();
  51. ShowPage (type, warnings);
  52. ShowAll ();
  53. });
  54. };
  55. }
  56. public void ShowPage (PageType type, string [] warnings)
  57. {
  58. if (type == PageType.Setup) {
  59. Header = "Welcome to SparkleShare!";
  60. Description = "First off, what’s your name and email?\n(visible only to team members)";
  61. FullNameLabel = new SparkleLabel ("Full Name:", NSTextAlignment.Right);
  62. FullNameLabel.Frame = new RectangleF (165, Frame.Height - 234, 160, 17);
  63. FullNameTextField = new NSTextField () {
  64. Frame = new RectangleF (330, Frame.Height - 238, 196, 22),
  65. StringValue = UnixUserInfo.GetRealUser ().RealName,
  66. Delegate = new SparkleTextFieldDelegate ()
  67. };
  68. EmailLabel = new SparkleLabel ("Email:", NSTextAlignment.Right);
  69. EmailLabel.Frame = new RectangleF (165, Frame.Height - 264, 160, 17);
  70. EmailTextField = new NSTextField () {
  71. Frame = new RectangleF (330, Frame.Height - 268, 196, 22),
  72. Delegate = new SparkleTextFieldDelegate ()
  73. };
  74. CancelButton = new NSButton () { Title = "Cancel" };
  75. ContinueButton = new NSButton () {
  76. Title = "Continue",
  77. Enabled = false
  78. };
  79. (FullNameTextField.Delegate as SparkleTextFieldDelegate).StringValueChanged += delegate {
  80. Controller.CheckSetupPage (FullNameTextField.StringValue, EmailTextField.StringValue);
  81. };
  82. (EmailTextField.Delegate as SparkleTextFieldDelegate).StringValueChanged += delegate {
  83. Controller.CheckSetupPage (FullNameTextField.StringValue, EmailTextField.StringValue);
  84. };
  85. ContinueButton.Activated += delegate {
  86. string full_name = FullNameTextField.StringValue.Trim ();
  87. string email = EmailTextField.StringValue.Trim ();
  88. Controller.SetupPageCompleted (full_name, email);
  89. };
  90. CancelButton.Activated += delegate { Controller.SetupPageCancelled (); };
  91. Controller.UpdateSetupContinueButtonEvent += delegate (bool button_enabled) {
  92. Program.Controller.Invoke (() => {
  93. ContinueButton.Enabled = button_enabled;
  94. });
  95. };
  96. ContentView.AddSubview (FullNameLabel);
  97. ContentView.AddSubview (FullNameTextField);
  98. ContentView.AddSubview (EmailLabel);
  99. ContentView.AddSubview (EmailTextField);
  100. Buttons.Add (ContinueButton);
  101. Buttons.Add (CancelButton);
  102. Controller.CheckSetupPage (FullNameTextField.StringValue, EmailTextField.StringValue);
  103. if (FullNameTextField.StringValue.Equals (""))
  104. MakeFirstResponder ((NSResponder) FullNameTextField);
  105. else
  106. MakeFirstResponder ((NSResponder) EmailTextField);
  107. }
  108. if (type == PageType.Invite) {
  109. Header = "You’ve received an invite!";
  110. Description = "Do you want to add this project to SparkleShare?";
  111. AddressLabel = new SparkleLabel ("Address:", NSTextAlignment.Right);
  112. AddressLabel.Frame = new RectangleF (165, Frame.Height - 238, 160, 17);
  113. AddressLabel.Font = NSFont.FromFontName (SparkleUI.FontName + " Bold", NSFont.SystemFontSize);
  114. AddressTextField = new SparkleLabel (Controller.PendingInvite.Address, NSTextAlignment.Left) {
  115. Frame = new RectangleF (330, Frame.Height - 240, 260, 17)
  116. };
  117. PathLabel = new SparkleLabel ("Remote Path:", NSTextAlignment.Right);
  118. PathLabel.Frame = new RectangleF (165, Frame.Height - 262, 160, 17);
  119. PathLabel.Font = NSFont.FromFontName (SparkleUI.FontName + " Bold", NSFont.SystemFontSize);
  120. PathTextField = new SparkleLabel (Controller.PendingInvite.RemotePath, NSTextAlignment.Left) {
  121. Frame = new RectangleF (330, Frame.Height - 264, 260, 17)
  122. };
  123. CancelButton = new NSButton () { Title = "Cancel" };
  124. AddButton = new NSButton () { Title = "Add" };
  125. CancelButton.Activated += delegate { Controller.PageCancelled (); };
  126. AddButton.Activated += delegate { Controller.InvitePageCompleted (); };
  127. ContentView.AddSubview (AddressLabel);
  128. ContentView.AddSubview (PathLabel);
  129. ContentView.AddSubview (AddressTextField);
  130. ContentView.AddSubview (PathTextField);
  131. Buttons.Add (AddButton);
  132. Buttons.Add (CancelButton);
  133. }
  134. if (type == PageType.Add) {
  135. Header = "Where’s your project hosted?";
  136. Description = "";
  137. AddressLabel = new SparkleLabel ("Address:", NSTextAlignment.Left) {
  138. Frame = new RectangleF (190, Frame.Height - 308, 160, 17),
  139. Font = NSFont.FromFontName (SparkleUI.FontName + " Bold", NSFont.SystemFontSize)
  140. };
  141. AddressTextField = new NSTextField () {
  142. Frame = new RectangleF (190, Frame.Height - 336, 196, 22),
  143. Enabled = (Controller.SelectedPlugin.Address == null),
  144. Delegate = new SparkleTextFieldDelegate (),
  145. StringValue = "" + Controller.PreviousAddress
  146. };
  147. AddressTextField.Cell.LineBreakMode = NSLineBreakMode.TruncatingTail;
  148. PathLabel = new SparkleLabel ("Remote Path:", NSTextAlignment.Left) {
  149. Frame = new RectangleF (190 + 196 + 16, Frame.Height - 308, 160, 17),
  150. Font = NSFont.FromFontName (SparkleUI.FontName + " Bold", NSFont.SystemFontSize)
  151. };
  152. PathTextField = new NSTextField () {
  153. Frame = new RectangleF (190 + 196 + 16, Frame.Height - 336, 196, 22),
  154. Enabled = (Controller.SelectedPlugin.Path == null),
  155. Delegate = new SparkleTextFieldDelegate (),
  156. StringValue = "" + Controller.PreviousPath
  157. };
  158. PathTextField.Cell.LineBreakMode = NSLineBreakMode.TruncatingTail;
  159. PathHelpLabel = new SparkleLabel (Controller.SelectedPlugin.PathExample, NSTextAlignment.Left) {
  160. TextColor = NSColor.DisabledControlText,
  161. Frame = new RectangleF (190 + 196 + 16, Frame.Height - 358, 204, 19)
  162. };
  163. AddressHelpLabel = new SparkleLabel (Controller.SelectedPlugin.AddressExample, NSTextAlignment.Left) {
  164. TextColor = NSColor.DisabledControlText,
  165. Frame = new RectangleF (190, Frame.Height - 358, 204, 19)
  166. };
  167. if (TableView == null || TableView.RowCount != Controller.Plugins.Count) {
  168. TableView = new NSTableView () {
  169. Frame = new RectangleF (0, 0, 0, 0),
  170. RowHeight = 38,
  171. IntercellSpacing = new SizeF (8, 12),
  172. HeaderView = null,
  173. Delegate = new SparkleTableViewDelegate ()
  174. };
  175. ScrollView = new NSScrollView () {
  176. Frame = new RectangleF (190, Frame.Height - 280, 408, 185),
  177. DocumentView = TableView,
  178. HasVerticalScroller = true,
  179. BorderType = NSBorderType.BezelBorder
  180. };
  181. IconColumn = new NSTableColumn () {
  182. Width = 36,
  183. HeaderToolTip = "Icon",
  184. DataCell = new NSImageCell () { ImageAlignment = NSImageAlignment.Right }
  185. };
  186. DescriptionColumn = new NSTableColumn () {
  187. Width = 350,
  188. HeaderToolTip = "Description",
  189. Editable = false
  190. };
  191. DescriptionColumn.DataCell.Font = NSFontManager.SharedFontManager.FontWithFamily (
  192. SparkleUI.FontName, NSFontTraitMask.Condensed, 0, 11);
  193. TableView.AddColumn (IconColumn);
  194. TableView.AddColumn (DescriptionColumn);
  195. // Hi-res display support was added after Snow Leopard
  196. if (Environment.OSVersion.Version.Major < 11)
  197. DataSource = new SparkleDataSource (1, Controller.Plugins);
  198. else
  199. DataSource = new SparkleDataSource (BackingScaleFactor, Controller.Plugins);
  200. TableView.DataSource = DataSource;
  201. TableView.ReloadData ();
  202. (TableView.Delegate as SparkleTableViewDelegate).SelectionChanged += delegate {
  203. Controller.SelectedPluginChanged (TableView.SelectedRow);
  204. Controller.CheckAddPage (AddressTextField.StringValue, PathTextField.StringValue, TableView.SelectedRow);
  205. };
  206. }
  207. TableView.SelectRow (Controller.SelectedPluginIndex, false);
  208. TableView.ScrollRowToVisible (Controller.SelectedPluginIndex);
  209. MakeFirstResponder ((NSResponder) TableView);
  210. HistoryCheckButton = new NSButton () {
  211. Frame = new RectangleF (190, Frame.Height - 400, 300, 18),
  212. Title = "Fetch prior revisions"
  213. };
  214. if (Controller.FetchPriorHistory)
  215. HistoryCheckButton.State = NSCellStateValue.On;
  216. HistoryCheckButton.SetButtonType (NSButtonType.Switch);
  217. AddButton = new NSButton () {
  218. Title = "Add",
  219. Enabled = false
  220. };
  221. CancelButton = new NSButton () { Title = "Cancel" };
  222. Controller.ChangeAddressFieldEvent += delegate (string text, string example_text, FieldState state) {
  223. Program.Controller.Invoke (() => {
  224. AddressTextField.StringValue = text;
  225. AddressTextField.Enabled = (state == FieldState.Enabled);
  226. AddressHelpLabel.StringValue = example_text;
  227. });
  228. };
  229. Controller.ChangePathFieldEvent += delegate (string text, string example_text, FieldState state) {
  230. Program.Controller.Invoke (() => {
  231. PathTextField.StringValue = text;
  232. PathTextField.Enabled = (state == FieldState.Enabled);
  233. PathHelpLabel.StringValue = example_text;
  234. });
  235. };
  236. (AddressTextField.Delegate as SparkleTextFieldDelegate).StringValueChanged += delegate {
  237. Controller.CheckAddPage (AddressTextField.StringValue, PathTextField.StringValue, TableView.SelectedRow);
  238. };
  239. (PathTextField.Delegate as SparkleTextFieldDelegate).StringValueChanged += delegate {
  240. Controller.CheckAddPage (AddressTextField.StringValue, PathTextField.StringValue, TableView.SelectedRow);
  241. };
  242. HistoryCheckButton.Activated += delegate {
  243. Controller.HistoryItemChanged (HistoryCheckButton.State == NSCellStateValue.On);
  244. };
  245. AddButton.Activated += delegate {
  246. Controller.AddPageCompleted (AddressTextField.StringValue, PathTextField.StringValue);
  247. };
  248. CancelButton.Activated += delegate { Controller.PageCancelled (); };
  249. Controller.UpdateAddProjectButtonEvent += delegate (bool button_enabled) {
  250. Program.Controller.Invoke (() => {
  251. AddButton.Enabled = button_enabled;
  252. });
  253. };
  254. ContentView.AddSubview (ScrollView);
  255. ContentView.AddSubview (AddressLabel);
  256. ContentView.AddSubview (AddressTextField);
  257. ContentView.AddSubview (AddressHelpLabel);
  258. ContentView.AddSubview (PathLabel);
  259. ContentView.AddSubview (PathTextField);
  260. ContentView.AddSubview (PathHelpLabel);
  261. ContentView.AddSubview (HistoryCheckButton);
  262. Buttons.Add (AddButton);
  263. Buttons.Add (CancelButton);
  264. Controller.CheckAddPage (AddressTextField.StringValue, PathTextField.StringValue, TableView.SelectedRow);
  265. }
  266. if (type == PageType.Syncing) {
  267. Header = "Adding project ‘" + Controller.SyncingFolder + "’…";
  268. Description = "This may take a while for large projects.\nIsn’t it coffee-o’clock?";
  269. ProgressIndicator = new NSProgressIndicator () {
  270. Frame = new RectangleF (190, Frame.Height - 200, 640 - 150 - 80, 20),
  271. Style = NSProgressIndicatorStyle.Bar,
  272. MinValue = 0.0,
  273. MaxValue = 100.0,
  274. Indeterminate = false,
  275. DoubleValue = Controller.ProgressBarPercentage
  276. };
  277. ProgressIndicator.StartAnimation (this);
  278. CancelButton = new NSButton () { Title = "Cancel" };
  279. FinishButton = new NSButton () {
  280. Title = "Finish",
  281. Enabled = false
  282. };
  283. ProgressLabel = new SparkleLabel ("Preparing to fetch files…", NSTextAlignment.Right);
  284. ProgressLabel.Frame = new RectangleF (Frame.Width - 40 - 250, 185, 250, 25);
  285. Controller.UpdateProgressBarEvent += delegate (double percentage, string speed) {
  286. Program.Controller.Invoke (() => {
  287. ProgressIndicator.DoubleValue = percentage;
  288. ProgressLabel.StringValue = speed;
  289. });
  290. };
  291. CancelButton.Activated += delegate { Controller.SyncingCancelled (); };
  292. ContentView.AddSubview (ProgressLabel);
  293. ContentView.AddSubview (ProgressIndicator);
  294. Buttons.Add (FinishButton);
  295. Buttons.Add (CancelButton);
  296. }
  297. if (type == PageType.Error) {
  298. Header = "Oops! Something went wrong…";
  299. Description = "Please check the following:";
  300. // Displaying marked up text with Cocoa is
  301. // a pain, so we just use a webview instead
  302. WebView web_view = new WebView ();
  303. web_view.Frame = new RectangleF (190, Frame.Height - 525, 375, 400);
  304. string html = "<style>" +
  305. "* {" +
  306. " font-family: '" + SparkleUI.FontName + "';" +
  307. " font-size: 12px; cursor: default;" +
  308. "}" +
  309. "body {" +
  310. " -webkit-user-select: none;" +
  311. " margin: 0;" +
  312. " padding: 3px;" +
  313. "}" +
  314. "li {" +
  315. " margin-bottom: 16px;" +
  316. " margin-left: 0;" +
  317. " padding-left: 0;" +
  318. " line-height: 20px;" +
  319. " word-wrap: break-word;" +
  320. "}" +
  321. "ul {" +
  322. " padding-left: 24px;" +
  323. "}" +
  324. "</style>" +
  325. "<ul>" +
  326. " <li><b>" + Controller.PreviousUrl + "</b> is the address we’ve compiled. Does this look alright?</li>" +
  327. " <li>Is this computer’s Client ID known by the host?</li>" +
  328. "</ul>";
  329. if (warnings.Length > 0) {
  330. string warnings_markup = "";
  331. foreach (string warning in warnings)
  332. warnings_markup += "<br><b>" + warning + "</b>";
  333. html = html.Replace ("</ul>", "<li>Here’s the raw error message: " + warnings_markup + "</li></ul>");
  334. }
  335. web_view.MainFrame.LoadHtmlString (html, new NSUrl (""));
  336. web_view.DrawsBackground = false;
  337. CancelButton = new NSButton () { Title = "Cancel" };
  338. TryAgainButton = new NSButton () { Title = "Try Again…" };
  339. CancelButton.Activated += delegate { Controller.PageCancelled (); };
  340. TryAgainButton.Activated += delegate { Controller.ErrorPageCompleted (); };
  341. ContentView.AddSubview (web_view);
  342. Buttons.Add (TryAgainButton);
  343. Buttons.Add (CancelButton);
  344. }
  345. if (type == PageType.CryptoSetup || type == PageType.CryptoPassword) {
  346. if (type == PageType.CryptoSetup) {
  347. Header = "Set up file encryption";
  348. Description = "Please a provide a strong password that you don’t use elsewhere.";
  349. } else {
  350. Header = "This project contains encrypted files";
  351. Description = "Please enter the password to see their contents.";
  352. }
  353. int extra_pos_y = 0;
  354. if (type == PageType.CryptoPassword)
  355. extra_pos_y = 20;
  356. PasswordLabel = new SparkleLabel ("Password:", NSTextAlignment.Right) {
  357. Frame = new RectangleF (155, Frame.Height - 202 - extra_pos_y, 160, 17),
  358. Font = NSFont.FromFontName (SparkleUI.FontName + " Bold", NSFont.SystemFontSize)
  359. };
  360. PasswordTextField = new NSSecureTextField () {
  361. Frame = new RectangleF (320, Frame.Height - 208 - extra_pos_y, 196, 22),
  362. Delegate = new SparkleTextFieldDelegate ()
  363. };
  364. VisiblePasswordTextField = new NSTextField () {
  365. Frame = new RectangleF (320, Frame.Height - 208 - extra_pos_y, 196, 22),
  366. Delegate = new SparkleTextFieldDelegate ()
  367. };
  368. ShowPasswordCheckButton = new NSButton () {
  369. Frame = new RectangleF (318, Frame.Height - 235 - extra_pos_y, 300, 18),
  370. Title = "Show password",
  371. State = NSCellStateValue.Off
  372. };
  373. ShowPasswordCheckButton.SetButtonType (NSButtonType.Switch);
  374. WarningImage = NSImage.ImageNamed ("NSInfo");
  375. WarningImage.Size = new SizeF (24, 24);
  376. WarningImageView = new NSImageView () {
  377. Image = WarningImage,
  378. Frame = new RectangleF (200, Frame.Height - 320, 24, 24)
  379. };
  380. WarningTextField = new SparkleLabel ("This password can’t be changed later, and your files can’t be recovered if it’s forgotten.", NSTextAlignment.Left) {
  381. Frame = new RectangleF (235, Frame.Height - 390, 325, 100),
  382. };
  383. CancelButton = new NSButton () { Title = "Cancel" };
  384. ContinueButton = new NSButton () {
  385. Title = "Continue",
  386. Enabled = false
  387. };
  388. Controller.UpdateCryptoPasswordContinueButtonEvent += delegate (bool button_enabled) {
  389. Program.Controller.Invoke (() => { ContinueButton.Enabled = button_enabled; });
  390. };
  391. Controller.UpdateCryptoSetupContinueButtonEvent += delegate (bool button_enabled) {
  392. Program.Controller.Invoke (() => { ContinueButton.Enabled = button_enabled; });
  393. };
  394. ShowPasswordCheckButton.Activated += delegate {
  395. if (PasswordTextField.Superview == ContentView) {
  396. PasswordTextField.RemoveFromSuperview ();
  397. ContentView.AddSubview (VisiblePasswordTextField);
  398. } else {
  399. VisiblePasswordTextField.RemoveFromSuperview ();
  400. ContentView.AddSubview (PasswordTextField);
  401. }
  402. };
  403. (PasswordTextField.Delegate as SparkleTextFieldDelegate).StringValueChanged += delegate {
  404. VisiblePasswordTextField.StringValue = PasswordTextField.StringValue;
  405. if (type == PageType.CryptoSetup)
  406. Controller.CheckCryptoSetupPage (PasswordTextField.StringValue);
  407. else
  408. Controller.CheckCryptoPasswordPage (PasswordTextField.StringValue);
  409. };
  410. (VisiblePasswordTextField.Delegate as SparkleTextFieldDelegate).StringValueChanged += delegate {
  411. PasswordTextField.StringValue = VisiblePasswordTextField.StringValue;
  412. if (type == PageType.CryptoSetup)
  413. Controller.CheckCryptoSetupPage (PasswordTextField.StringValue);
  414. else
  415. Controller.CheckCryptoPasswordPage (PasswordTextField.StringValue);
  416. };
  417. ContinueButton.Activated += delegate {
  418. if (type == PageType.CryptoSetup)
  419. Controller.CryptoSetupPageCompleted (PasswordTextField.StringValue);
  420. else
  421. Controller.CryptoPasswordPageCompleted (PasswordTextField.StringValue);
  422. };
  423. CancelButton.Activated += delegate { Controller.CryptoPageCancelled (); };
  424. ContentView.AddSubview (PasswordLabel);
  425. ContentView.AddSubview (PasswordTextField);
  426. ContentView.AddSubview (ShowPasswordCheckButton);
  427. if (type == PageType.CryptoSetup) {
  428. ContentView.AddSubview (WarningImageView);
  429. ContentView.AddSubview (WarningTextField);
  430. }
  431. Buttons.Add (ContinueButton);
  432. Buttons.Add (CancelButton);
  433. MakeFirstResponder ((NSResponder) PasswordTextField);
  434. NSApplication.SharedApplication.RequestUserAttention (NSRequestUserAttentionType.CriticalRequest);
  435. }
  436. if (type == PageType.Finished) {
  437. Header = "Your shared project is ready!";
  438. Description = "You can find the files in your SparkleShare folder.";
  439. if (warnings.Length > 0) {
  440. WarningImage = NSImage.ImageNamed ("NSInfo");
  441. WarningImage.Size = new SizeF (24, 24);
  442. WarningImageView = new NSImageView () {
  443. Image = WarningImage,
  444. Frame = new RectangleF (200, Frame.Height - 175, 24, 24)
  445. };
  446. WarningTextField = new SparkleLabel (warnings [0], NSTextAlignment.Left);
  447. WarningTextField.Frame = new RectangleF (235, Frame.Height - 245, 325, 100);
  448. ContentView.AddSubview (WarningImageView);
  449. ContentView.AddSubview (WarningTextField);
  450. }
  451. ShowFilesButton = new NSButton () { Title = "Show Files…" };
  452. FinishButton = new NSButton () { Title = "Finish" };
  453. ShowFilesButton.Activated += delegate { Controller.ShowFilesClicked (); };
  454. FinishButton.Activated += delegate { Controller.FinishPageCompleted (); };
  455. Buttons.Add (FinishButton);
  456. Buttons.Add (ShowFilesButton);
  457. NSApplication.SharedApplication.RequestUserAttention (NSRequestUserAttentionType.CriticalRequest);
  458. }
  459. if (type == PageType.Tutorial) {
  460. SlideImage = NSImage.ImageNamed ("tutorial-slide-" + Controller.TutorialPageNumber);
  461. if (SlideImage != null) {
  462. SlideImage.Size = new SizeF (324, 200);
  463. SlideImageView = new NSImageView () {
  464. Image = SlideImage,
  465. Frame = new RectangleF (228, Frame.Height - 350, 324, 200)
  466. };
  467. ContentView.AddSubview (SlideImageView);
  468. }
  469. switch (Controller.TutorialPageNumber) {
  470. case 1: {
  471. Header = "What’s happening next?";
  472. Description = "SparkleShare creates a special folder on your computer " +
  473. "that will keep track of your projects.";
  474. SkipTutorialButton = new NSButton () { Title = "Skip Tutorial" };
  475. ContinueButton = new NSButton () { Title = "Continue" };
  476. SkipTutorialButton.Activated += delegate { Controller.TutorialSkipped (); };
  477. ContinueButton.Activated += delegate { Controller.TutorialPageCompleted (); };
  478. ContentView.AddSubview (SlideImageView);
  479. Buttons.Add (ContinueButton);
  480. Buttons.Add (SkipTutorialButton);
  481. break;
  482. }
  483. case 2: {
  484. Header = "Sharing files with others";
  485. Description = "All files added to your project folders are synced automatically with " +
  486. "the host and your team members.";
  487. ContinueButton = new NSButton () { Title = "Continue" };
  488. ContinueButton.Activated += delegate { Controller.TutorialPageCompleted (); };
  489. Buttons.Add (ContinueButton);
  490. break;
  491. }
  492. case 3: {
  493. Header = "The status icon helps you";
  494. Description = "It shows the syncing progress, provides easy access to " +
  495. "your projects, and lets you view recent changes.";
  496. ContinueButton = new NSButton () { Title = "Continue" };
  497. ContinueButton.Activated += delegate { Controller.TutorialPageCompleted (); };
  498. Buttons.Add (ContinueButton);
  499. break;
  500. }
  501. case 4: {
  502. Header = "Here’s your unique Client ID";
  503. Description = "You’ll need it whenever you want to link this computer to a host. " +
  504. "You can also find it in the status icon menu.";
  505. LinkCodeTextField = new NSTextField () {
  506. StringValue = Program.Controller.CurrentUser.PublicKey,
  507. Enabled = false,
  508. Selectable = false,
  509. Frame = new RectangleF (230, Frame.Height - 238, 246, 22)
  510. };
  511. LinkCodeTextField.Cell.UsesSingleLineMode = true;
  512. LinkCodeTextField.Cell.LineBreakMode = NSLineBreakMode.TruncatingTail;
  513. CopyButton = new NSButton () {
  514. Title = "Copy",
  515. BezelStyle = NSBezelStyle.RoundRect,
  516. Frame = new RectangleF (480, Frame.Height - 238, 60, 22)
  517. };
  518. StartupCheckButton = new NSButton () {
  519. Frame = new RectangleF (190, Frame.Height - 400, 300, 18),
  520. Title = "Add SparkleShare to startup items",
  521. State = NSCellStateValue.On
  522. };
  523. StartupCheckButton.SetButtonType (NSButtonType.Switch);
  524. FinishButton = new NSButton () { Title = "Finish" };
  525. StartupCheckButton.Activated += delegate {
  526. Controller.StartupItemChanged (StartupCheckButton.State == NSCellStateValue.On);
  527. };
  528. CopyButton.Activated += delegate { Controller.CopyToClipboardClicked (); };
  529. FinishButton.Activated += delegate { Controller.TutorialPageCompleted (); };
  530. ContentView.AddSubview (LinkCodeTextField);
  531. ContentView.AddSubview (CopyButton);
  532. ContentView.AddSubview (StartupCheckButton);
  533. Buttons.Add (FinishButton);
  534. break;
  535. }
  536. }
  537. }
  538. }
  539. }
  540. [Register("SparkleDataSource")]
  541. public class SparkleDataSource : NSTableViewDataSource {
  542. public List<object> Items;
  543. public NSAttributedString [] Cells, SelectedCells;
  544. int backing_scale_factor;
  545. public SparkleDataSource (float backing_scale_factor, List<SparklePlugin> plugins)
  546. {
  547. Items = new List <object> ();
  548. Cells = new NSAttributedString [plugins.Count];
  549. SelectedCells = new NSAttributedString [plugins.Count];
  550. this.backing_scale_factor = (int) backing_scale_factor;
  551. int i = 0;
  552. foreach (SparklePlugin plugin in plugins) {
  553. Items.Add (plugin);
  554. NSTextFieldCell cell = new NSTextFieldCell ();
  555. NSData name_data = NSData.FromString ("<font face='" + SparkleUI.FontName + "'><b>" + plugin.Name + "</b></font>");
  556. NSDictionary name_dictionary = new NSDictionary();
  557. NSAttributedString name_attributes = new NSAttributedString (
  558. name_data, new NSUrl ("file://"), out name_dictionary);
  559. NSData description_data = NSData.FromString (
  560. "<small><font style='line-height: 150%' color='#aaa' face='" + SparkleUI.FontName + "'>" + plugin.Description + "</font></small>");
  561. NSDictionary description_dictionary = new NSDictionary();
  562. NSAttributedString description_attributes = new NSAttributedString (
  563. description_data, new NSUrl ("file://"), out description_dictionary);
  564. NSMutableAttributedString mutable_attributes = new NSMutableAttributedString (name_attributes);
  565. mutable_attributes.Append (new NSAttributedString ("\n"));
  566. mutable_attributes.Append (description_attributes);
  567. cell.AttributedStringValue = mutable_attributes;
  568. Cells [i] = (NSAttributedString) cell.ObjectValue;
  569. NSTextFieldCell selected_cell = new NSTextFieldCell ();
  570. NSData selected_name_data = NSData.FromString (
  571. "<font color='white' face='" + SparkleUI.FontName +"'><b>" + plugin.Name + "</b></font>");
  572. NSDictionary selected_name_dictionary = new NSDictionary ();
  573. NSAttributedString selected_name_attributes = new NSAttributedString (
  574. selected_name_data, new NSUrl ("file://"), out selected_name_dictionary);
  575. NSData selected_description_data = NSData.FromString (
  576. "<small><font style='line-height: 150%' color='#9bbaeb' face='" + SparkleUI.FontName + "'>" +
  577. plugin.Description + "</font></small>");
  578. NSDictionary selected_description_dictionary = new NSDictionary ();
  579. NSAttributedString selected_description_attributes = new NSAttributedString (
  580. selected_description_data, new NSUrl ("file://"), out selected_description_dictionary);
  581. NSMutableAttributedString selected_mutable_attributes =
  582. new NSMutableAttributedString (selected_name_attributes);
  583. selected_mutable_attributes.Append (new NSAttributedString ("\n"));
  584. selected_mutable_attributes.Append (selected_description_attributes);
  585. selected_cell.AttributedStringValue = selected_mutable_attributes;
  586. SelectedCells [i] = (NSAttributedString) selected_cell.ObjectValue;
  587. i++;
  588. }
  589. }
  590. [Export("numberOfRowsInTableView:")]
  591. public int numberOfRowsInTableView (NSTableView table_view)
  592. {
  593. if (Items == null)
  594. return 0;
  595. else
  596. return Items.Count;
  597. }
  598. [Export("tableView:objectValueForTableColumn:row:")]
  599. public NSObject objectValueForTableColumn (NSTableView table_view,
  600. NSTableColumn table_column, int row_index)
  601. {
  602. if (table_column.HeaderToolTip.Equals ("Description")) {
  603. if (table_view.SelectedRow == row_index &&
  604. Program.UI.Setup.IsKeyWindow &&
  605. Program.UI.Setup.FirstResponder == table_view) {
  606. return SelectedCells [row_index];
  607. } else {
  608. return Cells [row_index];
  609. }
  610. } else {
  611. SparklePlugin plugin = (SparklePlugin) Items [row_index];
  612. string path = plugin.ImagePath;
  613. if (backing_scale_factor >= 2) {
  614. string hi_path = String.Format ("{0}@{1}x{2}",
  615. Path.Combine (Path.GetDirectoryName (path), Path.GetFileNameWithoutExtension (path)),
  616. backing_scale_factor, Path.GetExtension (path)
  617. );
  618. if (File.Exists (hi_path))
  619. path = hi_path;
  620. }
  621. return new NSImage (path) { Size = new SizeF (24, 24) };
  622. }
  623. }
  624. }
  625. public class SparkleTextFieldDelegate : NSTextFieldDelegate {
  626. public event Action StringValueChanged = delegate { };
  627. public override void Changed (NSNotification notification)
  628. {
  629. StringValueChanged ();
  630. }
  631. }
  632. public class SparkleTableViewDelegate : NSTableViewDelegate {
  633. public event Action SelectionChanged = delegate { };
  634. public override void SelectionDidChange (NSNotification notification)
  635. {
  636. SelectionChanged ();
  637. }
  638. }
  639. public class SparkleLabel : NSTextField {
  640. public SparkleLabel (string label, NSTextAlignment alignment)
  641. {
  642. if (!string.IsNullOrEmpty (label))
  643. StringValue = label;
  644. Alignment = alignment;
  645. BackgroundColor = NSColor.WindowBackground;
  646. Bordered = false;
  647. Editable = false;
  648. }
  649. }
  650. }