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