From e90796cbae242e1c8389e88027be7fc742aa06b7 Mon Sep 17 00:00:00 2001 From: Hylke Bons Date: Fri, 24 Feb 2012 03:43:28 +0100 Subject: [PATCH] setup: '[X] Add SparklShare to startup items' and tutorial phrases tweaks --- SparkleShare/Mac/SparkleController.cs | 28 ++++++++++++- SparkleShare/Mac/SparkleSetup.cs | 43 +++++++++++--------- SparkleShare/SparkleController.cs | 4 +- SparkleShare/SparkleControllerBase.cs | 3 +- SparkleShare/SparkleSetup.cs | 35 ++++++---------- SparkleShare/SparkleSetupController.cs | 14 ++++++- SparkleShare/SparkleStatusIconController.cs | 2 +- data/tutorial-slide-4.png | Bin 6851 -> 4532 bytes 8 files changed, 79 insertions(+), 50 deletions(-) diff --git a/SparkleShare/Mac/SparkleController.cs b/SparkleShare/Mac/SparkleController.cs index 24d9637e..e3be75cf 100755 --- a/SparkleShare/Mac/SparkleController.cs +++ b/SparkleShare/Mac/SparkleController.cs @@ -102,9 +102,33 @@ namespace SparkleShare { } - public override void EnableSystemAutostart () + public override void CreateStartupItem () { - // N/A + // There aren't any bindings in MonoMac to support this yet, so + // we call out to an applescript to do the job + Process process = new Process (); + process.EnableRaisingEvents = true; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.UseShellExecute = false; + process.StartInfo.FileName = "osascript"; + process.StartInfo.CreateNoWindow = true; + + string app_path = Path.GetDirectoryName (NSBundle.MainBundle.ResourcePath); + app_path = Path.GetDirectoryName (app_path); + + process.StartInfo.Arguments = "-e 'tell application \"System Events\" to " + + "make login item at end with properties {path:\"" + app_path + "\", hidden:false}'"; + + process.Exited += delegate { + SparkleHelpers.DebugInfo ("Controller", "Added " + app_path + " to login items"); + }; + + try { + process.Start (); + + } catch (Exception e) { + SparkleHelpers.DebugInfo ("Controller", "Failed adding " + app_path + " to login items: " + e.Message); + } } diff --git a/SparkleShare/Mac/SparkleSetup.cs b/SparkleShare/Mac/SparkleSetup.cs index ca15b5ce..a90856c7 100755 --- a/SparkleShare/Mac/SparkleSetup.cs +++ b/SparkleShare/Mac/SparkleSetup.cs @@ -37,6 +37,7 @@ namespace SparkleShare { private NSButton TryAgainButton; private NSButton CancelButton; private NSButton SkipTutorialButton; + private NSButton StartupCheckButton; private NSButton OpenFolderButton; private NSButton FinishButton; private NSImage SlideImage; @@ -52,7 +53,6 @@ namespace SparkleShare { private NSTextField PathTextField; private NSTextField PathLabel; private NSTextField PathHelpLabel; - private NSTextField AddProjectTextField; private NSTextField WarningTextField; private NSImage WarningImage; private NSImageView WarningImageView; @@ -84,10 +84,9 @@ namespace SparkleShare { switch (type) { case PageType.Setup: { - // TODO: Improve text Header = "Welcome to SparkleShare!"; - Description = "We'll need some info to mark your changes in the event log. " + - "Don't worry, this stays between you and your peers."; + Description = "Before we get started, what's your name and email? " + + "Don't worry, this information is only visible to your team members."; FullNameLabel = new NSTextField () { @@ -618,7 +617,7 @@ namespace SparkleShare { switch (Controller.TutorialPageNumber) { case 1: { Header = "What's happening next?"; - Description = "SparkleShare creates a special folder in your personal folder " + + Description = "SparkleShare creates a special folder on your computer " + "that will keep track of your projects."; SkipTutorialButton = new NSButton () { @@ -658,8 +657,8 @@ namespace SparkleShare { case 2: { Header = "Sharing files with others"; - Description = "All files added to your project folders are synced with the host " + - "automatically, as well as with your collaborators."; + Description = "All files added to your project folders are synced automatically with " + + "the host and your team members."; ContinueButton = new NSButton () { Title = "Continue" @@ -689,8 +688,8 @@ namespace SparkleShare { case 3: { Header = "The status icon is here to help"; - Description = "It shows the syncing process status, " + - "and contains links to your projects and the event log."; + Description = "It shows the syncing progress, provides easy access to " + + "your projects and let's you view recent changes."; ContinueButton = new NSButton () { Title = "Continue" @@ -720,17 +719,20 @@ namespace SparkleShare { case 4: { Header = "Adding projects to SparkleShare"; - Description = "Just click this button when you see it on the web, and " + - "the project will be automatically added:"; + Description = "You can do this through the status icon menu, or by clicking " + + "magic buttons on webpages that look like this:"; - AddProjectTextField = new NSTextField () { - Frame = new RectangleF (190, Frame.Height - 290, 640 - 240, 44), - BackgroundColor = NSColor.WindowBackground, - Bordered = false, - Editable = false, - Font = SparkleUI.Font, - StringValue = "…or select ‘Add Hosted Project…’ from the status icon menu " + - "to add one by hand." + + StartupCheckButton = new NSButton () { + Frame = new RectangleF (190, Frame.Height - 400, 300, 18), + Title = "Add SparkleShare to startup items", + State = NSCellStateValue.On + }; + + StartupCheckButton.SetButtonType (NSButtonType.Switch); + + StartupCheckButton.Activated += delegate { + Controller.StartupItemChanged (StartupCheckButton.State == NSCellStateValue.On); }; FinishButton = new NSButton () { @@ -741,6 +743,7 @@ namespace SparkleShare { Controller.TutorialPageCompleted (); }; + string slide_image_path = Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "tutorial-slide-4.png"); @@ -754,7 +757,7 @@ namespace SparkleShare { }; ContentView.AddSubview (SlideImageView); - ContentView.AddSubview (AddProjectTextField); + ContentView.AddSubview (StartupCheckButton); Buttons.Add (FinishButton); break; diff --git a/SparkleShare/SparkleController.cs b/SparkleShare/SparkleController.cs index 07a17520..db8c93b8 100755 --- a/SparkleShare/SparkleController.cs +++ b/SparkleShare/SparkleController.cs @@ -45,8 +45,10 @@ namespace SparkleShare { // Creates a .desktop entry in autostart folder to // start SparkleShare automatically at login - public override void EnableSystemAutostart () + public override void CreateStartupItem () { + // TODO: check whether this still works + string autostart_path = Path.Combine (Environment.GetFolderPath ( Environment.SpecialFolder.ApplicationData), "autostart"); diff --git a/SparkleShare/SparkleControllerBase.cs b/SparkleShare/SparkleControllerBase.cs index 3e5bfbb4..eccd7034 100755 --- a/SparkleShare/SparkleControllerBase.cs +++ b/SparkleShare/SparkleControllerBase.cs @@ -92,7 +92,7 @@ namespace SparkleShare { public abstract string PluginsPath { get; } // Enables SparkleShare to start automatically at login - public abstract void EnableSystemAutostart (); + public abstract void CreateStartupItem (); // Installs the sparkleshare:// protocol handler public abstract void InstallProtocolHandler (); @@ -132,7 +132,6 @@ namespace SparkleShare { public virtual void Initialize () { - EnableSystemAutostart (); InstallProtocolHandler (); // Create the SparkleShare folder and add it to the bookmarks diff --git a/SparkleShare/SparkleSetup.cs b/SparkleShare/SparkleSetup.cs index 6a42eee9..3af57d68 100755 --- a/SparkleShare/SparkleSetup.cs +++ b/SparkleShare/SparkleSetup.cs @@ -64,8 +64,9 @@ namespace SparkleShare { case PageType.Setup: { Header = _("Welcome to SparkleShare!"); - Description = "We'll need some info to mark your changes in the event log. " + - "Don't worry, this stays between you and your peers."; + Description = "Before we get started, what's your name and email? " + + "Don't worry, this information is only visible to your team members."; + Table table = new Table (2, 3, true) { @@ -496,8 +497,8 @@ namespace SparkleShare { switch (Controller.TutorialPageNumber) { case 1: { Header = _("What's happening next?"); - Description = _("SparkleShare creates a special folder in your personal folder " + - "that will keep track of your projects."); + Description = "SparkleShare creates a special folder on your computer " + + "that will keep track of your projects."; Button skip_tutorial_button = new Button (_("Skip Tutorial")); skip_tutorial_button.Clicked += delegate { @@ -521,8 +522,8 @@ namespace SparkleShare { case 2: { Header = _("Sharing files with others"); - Description = _("All files added to your project folders are synced with the host " + - "automatically, as well as with your collaborators."); + Description = _("All files added to your project folders are synced automatically with " + + "the host and your team members."); Button continue_button = new Button (_("Continue")); continue_button.Clicked += delegate { @@ -539,8 +540,8 @@ namespace SparkleShare { case 3: { Header = _("The status icon is here to help"); - Description = _("It shows the syncing process status, " + - "and contains links to your projects and the event log."); + Description = _("It shows the syncing progress, provides easy access to " + + "your projects and let's you view recent changes."); Button continue_button = new Button (_("Continue")); continue_button.Clicked += delegate { @@ -557,15 +558,8 @@ namespace SparkleShare { case 4: { Header = _("Adding projects to SparkleShare"); - Description = _("Just click this button when you see it on the web, and " + - "the project will be automatically added:"); - - Label label = new Label (_("…or select ‘Add Hosted Project…’ from the status icon menu " + - "to add one by hand.")) { - Wrap = true, - Xalign = 0, - UseMarkup = true - }; + Description = _("You can do this through the status icon menu, or by clicking " + + "magic buttons on webpages that look like this:"); Image slide = SparkleUIHelpers.GetImage ("tutorial-slide-4.png"); @@ -574,12 +568,9 @@ namespace SparkleShare { Controller.FinishPageCompleted (); }; + // TODO: Add startup item checkbox here - VBox box = new VBox (false, 0); - box.Add (slide); - box.Add (label); - - Add (box); + Add (slide); AddButton (finish_button); break; diff --git a/SparkleShare/SparkleSetupController.cs b/SparkleShare/SparkleSetupController.cs index 240efaf3..08bcd946 100755 --- a/SparkleShare/SparkleSetupController.cs +++ b/SparkleShare/SparkleSetupController.cs @@ -103,6 +103,7 @@ namespace SparkleShare { private string saved_address = ""; private string saved_remote_path = ""; + private bool create_startup_item = true; public SparkleSetupController () @@ -209,14 +210,23 @@ namespace SparkleShare { } + public void StartupItemChanged (bool create_startup_item) + { + this.create_startup_item = create_startup_item; + } + + public void TutorialPageCompleted () { TutorialPageNumber++; - if (TutorialPageNumber == 4) { + if (TutorialPageNumber == 5) { if (HideWindowEvent != null) HideWindowEvent (); + if (this.create_startup_item) + Program.Controller.CreateStartupItem (); + } else { if (ChangePageEvent != null) ChangePageEvent (PageType.Tutorial, null); @@ -264,7 +274,7 @@ namespace SparkleShare { remote_path = remote_path.Trim (); if (selected_plugin == 0) - this.saved_address = address; + this.saved_address = address; this.saved_remote_path = remote_path; diff --git a/SparkleShare/SparkleStatusIconController.cs b/SparkleShare/SparkleStatusIconController.cs index 05671aec..c0212c1b 100755 --- a/SparkleShare/SparkleStatusIconController.cs +++ b/SparkleShare/SparkleStatusIconController.cs @@ -145,7 +145,7 @@ namespace SparkleShare { public void AddHostedProjectClicked () { - Program.Controller.ShowSetupWindow (PageType.Add); + Program.Controller.ShowSetupWindow (PageType.Tutorial); } diff --git a/data/tutorial-slide-4.png b/data/tutorial-slide-4.png index ae642773c7086b8b37f1a2fa136551fa42d95d95..315179b60bb0c1fc73277a55cf264a7340cd5764 100755 GIT binary patch literal 4532 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