diff --git a/.gitignore b/.gitignore index 11549e10..2b92be95 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ *.exe *.exe.mdb *.userprefs -*.app *.pidb *.gmo *.bak diff --git a/NEWS b/NEWS index 10bb72a0..ab470c1f 100755 --- a/NEWS +++ b/NEWS @@ -1,3 +1,11 @@ +0.8.3 for Linux and Mac (Mon Feb 19 2012): + + Hylke: + - + - + - + + 0.8.2 for Linux and Mac (Sat Feb 11 2012): Hylke: diff --git a/README.md b/README.md index fccd50ef..b84a8424 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ information see the LICENSE file or visit http://www.gnu.org/licenses/gpl-3.0.ht Requirements: - - git >= 1.7.0 + - git >= 1.7.3 - gtk-sharp2 - mono-core >= 2.8 - notify-sharp diff --git a/SparkleLib/Git/SparkleFetcherGit.cs b/SparkleLib/Git/SparkleFetcherGit.cs index f688dcc1..dc8782ef 100755 --- a/SparkleLib/Git/SparkleFetcherGit.cs +++ b/SparkleLib/Git/SparkleFetcherGit.cs @@ -19,6 +19,7 @@ using System; using System.IO; using System.Diagnostics; using System.Text.RegularExpressions; +using System.Threading; namespace SparkleLib { @@ -28,23 +29,27 @@ namespace SparkleLib { private SparkleGit git; - public SparkleFetcherGit (string server, string remote_folder, string target_folder) : - base (server, remote_folder, target_folder) + public SparkleFetcherGit (string server, string remote_path, string target_folder) : + base (server, remote_path, target_folder) { if (server.EndsWith ("/")) server = server.Substring (0, server.Length - 1); - if (!remote_folder.StartsWith ("/")) - remote_folder = "/" + remote_folder; + // FIXME: Adding these lines makes the fetcher fail + // if (remote_path.EndsWith ("/")) + // remote_path = remote_path.Substring (0, remote_path.Length - 1); + + if (!remote_path.StartsWith ("/")) + remote_path = "/" + remote_path; Uri uri; try { - uri = new Uri (server + remote_folder); + uri = new Uri (server + remote_path); } catch (UriFormatException) { - uri = new Uri ("ssh://" + server + remote_folder); + uri = new Uri ("ssh://" + server + remote_path); } @@ -132,6 +137,18 @@ namespace SparkleLib { this.git.WaitForExit (); SparkleHelpers.DebugInfo ("Git", "Exit code " + this.git.ExitCode.ToString ()); + while (percentage < 100) { + percentage += 25; + + if (percentage >= 100) + break; + + base.OnProgressChanged (percentage); + Thread.Sleep (750); + } + + base.OnProgressChanged (100); + Thread.Sleep (1000); if (this.git.ExitCode != 0) { return false; diff --git a/SparkleLib/Git/SparkleRepoGit.cs b/SparkleLib/Git/SparkleRepoGit.cs index 4f7bfadd..471d33b3 100644 --- a/SparkleLib/Git/SparkleRepoGit.cs +++ b/SparkleLib/Git/SparkleRepoGit.cs @@ -626,12 +626,11 @@ namespace SparkleLib { if (match.Success) { SparkleChangeSet change_set = new SparkleChangeSet (); - change_set.Folder = Name; - change_set.Revision = match.Groups [1].Value; - change_set.User.Name = match.Groups [2].Value; - change_set.User.Email = match.Groups [3].Value; - change_set.IsMagical = is_merge_commit; - change_set.Url = Url; + change_set.Folder = Name; + change_set.Revision = match.Groups [1].Value; + change_set.User = new SparkleUser (match.Groups [2].Value, match.Groups [3].Value); + change_set.IsMagical = is_merge_commit; + change_set.Url = Url; change_set.Timestamp = new DateTime (int.Parse (match.Groups [4].Value), int.Parse (match.Groups [5].Value), int.Parse (match.Groups [6].Value), @@ -724,6 +723,9 @@ namespace SparkleLib { } else if (child_path.EndsWith (".notes")) { continue; + + } else if (child_path.EndsWith (".git")) { + continue; } PrepareDirectories (child_path); @@ -780,7 +782,10 @@ namespace SparkleLib { if (file_name.EndsWith (".empty")) file_name = file_name.Substring (0, file_name.Length - 6); - message += "+ ‘" + file_name + "’" + n; + if (file_name.StartsWith (".notes")) + message += "added a note"; + else + message += "+ ‘" + file_name + "’" + n; count++; if (count == max_count) diff --git a/SparkleLib/Makefile.am b/SparkleLib/Makefile.am index 30484fe1..ddd7498c 100755 --- a/SparkleLib/Makefile.am +++ b/SparkleLib/Makefile.am @@ -17,6 +17,7 @@ SOURCES = \ SparkleListenerFactory.cs \ SparkleListenerTcp.cs \ SparkleRepoBase.cs \ + SparkleUser.cs \ SparkleWatcher.cs diff --git a/SparkleLib/SparkleChangeSet.cs b/SparkleLib/SparkleChangeSet.cs index bc173ac3..ef29d56f 100755 --- a/SparkleLib/SparkleChangeSet.cs +++ b/SparkleLib/SparkleChangeSet.cs @@ -84,22 +84,6 @@ namespace SparkleLib { } - public class SparkleUser { - - public string Name; - public string Email; - - public string PublicKey; - - - public SparkleUser (string name, string email) - { - Name = name; - Email = email; - } - } - - public class SparkleFolder { public string Name; diff --git a/SparkleLib/SparkleConfig.cs b/SparkleLib/SparkleConfig.cs index 9cbc5e2c..8e02e978 100755 --- a/SparkleLib/SparkleConfig.cs +++ b/SparkleLib/SparkleConfig.cs @@ -18,8 +18,8 @@ using System; using System.IO; using System.Collections.Generic; -using System.Xml; using System.Security.Principal; +using System.Xml; namespace SparkleLib { @@ -145,7 +145,17 @@ namespace SparkleLib { XmlNode email_node = SelectSingleNode ("/sparkleshare/user/email/text()"); string email = email_node.Value; - return new SparkleUser (name, email); + string pubkey_file_path = Path.Combine ( + Path.GetDirectoryName (FullPath), + "sparkleshare." + email + ".key.pub" + ); + + SparkleUser user = new SparkleUser (name, email); + + if (File.Exists (pubkey_file_path)) + user.PublicKey = File.ReadAllText (pubkey_file_path); + + return user; } set { @@ -157,7 +167,7 @@ namespace SparkleLib { XmlNode email_node = SelectSingleNode ("/sparkleshare/user/email/text()"); email_node.InnerText = user.Email; - this.Save (); + Save (); // ConfigureSSH (); } @@ -248,7 +258,7 @@ namespace SparkleLib { XmlNode node_root = SelectSingleNode ("/sparkleshare"); node_root.AppendChild (node_folder); - this.Save (); + Save (); } @@ -259,32 +269,32 @@ namespace SparkleLib { SelectSingleNode ("/sparkleshare").RemoveChild (node_folder); } - this.Save (); + Save (); } public bool FolderExists (string name) { - XmlNode folder = this.GetFolder (name); + XmlNode folder = GetFolder (name); return (folder != null); } public string GetBackendForFolder (string name) { - return this.GetFolderValue (name, "backend"); + return GetFolderValue (name, "backend"); } public string GetUrlForFolder (string name) { - return this.GetFolderValue (name, "url"); + return GetFolderValue (name, "url"); } public bool SetFolderOptionalAttribute (string folder_name, string key, string value) { - XmlNode folder = this.GetFolder (folder_name); + XmlNode folder = GetFolder (folder_name); if (folder == null) return false; @@ -298,13 +308,14 @@ namespace SparkleLib { folder.AppendChild (new_node); } + Save (); return true; } public string GetFolderOptionalAttribute (string folder_name, string key) { - XmlNode folder = this.GetFolder (folder_name); + XmlNode folder = GetFolder (folder_name); if (folder != null) { if (folder [key] != null) @@ -364,7 +375,7 @@ namespace SparkleLib { private string GetFolderValue (string name, string key) { - XmlNode folder = this.GetFolder(name); + XmlNode folder = GetFolder(name); if ((folder != null) && (folder [key] != null)) { return folder [key].InnerText; @@ -401,7 +412,7 @@ namespace SparkleLib { } SparkleHelpers.DebugInfo ("Config", "Updated " + name + ":" + content); - this.Save (); + Save (); } @@ -410,7 +421,7 @@ namespace SparkleLib { if (!File.Exists (FullPath)) throw new ConfigFileNotFoundException (FullPath + " does not exist"); - this.Save (FullPath); + Save (FullPath); SparkleHelpers.DebugInfo ("Config", "Updated \"" + FullPath + "\""); } diff --git a/SparkleLib/SparkleFetcherBase.cs b/SparkleLib/SparkleFetcherBase.cs index ec01fba5..ce278853 100755 --- a/SparkleLib/SparkleFetcherBase.cs +++ b/SparkleLib/SparkleFetcherBase.cs @@ -42,6 +42,7 @@ namespace SparkleLib { public string RemoteUrl; public string [] ExcludeRules; public string [] Warnings; + public bool IsActive { get; private set; } private Thread thread; @@ -50,6 +51,7 @@ namespace SparkleLib { { TargetFolder = target_folder; RemoteUrl = server + "/" + remote_folder; + IsActive = false; ExcludeRules = new string [] { // gedit and emacs @@ -125,6 +127,7 @@ namespace SparkleLib { // Clones the remote repository public void Start () { + IsActive = true; SparkleHelpers.DebugInfo ("Fetcher", "[" + TargetFolder + "] Fetching folder: " + RemoteUrl); if (Started != null) @@ -149,6 +152,7 @@ namespace SparkleLib { SparkleHelpers.DebugInfo ("Fetcher", "Finished"); EnableHostKeyCheckingForHost (host); + IsActive = false; if (Finished != null) Finished (Warnings); @@ -157,6 +161,7 @@ namespace SparkleLib { SparkleHelpers.DebugInfo ("Fetcher", "Failed"); EnableHostKeyCheckingForHost (host); + IsActive = false; if (Failed != null) Failed (); @@ -178,7 +183,7 @@ namespace SparkleLib { protected void OnProgressChanged (double percentage) { if (ProgressChanged != null) - ProgressChanged (percentage); + ProgressChanged (percentage); } diff --git a/SparkleLib/SparkleListenerTcp.cs b/SparkleLib/SparkleListenerTcp.cs index ff0323eb..1810a065 100755 --- a/SparkleLib/SparkleListenerTcp.cs +++ b/SparkleLib/SparkleListenerTcp.cs @@ -91,7 +91,8 @@ namespace SparkleLib { this.is_connected = false; this.is_connecting = false; - // this.socket.Dispose (); + if (this.socket != null) + this.socket.Close (); OnDisconnected (e.Message); return; @@ -158,7 +159,8 @@ namespace SparkleLib { this.is_connected = false; this.is_connecting = false;; - // this.socket.Dispose (); + if (this.socket != null) + this.socket.Close (); OnDisconnected ("Ping timeout"); return; @@ -244,6 +246,9 @@ namespace SparkleLib { this.thread.Abort (); this.thread.Join (); + if (this.socket != null) + this.socket.Close (); + base.Dispose (); } diff --git a/SparkleLib/SparkleUser.cs b/SparkleLib/SparkleUser.cs new file mode 100644 index 00000000..ef44bc41 --- /dev/null +++ b/SparkleLib/SparkleUser.cs @@ -0,0 +1,36 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +using System; + +namespace SparkleLib { + + public class SparkleUser { + + public readonly string Name; + public readonly string Email; + + public string PublicKey; + + + public SparkleUser (string name, string email) + { + Name = name; + Email = email; + } + } +} diff --git a/SparkleShare/Mac/SparkleAbout.cs b/SparkleShare/Mac/SparkleAbout.cs index 069ba2e2..3f3999fa 100755 --- a/SparkleShare/Mac/SparkleAbout.cs +++ b/SparkleShare/Mac/SparkleAbout.cs @@ -54,18 +54,23 @@ namespace SparkleShare { CreateAbout (); - NSApplication.SharedApplication.ActivateIgnoringOtherApps (true); - MakeKeyAndOrderFront (this); + Controller.HideWindowEvent += delegate { + InvokeOnMainThread (delegate { + PerformClose (this); + }); + }; - OrderFrontRegardless (); - - Program.UI.UpdateDockIconVisibility (); + Controller.ShowWindowEvent += delegate { + InvokeOnMainThread (delegate { + OrderFrontRegardless (); + }); + }; Controller.NewVersionEvent += delegate (string new_version) { InvokeOnMainThread (delegate { UpdatesTextField.StringValue = "A newer version (" + new_version + ") is available!"; UpdatesTextField.TextColor = - NSColor.FromCalibratedRgba (0.96f, 0.47f, 0.0f, 1.0f); // Tango Orange #2 + NSColor.FromCalibratedRgba (0.45f, 0.62f, 0.81f, 1.0f); }); }; @@ -73,7 +78,7 @@ namespace SparkleShare { InvokeOnMainThread (delegate { UpdatesTextField.StringValue = "You are running the latest version."; UpdatesTextField.TextColor = - NSColor.FromCalibratedRgba (0.45f, 0.62f, 0.81f, 1.0f); // Tango Sky Blue #1 + NSColor.FromCalibratedRgba (0.45f, 0.62f, 0.81f, 1.0f); }); }; @@ -157,6 +162,29 @@ namespace SparkleShare { ContentView.AddSubview (UpdatesTextField); ContentView.AddSubview (CreditsTextField); } + + + public override void OrderFrontRegardless () + { + NSApplication.SharedApplication.ActivateIgnoringOtherApps (true); + MakeKeyAndOrderFront (this); + + if (Program.UI != null) + Program.UI.UpdateDockIconVisibility (); + + base.OrderFrontRegardless (); + } + + + public override void PerformClose (NSObject sender) + { + base.OrderOut (this); + + if (Program.UI != null) + Program.UI.UpdateDockIconVisibility (); + + return; + } } @@ -164,9 +192,7 @@ namespace SparkleShare { public override bool WindowShouldClose (NSObject sender) { - (sender as SparkleAbout).OrderOut (this); - Program.UI.UpdateDockIconVisibility (); - + (sender as SparkleAbout).Controller.WindowClosed (); return false; } } diff --git a/SparkleShare/Mac/SparkleBubbles.cs b/SparkleShare/Mac/SparkleBubbles.cs index 8f169c6c..a36443f7 100755 --- a/SparkleShare/Mac/SparkleBubbles.cs +++ b/SparkleShare/Mac/SparkleBubbles.cs @@ -26,12 +26,12 @@ namespace SparkleShare { public class SparkleBubbles : NSObject { - private SparkleBubblesController controller = new SparkleBubblesController (); + public SparkleBubblesController Controller = new SparkleBubblesController (); public SparkleBubbles () { - this.controller.ShowBubbleEvent += delegate (string title, string subtext, string image_path) { + Controller.ShowBubbleEvent += delegate (string title, string subtext, string image_path) { InvokeOnMainThread (delegate { if (!GrowlApplicationBridge.IsGrowlRunning ()) { NSApplication.SharedApplication.RequestUserAttention ( @@ -68,17 +68,7 @@ namespace SparkleShare { [Export("growlNotificationWasClicked")] public override void GrowlNotificationWasClicked (NSObject o) { - InvokeOnMainThread (delegate { - NSApplication.SharedApplication.ActivateIgnoringOtherApps (true); - - if (SparkleUI.EventLog == null) - SparkleUI.EventLog = new SparkleEventLog (); - - SparkleUI.EventLog.Controller.SelectedFolder = null; - - SparkleUI.EventLog.OrderFrontRegardless (); - SparkleUI.EventLog.MakeKeyAndOrderFront (this); - }); + SparkleUI.Bubbles.Controller.BubbleClicked (); } } } diff --git a/SparkleShare/Mac/SparkleController.cs b/SparkleShare/Mac/SparkleController.cs index d0fb3cb2..e3be75cf 100755 --- a/SparkleShare/Mac/SparkleController.cs +++ b/SparkleShare/Mac/SparkleController.cs @@ -102,16 +102,40 @@ 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); + } } - public override void InstallLauncher () - { - // N/A - } + public override void InstallProtocolHandler () + { + // We ship SparkleShareInviteHandler.app in the bundle + } // Adds the SparkleShare folder to the user's diff --git a/SparkleShare/Mac/SparkleEventLog.cs b/SparkleShare/Mac/SparkleEventLog.cs index a12d2c52..e5d1bdb9 100755 --- a/SparkleShare/Mac/SparkleEventLog.cs +++ b/SparkleShare/Mac/SparkleEventLog.cs @@ -54,7 +54,8 @@ namespace SparkleShare { // TODO: Window needs to be made resizable public SparkleEventLog () : base () { - Title = "Recent Events"; + Title = "Recent Changes"; + Delegate = new SparkleEventsDelegate (); SetFrame (new RectangleF (0, 0, 480, 640), true); @@ -77,7 +78,7 @@ namespace SparkleShare { }; this.hidden_close_button.Activated += delegate { - PerformClose (this); + Controller.WindowClosed (); }; ContentView.AddSubview (this.hidden_close_button); @@ -142,13 +143,28 @@ namespace SparkleShare { ContentView.AddSubview (this.progress_indicator); - UpdateContent (null); - UpdateChooser (null); - OrderFrontRegardless (); + (this.web_view.PolicyDelegate as SparkleWebPolicyDelegate) + .LinkClicked += delegate (string href) { + Controller.LinkClicked (href); + }; - Program.UI.UpdateDockIconVisibility (); // Hook up the controller events + Controller.HideWindowEvent += delegate { + InvokeOnMainThread (delegate { + PerformClose (this); + }); + }; + + Controller.ShowWindowEvent += delegate { + InvokeOnMainThread (delegate { + OrderFrontRegardless (); + + UpdateContent (null); + UpdateChooser (null); + }); + }; + Controller.UpdateChooserEvent += delegate (string [] folders) { InvokeOnMainThread (delegate { UpdateChooser (folders); @@ -226,9 +242,9 @@ namespace SparkleShare { html = html.Replace ("", "#f5f5f5"); html = html.Replace ("", "#0085cf"); html = html.Replace ("", "#009ff8"); - html = html.Replace ("", + html = html.Replace ("", "file://" + Path.Combine (NSBundle.MainBundle.ResourcePath, - "Pixmaps","avatar-default.png")); + "Pixmaps")); html = html.Replace ("", "file://" + Path.Combine (NSBundle.MainBundle.ResourcePath, @@ -245,7 +261,8 @@ namespace SparkleShare { html = html.Replace ("", "file://" + Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "document-moved-12.png")); - + + InvokeOnMainThread (delegate { if (this.progress_indicator.Superview == ContentView) this.progress_indicator.RemoveFromSuperview (); @@ -258,6 +275,29 @@ namespace SparkleShare { thread.Start (); } } + + + public override void OrderFrontRegardless () + { + NSApplication.SharedApplication.ActivateIgnoringOtherApps (true); + MakeKeyAndOrderFront (this); + + if (Program.UI != null) + Program.UI.UpdateDockIconVisibility (); + + base.OrderFrontRegardless (); + } + + + public override void PerformClose (NSObject sender) + { + base.OrderOut (this); + + if (Program.UI != null) + Program.UI.UpdateDockIconVisibility (); + + return; + } } @@ -265,20 +305,23 @@ namespace SparkleShare { public override bool WindowShouldClose (NSObject sender) { - (sender as SparkleEventLog).OrderOut (this); - Program.UI.UpdateDockIconVisibility (); - + (sender as SparkleEventLog).Controller.WindowClosed (); return false; } } public class SparkleWebPolicyDelegate : WebPolicyDelegate { - + + public event LinkClickedHandler LinkClicked; + public delegate void LinkClickedHandler (string href); + + public override void DecidePolicyForNavigation (WebView web_view, NSDictionary action_info, NSUrlRequest request, WebFrame frame, NSObject decision_token) { - SparkleEventLogController.LinkClicked (request.Url.ToString ()); + if (LinkClicked != null) + LinkClicked (request.Url.ToString ()); } } } diff --git a/SparkleShare/Mac/SparkleSetup.cs b/SparkleShare/Mac/SparkleSetup.cs index 9d890127..a90856c7 100755 --- a/SparkleShare/Mac/SparkleSetup.cs +++ b/SparkleShare/Mac/SparkleSetup.cs @@ -33,10 +33,11 @@ namespace SparkleShare { public SparkleSetupController Controller = new SparkleSetupController (); private NSButton ContinueButton; - private NSButton SyncButton; + private NSButton AddButton; private NSButton TryAgainButton; private NSButton CancelButton; private NSButton SkipTutorialButton; + private NSButton StartupCheckButton; private NSButton OpenFolderButton; private NSButton FinishButton; private NSImage SlideImage; @@ -48,10 +49,10 @@ namespace SparkleShare { private NSTextField FullNameLabel; private NSTextField AddressTextField; private NSTextField AddressLabel; + private NSTextField AddressHelpLabel; private NSTextField PathTextField; private NSTextField PathLabel; private NSTextField PathHelpLabel; - private NSTextField AddProjectTextField; private NSTextField WarningTextField; private NSImage WarningImage; private NSImageView WarningImageView; @@ -64,6 +65,18 @@ namespace SparkleShare { public SparkleSetup () : base () { + Controller.HideWindowEvent += delegate { + InvokeOnMainThread (delegate { + PerformClose (this); + }); + }; + + Controller.ShowWindowEvent += delegate { + InvokeOnMainThread (delegate { + OrderFrontRegardless (); + }); + }; + Controller.ChangePageEvent += delegate (PageType type, string [] warnings) { InvokeOnMainThread (delegate { Reset (); @@ -72,8 +85,8 @@ 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."; FullNameLabel = new NSTextField () { @@ -158,10 +171,85 @@ namespace SparkleShare { break; } + case PageType.Invite: { + + Header = "You've received an invite!"; + Description = "Do you want to add this project to SparkleShare?"; + + + AddressLabel = new NSTextField () { + Alignment = NSTextAlignment.Right, + BackgroundColor = NSColor.WindowBackground, + Bordered = false, + Editable = false, + Frame = new RectangleF (165, Frame.Height - 240, 160, 17), + StringValue = "Address:", + Font = SparkleUI.Font + }; + + PathLabel = new NSTextField () { + Alignment = NSTextAlignment.Right, + BackgroundColor = NSColor.WindowBackground, + Bordered = false, + Editable = false, + Frame = new RectangleF (165, Frame.Height - 264, 160, 17), + StringValue = "Remote Path:", + Font = SparkleUI.Font + }; + + AddressTextField = new NSTextField () { + Alignment = NSTextAlignment.Left, + BackgroundColor = NSColor.WindowBackground, + Bordered = false, + Editable = false, + Frame = new RectangleF (330, Frame.Height - 240, 260, 17), + StringValue = Controller.PendingInvite.Address, + Font = SparkleUI.BoldFont + }; + + PathTextField = new NSTextField () { + Alignment = NSTextAlignment.Left, + BackgroundColor = NSColor.WindowBackground, + Bordered = false, + Editable = false, + Frame = new RectangleF (330, Frame.Height - 264, 260, 17), + StringValue = Controller.PendingInvite.RemotePath, + Font = SparkleUI.BoldFont + }; + + + ContentView.AddSubview (AddressLabel); + ContentView.AddSubview (PathLabel); + ContentView.AddSubview (AddressTextField); + ContentView.AddSubview (PathTextField); + + + CancelButton = new NSButton () { + Title = "Cancel" + }; + + CancelButton.Activated += delegate { + Controller.PageCancelled (); + }; + + AddButton = new NSButton () { + Title = "Add" + }; + + AddButton.Activated += delegate { + Controller.InvitePageCompleted (); + }; + + Buttons.Add (AddButton); + Buttons.Add (CancelButton); + + break; + } + case PageType.Add: { - Header = "Where's your project hosted?"; - Description = ""; + Header = "Where's your project hosted?"; + Description = ""; AddressLabel = new NSTextField () { Alignment = NSTextAlignment.Left, @@ -170,7 +258,7 @@ namespace SparkleShare { Editable = false, Frame = new RectangleF (190, Frame.Height - 308, 160, 17), StringValue = "Address:", - Font = SparkleUI.Font + Font = SparkleUI.BoldFont }; AddressTextField = new NSTextField () { @@ -189,7 +277,7 @@ namespace SparkleShare { Editable = false, Frame = new RectangleF (190 + 196 + 16, Frame.Height - 308, 160, 17), StringValue = "Remote Path:", - Font = SparkleUI.Font + Font = SparkleUI.BoldFont }; PathTextField = new NSTextField () { @@ -210,7 +298,18 @@ namespace SparkleShare { TextColor = NSColor.DisabledControlText, Editable = false, Frame = new RectangleF (190 + 196 + 16, Frame.Height - 355, 204, 17), - StringValue = "e.g. ‘rupert/website-design’", + StringValue = "", + Font = NSFontManager.SharedFontManager.FontWithFamily + ("Lucida Grande", NSFontTraitMask.Condensed, 0, 11) + }; + + AddressHelpLabel = new NSTextField () { + BackgroundColor = NSColor.WindowBackground, + Bordered = false, + TextColor = NSColor.DisabledControlText, + Editable = false, + Frame = new RectangleF (190, Frame.Height - 355, 204, 17), + StringValue = "", Font = NSFontManager.SharedFontManager.FontWithFamily ("Lucida Grande", NSFontTraitMask.Condensed, 0, 11) }; @@ -265,6 +364,7 @@ namespace SparkleShare { InvokeOnMainThread (delegate { AddressTextField.StringValue = text; AddressTextField.Enabled = (state == FieldState.Enabled); + AddressHelpLabel.StringValue = example_text; }); }; @@ -275,9 +375,7 @@ namespace SparkleShare { InvokeOnMainThread (delegate { PathTextField.StringValue = text; PathTextField.Enabled = (state == FieldState.Enabled); - - if (!string.IsNullOrEmpty (example_text)) - PathHelpLabel.StringValue = "e.g. " + example_text; + PathHelpLabel.StringValue = example_text; }); }; @@ -285,7 +383,7 @@ namespace SparkleShare { TableView.SelectRow (Controller.SelectedPluginIndex, false); - (AddressTextField.Delegate as SparkleTextFieldDelegate).StringValueChanged += delegate { + (AddressTextField.Delegate as SparkleTextFieldDelegate).StringValueChanged += delegate { Controller.CheckAddPage ( AddressTextField.StringValue, PathTextField.StringValue, @@ -314,7 +412,7 @@ namespace SparkleShare { Controller.UpdateAddProjectButtonEvent += delegate (bool button_enabled) { InvokeOnMainThread (delegate { - SyncButton.Enabled = button_enabled; + AddButton.Enabled = button_enabled; }); }; @@ -322,32 +420,31 @@ namespace SparkleShare { ContentView.AddSubview (ScrollView); ContentView.AddSubview (AddressLabel); ContentView.AddSubview (AddressTextField); + ContentView.AddSubview (AddressHelpLabel); ContentView.AddSubview (PathLabel); ContentView.AddSubview (PathTextField); ContentView.AddSubview (PathHelpLabel); - SyncButton = new NSButton () { + AddButton = new NSButton () { Title = "Add", Enabled = false }; - SyncButton.Activated += delegate { + AddButton.Activated += delegate { Controller.AddPageCompleted ( AddressTextField.StringValue, PathTextField.StringValue ); }; - Buttons.Add (SyncButton); + Buttons.Add (AddButton); CancelButton = new NSButton () { Title = "Cancel" }; CancelButton.Activated += delegate { - InvokeOnMainThread (delegate { - PerformClose (this); - }); + Controller.PageCancelled (); }; Buttons.Add (CancelButton); @@ -493,10 +590,7 @@ namespace SparkleShare { }; FinishButton.Activated += delegate { - InvokeOnMainThread (delegate { - Controller.FinishedPageCompleted (); - PerformClose (this); - }); + Controller.FinishPageCompleted (); }; OpenFolderButton = new NSButton () { @@ -504,7 +598,7 @@ namespace SparkleShare { }; OpenFolderButton.Activated += delegate { - Program.Controller.OpenSparkleShareFolder (Path.GetFileName (Controller.PreviousPath)); + Controller.OpenFolderClicked (); }; Buttons.Add (FinishButton); @@ -523,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 () { @@ -563,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" @@ -594,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" @@ -625,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 () { @@ -643,11 +740,10 @@ namespace SparkleShare { }; FinishButton.Activated += delegate { - InvokeOnMainThread (delegate { - PerformClose (this); - }); + Controller.TutorialPageCompleted (); }; + string slide_image_path = Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "tutorial-slide-4.png"); @@ -661,7 +757,7 @@ namespace SparkleShare { }; ContentView.AddSubview (SlideImageView); - ContentView.AddSubview (AddProjectTextField); + ContentView.AddSubview (StartupCheckButton); Buttons.Add (FinishButton); break; diff --git a/SparkleShare/Mac/SparkleSetupWindow.cs b/SparkleShare/Mac/SparkleSetupWindow.cs index 1441071b..dbd194a2 100755 --- a/SparkleShare/Mac/SparkleSetupWindow.cs +++ b/SparkleShare/Mac/SparkleSetupWindow.cs @@ -83,11 +83,6 @@ namespace SparkleShare { Font = SparkleUI.Font }; - NSApplication.SharedApplication.ActivateIgnoringOtherApps (true); - MakeKeyAndOrderFront (this); - - OrderFrontRegardless (); - if (Program.UI != null) Program.UI.UpdateDockIconVisibility (); } @@ -140,6 +135,12 @@ namespace SparkleShare { public override void OrderFrontRegardless () { NSApplication.SharedApplication.AddWindowsItem (this, "SparkleShare Setup", false); + NSApplication.SharedApplication.ActivateIgnoringOtherApps (true); + MakeKeyAndOrderFront (this); + + if (Program.UI != null) + Program.UI.UpdateDockIconVisibility (); + base.OrderFrontRegardless (); } diff --git a/SparkleShare/Mac/SparkleShare.csproj b/SparkleShare/Mac/SparkleShare.csproj index 23783cbb..8cf2ea5d 100755 --- a/SparkleShare/Mac/SparkleShare.csproj +++ b/SparkleShare/Mac/SparkleShare.csproj @@ -11,7 +11,7 @@ SparkleShare SparkleShare v4.0 - 0.8.2 + 0.8.3 true @@ -24,7 +24,7 @@ false - + @@ -59,7 +59,7 @@ False - + False ..\..\bin\SparkleLib.dll @@ -120,9 +120,6 @@ - - Pixmaps\avatar-default.png - @@ -326,6 +323,42 @@ Plugins\own-server.png + + Pixmaps\avatar-default.png + + + Pixmaps\avatar-a.png + + + Pixmaps\avatar-b.png + + + Pixmaps\avatar-c.png + + + Pixmaps\avatar-d.png + + + Pixmaps\avatar-e.png + + + Pixmaps\avatar-f.png + + + Pixmaps\avatar-g.png + + + Pixmaps\avatar-h.png + + + Pixmaps\avatar-i.png + + + Pixmaps\avatar-j.png + + + Pixmaps\avatar-k.png + diff --git a/SparkleShare/Mac/SparkleShare.sln b/SparkleShare/Mac/SparkleShare.sln index 6ad0b1a6..3521ad0b 100644 --- a/SparkleShare/Mac/SparkleShare.sln +++ b/SparkleShare/Mac/SparkleShare.sln @@ -16,6 +16,6 @@ Global EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = SparkleShare.csproj - version = 0.8.2 + version = 0.8.3 EndGlobalSection EndGlobal diff --git a/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Info.plist b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Info.plist new file mode 100644 index 00000000..72862b4c --- /dev/null +++ b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Info.plist @@ -0,0 +1,57 @@ + + + + + CFBundleAllowMixedLocalizations + + CFBundleDevelopmentRegion + English + CFBundleExecutable + applet + CFBundleIconFile + applet + CFBundleIdentifier + org.sparkleshare.SparkleShareInviteOpener + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + SparkleShareInviteOpen + CFBundlePackageType + APPL + CFBundleSignature + aplt + CFBundleURLTypes + + + CFBundleURLName + SparkleShareInviteOpener + CFBundleURLSchemes + + sparkleshare + + + + LSMinimumSystemVersionByArchitecture + + x86_64 + 10.6 + + LSRequiresCarbon + + WindowState + + dividerCollapsed + + eventLogLevel + -1 + name + ScriptWindowState + positionOfDivider + 333 + savedFrame + 263 111 773 597 0 0 1280 778 + selectedTabView + event log + + + diff --git a/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/MacOS/applet b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/MacOS/applet new file mode 100755 index 00000000..0079f4b1 Binary files /dev/null and b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/MacOS/applet differ diff --git a/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/PkgInfo b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/PkgInfo new file mode 100644 index 00000000..3253614c --- /dev/null +++ b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/PkgInfo @@ -0,0 +1 @@ +APPLaplt \ No newline at end of file diff --git a/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/Scripts/main.scpt b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/Scripts/main.scpt new file mode 100644 index 00000000..37bae65b Binary files /dev/null and b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/Scripts/main.scpt differ diff --git a/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/applet.icns b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/applet.icns new file mode 100644 index 00000000..fcc1f092 Binary files /dev/null and b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/applet.icns differ diff --git a/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/applet.rsrc b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/applet.rsrc new file mode 100644 index 00000000..2015dcc1 Binary files /dev/null and b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/applet.rsrc differ diff --git a/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/description.rtfd/TXT.rtf b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/description.rtfd/TXT.rtf new file mode 100644 index 00000000..0d0a60c0 --- /dev/null +++ b/SparkleShare/Mac/SparkleShareInviteOpener.app/Contents/Resources/description.rtfd/TXT.rtf @@ -0,0 +1,4 @@ +{\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf230 +{\fonttbl} +{\colortbl;\red255\green255\blue255;} +} \ No newline at end of file diff --git a/SparkleShare/Mac/SparkleStatusIcon.cs b/SparkleShare/Mac/SparkleStatusIcon.cs index 231fe902..58c4d9cf 100755 --- a/SparkleShare/Mac/SparkleStatusIcon.cs +++ b/SparkleShare/Mac/SparkleStatusIcon.cs @@ -85,7 +85,7 @@ namespace SparkleShare { if (Controller.Folders.Length == 0) StateText = _("Welcome to SparkleShare!"); else - StateText = _("Up to date") + Controller.FolderSize; + StateText = _("Files up to date") + Controller.FolderSize; CreateMenu (); @@ -112,7 +112,7 @@ namespace SparkleShare { if (Controller.Folders.Length == 0) StateText = _("Welcome to SparkleShare!"); else - StateText = _("Up to date") + Controller.FolderSize; + StateText = _("Files up to date") + Controller.FolderSize; StateMenuItem.Title = StateText; CreateMenu (); @@ -180,7 +180,7 @@ namespace SparkleShare { }; FolderMenuItem.Activated += delegate { - Program.Controller.OpenSparkleShareFolder (); + Controller.SparkleShareClicked (); }; FolderMenuItem.Image = SparkleShareImage; @@ -230,48 +230,26 @@ namespace SparkleShare { Menu.AddItem (NSMenuItem.SeparatorItem); SyncMenuItem = new NSMenuItem () { - Title = "Add Hosted Project…", + Title = "Add Hosted Project…", Enabled = true }; - if (!Program.Controller.FirstRun) { - SyncMenuItem.Activated += delegate { - InvokeOnMainThread (delegate { - NSApplication.SharedApplication.ActivateIgnoringOtherApps (true); - - if (SparkleUI.Setup == null) { - SparkleUI.Setup = new SparkleSetup (); - SparkleUI.Setup.Controller.ShowAddPage (); - } - - if (!SparkleUI.Setup.IsVisible) - SparkleUI.Setup.Controller.ShowAddPage (); - - SparkleUI.Setup.OrderFrontRegardless (); - SparkleUI.Setup.MakeKeyAndOrderFront (this); - }); - }; - } + SyncMenuItem.Activated += delegate { + Controller.AddHostedProjectClicked (); + }; + Menu.AddItem (SyncMenuItem); Menu.AddItem (NSMenuItem.SeparatorItem); RecentEventsMenuItem = new NSMenuItem () { - Title = "Open Recent Events", + Title = "View Recent Changes…", Enabled = (Controller.Folders.Length > 0) }; if (Controller.Folders.Length > 0) { RecentEventsMenuItem.Activated += delegate { - InvokeOnMainThread (delegate { - NSApplication.SharedApplication.ActivateIgnoringOtherApps (true); - - if (SparkleUI.EventLog == null) - SparkleUI.EventLog = new SparkleEventLog (); - - SparkleUI.EventLog.OrderFrontRegardless (); - SparkleUI.EventLog.MakeKeyAndOrderFront (this); - }); + Controller.OpenRecentEventsClicked (); }; } @@ -304,17 +282,9 @@ namespace SparkleShare { Title = "About SparkleShare", Enabled = true }; - - AboutMenuItem.Activated += delegate { - InvokeOnMainThread (delegate { - NSApplication.SharedApplication.ActivateIgnoringOtherApps (true); - - if (SparkleUI.About == null) - SparkleUI.About = new SparkleAbout (); - else - SparkleUI.About.OrderFrontRegardless (); - }); + AboutMenuItem.Activated += delegate { + Controller.AboutClicked (); }; Menu.AddItem (AboutMenuItem); @@ -343,7 +313,7 @@ namespace SparkleShare { private EventHandler OpenFolderDelegate (string name) { return delegate { - Program.Controller.OpenSparkleShareFolder (name); + Controller.SubfolderClicked (name); }; } diff --git a/SparkleShare/Mac/SparkleUI.cs b/SparkleShare/Mac/SparkleUI.cs index 43e9f62f..54712290 100755 --- a/SparkleShare/Mac/SparkleUI.cs +++ b/SparkleShare/Mac/SparkleUI.cs @@ -63,15 +63,14 @@ namespace SparkleShare { BoldFont = NSFontManager.SharedFontManager.FontWithFamily ("Lucida Grande", NSFontTraitMask.Bold, 0, 13); + Setup = new SparkleSetup (); + EventLog = new SparkleEventLog (); + About = new SparkleAbout (); + Bubbles = new SparkleBubbles (); StatusIcon = new SparkleStatusIcon (); - Bubbles = new SparkleBubbles (); - if (Program.Controller.FirstRun) { - Setup = new SparkleSetup (); - Setup.Controller.ShowSetupPage (); - - UpdateDockIconVisibility (); - } + if (Program.Controller.FirstRun) + Program.Controller.ShowSetupWindow (PageType.Setup); } } @@ -96,8 +95,8 @@ namespace SparkleShare { public void UpdateDockIconVisibility () { - // if (true) { // TODO: check for open windows - + // TODO: check for open windows + // if (true) { ShowDockIcon (); // } else { @@ -106,13 +105,15 @@ namespace SparkleShare { } - private void HideDockIcon () { + private void HideDockIcon () + { // Currently not supported, here for completeness sake (see Apple's docs) // NSApplication.SharedApplication.ActivationPolicy = NSApplicationActivationPolicy.None; } - private void ShowDockIcon () { + private void ShowDockIcon () + { NSApplication.SharedApplication.ActivationPolicy = NSApplicationActivationPolicy.Regular; } diff --git a/SparkleShare/Makefile.am b/SparkleShare/Makefile.am index ad557503..28cd4390 100755 --- a/SparkleShare/Makefile.am +++ b/SparkleShare/Makefile.am @@ -19,12 +19,11 @@ SOURCES = \ SparkleBubblesController.cs \ SparkleController.cs \ SparkleControllerBase.cs \ - SparkleEntry.cs \ SparkleEventLog.cs \ SparkleEventLogController.cs \ SparkleExtensions.cs \ - SparkleOptions.cs \ SparkleInvite.cs \ + SparkleOptions.cs \ SparklePlugin.cs \ SparkleSetup.cs \ SparkleSetupController.cs \ diff --git a/SparkleShare/SparkleAbout.cs b/SparkleShare/SparkleAbout.cs index 6a35cf78..51a220ca 100755 --- a/SparkleShare/SparkleAbout.cs +++ b/SparkleShare/SparkleAbout.cs @@ -27,7 +27,7 @@ namespace SparkleShare { public class SparkleAbout : Window { - public SparkleAboutController Controller; + public SparkleAboutController Controller = new SparkleAboutController (); private Label updates; @@ -41,10 +41,11 @@ namespace SparkleShare { public SparkleAbout () : base ("") { DeleteEvent += delegate (object o, DeleteEventArgs args) { - HideAll (); + Controller.WindowClosed (); args.RetVal = true; }; + DefaultSize = new Gdk.Size (600, 260); Resizable = false; BorderWidth = 0; @@ -62,11 +63,23 @@ namespace SparkleShare { buf.RenderPixmapAndMask (out map, out map2, 255); GdkWindow.SetBackPixmap (map, false); - Controller = new SparkleAboutController (); + + Controller.HideWindowEvent += delegate { + Application.Invoke (delegate { + HideAll (); + }); + }; + + Controller.ShowWindowEvent += delegate { + Application.Invoke (delegate { + ShowAll (); + Present (); + }); + }; Controller.NewVersionEvent += delegate (string new_version) { Application.Invoke (delegate { - this.updates.Markup = String.Format ("{0}", + this.updates.Markup = String.Format ("{0}", String.Format (_("A newer version ({0}) is available!"), new_version)); this.updates.ShowAll (); diff --git a/SparkleShare/SparkleAboutController.cs b/SparkleShare/SparkleAboutController.cs index 801d84a6..fb9fa5ee 100755 --- a/SparkleShare/SparkleAboutController.cs +++ b/SparkleShare/SparkleAboutController.cs @@ -26,6 +26,12 @@ namespace SparkleShare { public class SparkleAboutController { + public event ShowWindowEventHandler ShowWindowEvent; + public delegate void ShowWindowEventHandler (); + + public event HideWindowEventHandler HideWindowEvent; + public delegate void HideWindowEventHandler (); + public event NewVersionEventHandler NewVersionEvent; public delegate void NewVersionEventHandler (string new_version); @@ -35,32 +41,34 @@ namespace SparkleShare { public event CheckingForNewVersionEventHandler CheckingForNewVersionEvent; public delegate void CheckingForNewVersionEventHandler (); + public string RunningVersion { get { return SparkleBackend.Version; } } - // Check for a new version once a day - private System.Timers.Timer version_checker = new System.Timers.Timer () { - Enabled = true, - Interval = 24 * 60 * 60 * 1000 - }; - public SparkleAboutController () { - CheckForNewVersion (); + Program.Controller.ShowAboutWindowEvent += delegate { + if (ShowWindowEvent != null) + ShowWindowEvent (); - this.version_checker.Elapsed += delegate { CheckForNewVersion (); }; } + public void WindowClosed () + { + if (HideWindowEvent != null) + HideWindowEvent (); + } + + public void CheckForNewVersion () { - this.version_checker.Stop (); if (CheckingForNewVersionEvent != null) CheckingForNewVersionEvent (); @@ -82,7 +90,7 @@ namespace SparkleShare { // Add a little delay, making it seems we're // actually doing hard work - Thread.Sleep (2 * 1000); + Thread.Sleep (1000); if (running_version >= new_version) { if (VersionUpToDateEvent != null) @@ -92,8 +100,6 @@ namespace SparkleShare { if (NewVersionEvent != null) NewVersionEvent (result); } - - this.version_checker.Start (); }; web_client.DownloadStringAsync (uri); diff --git a/SparkleShare/SparkleBubbles.cs b/SparkleShare/SparkleBubbles.cs index 1d08df2a..8fbbab6f 100755 --- a/SparkleShare/SparkleBubbles.cs +++ b/SparkleShare/SparkleBubbles.cs @@ -43,16 +43,9 @@ namespace SparkleShare { else notification.IconName = "folder-sparkleshare"; - notification.Closed += delegate { - Application.Invoke (delegate { - if (SparkleUI.EventLog == null) - SparkleUI.EventLog = new SparkleEventLog (); - - SparkleUI.EventLog.Controller.SelectedFolder = null; - - SparkleUI.EventLog.ShowAll (); - SparkleUI.EventLog.Present (); - }); + notification.Closed += delegate (object o, EventArgs args) { + if ((args as CloseArgs).Reason == CloseReason.User) + Controller.BubbleClicked (); }; notification.Show (); diff --git a/SparkleShare/SparkleBubblesController.cs b/SparkleShare/SparkleBubblesController.cs index 1dcf0a1c..2b1b7cff 100755 --- a/SparkleShare/SparkleBubblesController.cs +++ b/SparkleShare/SparkleBubblesController.cs @@ -28,10 +28,8 @@ namespace SparkleShare { public SparkleBubblesController () { - Program.Controller.ConflictNotificationRaised += delegate { - ShowBubble ("Conflict detected.", - "Don't worry, SparkleShare made a copy of each conflicting file.", - null); + Program.Controller.AlertNotificationRaised += delegate (string title, string message) { + ShowBubble (title, message, null); }; Program.Controller.NotificationRaised += delegate (SparkleChangeSet change_set) { @@ -53,6 +51,12 @@ namespace SparkleShare { } + public void BubbleClicked () + { + Program.Controller.ShowEventLogWindow (); + } + + private string FormatMessage (SparkleChangeSet change_set) { string file_name = ""; diff --git a/SparkleShare/SparkleController.cs b/SparkleShare/SparkleController.cs index 3016430d..5dcd461e 100755 --- a/SparkleShare/SparkleController.cs +++ b/SparkleShare/SparkleController.cs @@ -45,10 +45,12 @@ namespace SparkleShare { // Creates a .desktop entry in autostart folder to // start SparkleShare automatically at login - public override void EnableSystemAutostart () + public override void CreateStartupItem () { - string autostart_path = Path.Combine (Environment.GetFolderPath ( - Environment.SpecialFolder.ApplicationData), "autostart"); + string autostart_path = Path.Combine ( + Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData), + "autostart" + ); string desktopfile_path = Path.Combine (autostart_path, "sparkleshare.desktop"); @@ -56,57 +58,33 @@ namespace SparkleShare { Directory.CreateDirectory (autostart_path); if (!File.Exists (desktopfile_path)) { - TextWriter writer = new StreamWriter (desktopfile_path); - writer.WriteLine ("[Desktop Entry]\n" + - "Type=Application\n" + - "Name=SparkleShare\n" + - "Exec=sparkleshare start\n" + - "Icon=folder-sparkleshare\n" + - "Terminal=false\n" + - "X-GNOME-Autostart-enabled=true\n" + - "Categories=Network"); - writer.Close (); + try { + File.WriteAllText (desktopfile_path, + "[Desktop Entry]\n" + + "Type=Application\n" + + "Name=SparkleShare\n" + + "Exec=sparkleshare start\n" + + "Icon=folder-sparkleshare\n" + + "Terminal=false\n" + + "X-GNOME-Autostart-enabled=true\n" + + "Categories=Network"); - // Give the launcher the right permissions so it can be launched by the user - UnixFileInfo file_info = new UnixFileInfo (desktopfile_path); - file_info.Create (FileAccessPermissions.UserReadWriteExecute); + // Give the launcher the right permissions so it can be launched by the user + UnixFileInfo file_info = new UnixFileInfo (desktopfile_path); + file_info.Create (FileAccessPermissions.UserReadWriteExecute); - SparkleHelpers.DebugInfo ("Controller", "Enabled autostart on login"); + SparkleHelpers.DebugInfo ("Controller", "Added " + app_path + " to login items"); + + } catch (Exception e) { + SparkleHelpers.DebugInfo ("Controller", "Failed adding " + app_path + " to login items: " + e.Message); + } } } - - // Installs a launcher so the user can launch SparkleShare - // from the Internet category if needed - public override void InstallLauncher () + + public override void InstallProtocolHandler () { - string apps_path = - new string [] {SparkleConfig.DefaultConfig.HomePath, - ".local", "share", "applications"}.Combine (); - - string desktopfile_path = Path.Combine (apps_path, "sparkleshare.desktop"); - - if (!File.Exists (desktopfile_path)) { - if (!Directory.Exists (apps_path)) - Directory.CreateDirectory (apps_path); - - TextWriter writer = new StreamWriter (desktopfile_path); - writer.WriteLine ("[Desktop Entry]\n" + - "Type=Application\n" + - "Name=SparkleShare\n" + - "Comment=Share documents\n" + - "Exec=sparkleshare start\n" + - "Icon=folder-sparkleshare\n" + - "Terminal=false\n" + - "Categories=Network;"); - writer.Close (); - - // Give the launcher the right permissions so it can be launched by the user - UnixFileInfo file_info = new UnixFileInfo (desktopfile_path); - file_info.FileAccessPermissions = FileAccessPermissions.UserReadWriteExecute; - - SparkleHelpers.DebugInfo ("Controller", "Created '" + desktopfile_path + "'"); - } + // TODO } @@ -226,7 +204,7 @@ namespace SparkleShare { { Process process = new Process (); process.StartInfo.FileName = "xdg-open"; - process.StartInfo.Arguments = url.Replace (" ", "%20"); + process.StartInfo.Arguments = "\"" + url + "\""; process.Start (); } } diff --git a/SparkleShare/SparkleControllerBase.cs b/SparkleShare/SparkleControllerBase.cs index 23b156f8..2cb75de0 100644 --- a/SparkleShare/SparkleControllerBase.cs +++ b/SparkleShare/SparkleControllerBase.cs @@ -36,12 +36,23 @@ namespace SparkleShare { public abstract class SparkleControllerBase { - public List Repositories; + public List Repositories = new List (); public readonly string SparklePath = SparkleConfig.DefaultConfig.FoldersPath; public double ProgressPercentage = 0.0; public string ProgressSpeed = ""; + + public event ShowSetupWindowEventHandler ShowSetupWindowEvent; + public delegate void ShowSetupWindowEventHandler (PageType page_type); + + public event ShowAboutWindowEventHandler ShowAboutWindowEvent; + public delegate void ShowAboutWindowEventHandler (); + + public event ShowEventLogWindowEventHandler ShowEventLogWindowEvent; + public delegate void ShowEventLogWindowEventHandler (); + + public event FolderFetchedEventHandler FolderFetched; public delegate void FolderFetchedEventHandler (string [] warnings); @@ -66,24 +77,47 @@ namespace SparkleShare { public event OnErrorHandler OnError; public delegate void OnErrorHandler (); - public event OnInviteHandler OnInvite; - public delegate void OnInviteHandler (SparkleInvite invite); - - public event ConflictNotificationRaisedHandler ConflictNotificationRaised; - public delegate void ConflictNotificationRaisedHandler (); + public event InviteReceivedHandler InviteReceived; + public delegate void InviteReceivedHandler (SparkleInvite invite); public event NotificationRaisedEventHandler NotificationRaised; public delegate void NotificationRaisedEventHandler (SparkleChangeSet change_set); + public event AlertNotificationRaisedEventHandler AlertNotificationRaised; + public delegate void AlertNotificationRaisedEventHandler (string title, string message); + public event NoteNotificationRaisedEventHandler NoteNotificationRaised; public delegate void NoteNotificationRaisedEventHandler (SparkleUser user, string folder_name); + + // Path where the plugins are kept public abstract string PluginsPath { get; } + // Enables SparkleShare to start automatically at login + public abstract void CreateStartupItem (); + + // Installs the sparkleshare:// protocol handler + public abstract void InstallProtocolHandler (); + + // Adds the SparkleShare folder to the user's + // list of bookmarked places + public abstract void AddToBookmarks (); + + // Creates the SparkleShare folder in the user's home folder + public abstract bool CreateSparkleShareFolder (); + + // Opens the SparkleShare folder or an (optional) subfolder + public abstract void OpenSparkleShareFolder (string subfolder); + + // Opens a file with the appropriate application + public abstract void OpenFile (string url); + + private SparkleFetcherBase fetcher; private List failed_avatars = new List (); private Object avatar_lock = new Object (); + private Object repo_lock = new Object (); // Short alias for the translations @@ -97,11 +131,10 @@ namespace SparkleShare { { } - + public virtual void Initialize () { - InstallLauncher (); - EnableSystemAutostart (); + InstallProtocolHandler (); // Create the SparkleShare folder and add it to the bookmarks if (CreateSparkleShareFolder ()) @@ -128,16 +161,37 @@ namespace SparkleShare { FolderListChanged (); }; + watcher.Created += delegate (object o, FileSystemEventArgs args) { + if (!args.FullPath.EndsWith (".xml")) + return; - SparkleInviteListener invite_listener = new SparkleInviteListener (1987); + if (this.fetcher != null && + this.fetcher.IsActive) { - invite_listener.InviteReceived += delegate (SparkleInvite invite) { - if (OnInvite != null && !FirstRun) - OnInvite (invite); + if (AlertNotificationRaised != null) + AlertNotificationRaised ("SparkleShare Setup seems busy", + "Please wait for it to finish"); + + } else { + if (InviteReceived != null) { + SparkleInvite invite = new SparkleInvite (args.FullPath); + + if (invite.IsValid) { + InviteReceived (invite); + + } else { + invite = null; + + if (AlertNotificationRaised != null) + AlertNotificationRaised ("Oh noes!", + "This invite seems screwed up..."); + } + + File.Delete (args.FullPath); + } + } }; - invite_listener.Start (); - new Thread (new ThreadStart (PopulateRepositories)).Start (); } @@ -149,43 +203,11 @@ namespace SparkleShare { } - // Uploads the user's public key to the server - public bool AcceptInvitation (string server, string folder, string token) - { - // The location of the user's public key for SparkleShare - string public_key_file_path = SparkleHelpers.CombineMore (SparkleConfig.DefaultConfig.HomePath, - ".ssh", "sparkleshare." + UserEmail + ".key.pub"); - - if (!File.Exists (public_key_file_path)) - return false; - - StreamReader reader = new StreamReader (public_key_file_path); - string public_key = reader.ReadToEnd (); - reader.Close (); - - string url = "https://" + server + "/?folder=" + folder + - "&token=" + token + "&pubkey=" + public_key; - - SparkleHelpers.DebugInfo ("WebRequest", url); - - HttpWebRequest request = (HttpWebRequest) WebRequest.Create (url); - HttpWebResponse response = (HttpWebResponse) request.GetResponse(); - - if (response.StatusCode == HttpStatusCode.OK) { - response.Close (); - return true; - - } else { - response.Close (); - return false; - } - } - - public List Folders { get { List folders = SparkleConfig.DefaultConfig.Folders; folders.Sort (); + return folders; } } @@ -196,6 +218,7 @@ namespace SparkleShare { List hosts = SparkleConfig.DefaultConfig.HostsWithUsername; hosts.AddRange(SparkleConfig.DefaultConfig.Hosts); hosts.Sort (); + return hosts; } } @@ -205,27 +228,53 @@ namespace SparkleShare { get { List unsynced_folders = new List (); - foreach (SparkleRepoBase repo in Repositories) { - if (repo.HasUnsyncedChanges) - unsynced_folders.Add (repo.Name); - } + lock (this.repo_lock) { + foreach (SparkleRepoBase repo in Repositories) { + if (repo.HasUnsyncedChanges) + unsynced_folders.Add (repo.Name); + } + } return unsynced_folders; } } + public void ShowSetupWindow (PageType page_type) + { + if (ShowSetupWindowEvent != null) + ShowSetupWindowEvent (page_type); + } + + + public void ShowAboutWindow () + { + if (ShowAboutWindowEvent != null) + ShowAboutWindowEvent (); + } + + + public void ShowEventLogWindow () + { + if (ShowEventLogWindowEvent != null) + ShowEventLogWindowEvent (); + } + + + public List GetLog () { List list = new List (); - foreach (SparkleRepoBase repo in Repositories) { - List change_sets = repo.GetChangeSets (30); - - if (change_sets != null) - list.AddRange (change_sets); - else - SparkleHelpers.DebugInfo ("Log", "Could not create log for " + repo.Name); + lock (this.repo_lock) { + foreach (SparkleRepoBase repo in Repositories) { + List change_sets = repo.GetChangeSets (30); + + if (change_sets != null) + list.AddRange (change_sets); + else + SparkleHelpers.DebugInfo ("Log", "Could not create log for " + repo.Name); + } } list.Sort ((x, y) => (x.Timestamp.CompareTo (y.Timestamp))); @@ -245,10 +294,12 @@ namespace SparkleShare { string path = Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, name); int log_size = 50; - - foreach (SparkleRepoBase repo in Repositories) { - if (repo.LocalPath.Equals (path)) - return repo.GetChangeSets (log_size); + + lock (this.repo_lock) { + foreach (SparkleRepoBase repo in Repositories) { + if (repo.LocalPath.Equals (path)) + return repo.GetChangeSets (log_size); + } } return null; @@ -437,8 +488,8 @@ namespace SparkleShare { if (File.Exists (change_set_avatar)) change_set_avatar = "file://" + change_set_avatar; else - change_set_avatar = ""; - + change_set_avatar = "/" + AssignAvatar (change_set.User.Email); + event_entry += ""; string timestamp = change_set.Timestamp.ToString ("H:mm"); @@ -508,47 +559,26 @@ namespace SparkleShare { } - // Creates a .desktop entry in autostart folder to - // start SparkleShare automatically at login - public abstract void EnableSystemAutostart (); - - // Installs a launcher so the user can launch SparkleShare - // from the Internet category if needed - public abstract void InstallLauncher (); - - // Adds the SparkleShare folder to the user's - // list of bookmarked places - public abstract void AddToBookmarks (); - - // Creates the SparkleShare folder in the user's home folder - public abstract bool CreateSparkleShareFolder (); - - // Opens the SparkleShare folder or an (optional) subfolder - public abstract void OpenSparkleShareFolder (string subfolder); - - // Opens a file with the appropriate application - public abstract void OpenFile (string url); - - // Fires events for the current syncing state public void UpdateState () { bool has_syncing_repos = false; bool has_unsynced_repos = false; - foreach (SparkleRepoBase repo in Repositories) { - if (repo.Status == SyncStatus.SyncDown || - repo.Status == SyncStatus.SyncUp || - repo.IsBuffering) { - - has_syncing_repos = true; - - } else if (repo.HasUnsyncedChanges) { - has_unsynced_repos = true; + lock (this.repo_lock) { + foreach (SparkleRepoBase repo in Repositories) { + if (repo.Status == SyncStatus.SyncDown || + repo.Status == SyncStatus.SyncUp || + repo.IsBuffering) { + + has_syncing_repos = true; + + } else if (repo.HasUnsyncedChanges) { + has_unsynced_repos = true; + } } } - if (has_syncing_repos) { if (OnSyncing != null) OnSyncing (); @@ -586,7 +616,6 @@ namespace SparkleShare { repo.NewChangeSet += delegate (SparkleChangeSet change_set) { - if (NotificationRaised != null) NotificationRaised (change_set); }; @@ -598,8 +627,9 @@ namespace SparkleShare { }; repo.ConflictResolved += delegate { - if (ConflictNotificationRaised != null) - ConflictNotificationRaised (); + if (AlertNotificationRaised != null) + AlertNotificationRaised ("Conflict detected.", + "Don't worry, SparkleShare made a copy of each conflicting file."); }; repo.SyncStatusChanged += delegate (SyncStatus status) { @@ -629,7 +659,10 @@ namespace SparkleShare { }; - Repositories.Add (repo); + lock (this.repo_lock) { + Repositories.Add (repo); + } + repo.Initialize (); } @@ -640,14 +673,16 @@ namespace SparkleShare { { string folder_name = Path.GetFileName (folder_path); - for (int i = 0; i < Repositories.Count; i++) { - SparkleRepoBase repo = Repositories [i]; - - if (repo.Name.Equals (folder_name)) { - repo.Dispose (); - Repositories.Remove (repo); - repo = null; - break; + lock (this.repo_lock) { + for (int i = 0; i < Repositories.Count; i++) { + SparkleRepoBase repo = Repositories [i]; + + if (repo.Name.Equals (folder_name)) { + repo.Dispose (); + Repositories.Remove (repo); + repo = null; + break; + } } } } @@ -657,8 +692,6 @@ namespace SparkleShare { // folders in the SparkleShare folder private void PopulateRepositories () { - Repositories = new List (); - foreach (string folder_name in SparkleConfig.DefaultConfig.Folders) { string folder_path = new SparkleFolder (folder_name).FullPath; @@ -701,34 +734,6 @@ namespace SparkleShare { } - public string GetSize (string folder_name) - { - double folder_size = 0; - /* TODO - foreach (SparkleRepoBase repo in - Repositories.GetRange (0, Repositories.Count)) { - - folder_size += repo.Size + repo.HistorySize; - } - */ - return FormatSize (folder_size); - } - - - public string GetHistorySize (string folder_name) - { - double folder_size = 0; - /* TODO - foreach (SparkleRepoBase repo in - Repositories.GetRange (0, Repositories.Count)) { - - folder_size += repo.Size + repo.HistorySize; - } - */ - return FormatSize (folder_size); - } - - // Format a file size nicely with small caps. // Example: 1048576 becomes "1 ᴍʙ" public string FormatSize (double byte_count) @@ -738,9 +743,9 @@ namespace SparkleShare { else if (byte_count >= 1073741824) return String.Format ("{0:##.##} ɢʙ", Math.Round (byte_count / 1073741824, 1)); else if (byte_count >= 1048576) - return String.Format ("{0:##.##} ᴍʙ", Math.Round (byte_count / 1048576, 1)); + return String.Format ("{0:##.##} ᴍʙ", Math.Round (byte_count / 1048576, 0)); else if (byte_count >= 1024) - return String.Format ("{0:##.##} ᴋʙ", Math.Round (byte_count / 1024, 1)); + return String.Format ("{0:##.##} ᴋʙ", Math.Round (byte_count / 1024, 0)); else return byte_count.ToString () + " bytes"; } @@ -881,7 +886,6 @@ namespace SparkleShare { } foreach (string raw_email in emails) { - // Gravatar wants lowercase emails string email = raw_email.ToLower (); string avatar_file_path = Path.Combine (avatar_path, "avatar-" + email); @@ -896,9 +900,6 @@ namespace SparkleShare { old_avatars.Add (email); } catch (FileNotFoundException) { - // FIXME: For some reason the previous File.Exists () check - // doesn't cover all cases sometimes, so we catch any errors - if (old_avatars.Contains (email)) old_avatars.Remove (email); } @@ -906,11 +907,11 @@ namespace SparkleShare { } else if (this.failed_avatars.Contains (email)) { break; + } else { WebClient client = new WebClient (); string url = "http://gravatar.com/avatar/" + GetMD5 (email) + ".jpg?s=" + size + "&d=404"; - try { // Fetch the avatar byte [] buffer = client.DownloadData (url); @@ -930,11 +931,10 @@ namespace SparkleShare { SparkleHelpers.DebugInfo ("Avatar", "Failed fetching gravatar for " + email); // Stop downloading further avatars if we have no internet access - if (e.Status == WebExceptionStatus.Timeout){ + if (e.Status == WebExceptionStatus.Timeout) break; - } else { + else this.failed_avatars.Add (email); - } } } } @@ -969,10 +969,14 @@ namespace SparkleShare { } - public void FetchFolder (string server, string remote_folder) + public void FetchFolder (string server, string remote_folder, string announcements_url) { - server = server.Trim (); - remote_folder = remote_folder.Trim (); + server = server.Trim (); + remote_folder = remote_folder.Trim (); + + if (announcements_url != null) + announcements_url = announcements_url.Trim (); + string tmp_path = SparkleConfig.DefaultConfig.TmpPath; if (!Directory.Exists (tmp_path)) { @@ -1042,8 +1046,14 @@ namespace SparkleShare { try { Directory.Move (tmp_folder, target_folder_path); - SparkleConfig.DefaultConfig.AddFolder (target_folder_name, this.fetcher.RemoteUrl, backend); + + if (!string.IsNullOrEmpty (announcements_url)) { + SparkleConfig.DefaultConfig.SetFolderOptionalAttribute (target_folder_name, + "announcements_url", announcements_url); + } + + AddRepository (target_folder_path); if (FolderFetched != null) @@ -1060,6 +1070,8 @@ namespace SparkleShare { } catch (Exception e) { SparkleHelpers.DebugInfo ("Controller", "Error moving folder: " + e.Message); } + + this.fetcher = null; }; this.fetcher.Failed += delegate { @@ -1070,6 +1082,8 @@ namespace SparkleShare { if (Directory.Exists (tmp_path)) Directory.Delete (tmp_path, true); + + this.fetcher = null; }; this.fetcher.ProgressChanged += delegate (double percentage) { @@ -1093,12 +1107,14 @@ namespace SparkleShare { // quits if safe public void TryQuit () { - foreach (SparkleRepoBase repo in Repositories) { - if (repo.Status == SyncStatus.SyncUp || - repo.Status == SyncStatus.SyncDown || - repo.IsBuffering) { - - return; + lock (this.repo_lock) { + foreach (SparkleRepoBase repo in Repositories) { + if (repo.Status == SyncStatus.SyncUp || + repo.Status == SyncStatus.SyncDown || + repo.IsBuffering) { + + return; + } } } @@ -1108,8 +1124,10 @@ namespace SparkleShare { public virtual void Quit () { - foreach (SparkleRepoBase repo in Repositories) - repo.Dispose (); + lock (this.repo_lock) { + foreach (SparkleRepoBase repo in Repositories) + repo.Dispose (); + } #if __MonoCS__ Environment.Exit (0); @@ -1124,9 +1142,11 @@ namespace SparkleShare { folder_name = folder_name.Replace ("%20", " "); note = note.Replace ("%20", " "); - foreach (SparkleRepoBase repo in Repositories) { - if (repo.Name.Equals (folder_name)) - repo.AddNote (revision, note); + lock (this.repo_lock) { + foreach (SparkleRepoBase repo in Repositories) { + if (repo.Name.Equals (folder_name)) + repo.AddNote (revision, note); + } } } @@ -1138,13 +1158,25 @@ namespace SparkleShare { private string AssignColor (string s) { - string hash = GetMD5 (s).Substring (0, 8); + string hash = "0" + GetMD5 (s).Substring (0, 8); string numbers = Regex.Replace (hash, "[a-z]", ""); - int number = 3 + int.Parse (numbers); + int number = int.Parse (numbers); + return this.tango_palette [number % this.tango_palette.Length]; } + private string AssignAvatar (string s) + { + string hash = "0" + GetMD5 (s).Substring (0, 8); + string numbers = Regex.Replace (hash, "[a-z]", ""); + int number = int.Parse (numbers); + string letters = "abcdefghijklmnopqrstuvwxyz"; + + return "avatar-" + letters [(number % 11)] + ".png"; + } + + // Creates an MD5 hash of input private string GetMD5 (string s) { diff --git a/SparkleShare/SparkleEntry.cs b/SparkleShare/SparkleEntry.cs deleted file mode 100755 index 304fe941..00000000 --- a/SparkleShare/SparkleEntry.cs +++ /dev/null @@ -1,106 +0,0 @@ -// SparkleShare, a collaboration and sharing tool. -// Copyright (C) 2010 Hylke Bons -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General private License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General private License for more details. -// -// You should have received a copy of the GNU General private License -// along with this program. If not, see . - - -using Gtk; - -// TODO: Remove with Gtk3 -namespace SparkleShare { - - public class SparkleEntry : Entry { - - - private string example_text; - private bool example_text_active; - - - public SparkleEntry () - { - ExampleTextActive = true; - - FocusGrabbed += delegate { OnEntered (); }; - ClipboardPasted += delegate { OnEntered (); }; - - FocusOutEvent += delegate { - if (Text.Equals ("") || Text == null) - ExampleTextActive = true; - - if (ExampleTextActive) - UseExampleText (); - }; - } - - - private void OnEntered () - { - if (ExampleTextActive) { - ExampleTextActive = false; - Text = ""; - UseNormalTextColor (); - } - } - - - public bool ExampleTextActive { - get { - return this.example_text_active; - } - - set { - this.example_text_active = value; - - if (this.example_text_active) - UseSecondaryTextColor (); - else - UseNormalTextColor (); - } - } - - - public string ExampleText - { - get { - return this.example_text; - } - - set { - this.example_text = value; - - if (this.example_text_active) - UseExampleText (); - } - } - - - private void UseExampleText () - { - Text = this.example_text; - UseSecondaryTextColor (); - } - - - private void UseSecondaryTextColor () - { - ModifyText (StateType.Normal, Style.Foreground (StateType.Insensitive)); - } - - - private void UseNormalTextColor () - { - ModifyText (StateType.Normal, Style.Foreground (StateType.Normal)); - } - } -} diff --git a/SparkleShare/SparkleEventLog.cs b/SparkleShare/SparkleEventLog.cs index b9f39580..833be1d4 100755 --- a/SparkleShare/SparkleEventLog.cs +++ b/SparkleShare/SparkleEventLog.cs @@ -30,6 +30,7 @@ namespace SparkleShare { public SparkleEventLogController Controller = new SparkleEventLogController (); private Label size_label; + private Label history_label; private HBox layout_horizontal; private ComboBox combo_box; private EventBox content_wrapper; @@ -54,14 +55,27 @@ namespace SparkleShare { Resizable = true; BorderWidth = 0; - Title = _("Recent Events"); + Title = _("Recent Changes"); IconName = "folder-sparkleshare"; - DeleteEvent += Close; + DeleteEvent += delegate (object o, DeleteEventArgs args) { + Controller.WindowClosed (); + args.RetVal = true; + }; this.size_label = new Label () { - Markup = "Size:History: …" + Markup = "Size: …", + Xalign = 0 }; + + this.history_label = new Label () { + Markup = "History: …", + Xalign = 0 + }; + + HBox layout_sizes = new HBox (false, 12); + layout_sizes.Add (this.size_label); + layout_sizes.Add (this.history_label); VBox layout_vertical = new VBox (false, 0); this.spinner = new SparkleSpinner (22); @@ -78,7 +92,7 @@ namespace SparkleShare { this.web_view.NavigationRequested += delegate (object o, WebKit.NavigationRequestedArgs args) { if (args.Request.Uri == this.link_status) - SparkleEventLogController.LinkClicked (args.Request.Uri); + Controller.LinkClicked (args.Request.Uri); // Don't follow HREFs (as this would cause a page refresh) if (!args.Request.Uri.Equals ("file:")) @@ -90,22 +104,33 @@ namespace SparkleShare { this.spinner.Start (); - this.layout_horizontal = new HBox (false, 0); - this.layout_horizontal.PackStart (this.size_label, true, true, 0); - this.layout_horizontal.PackStart (new Label (" "), false, false, 0); + this.layout_horizontal = new HBox (true, 0); + this.layout_horizontal.PackStart (layout_sizes, true, true, 12); layout_vertical.PackStart (this.layout_horizontal, false, false, 0); layout_vertical.PackStart (CreateShortcutsBar (), false, false, 0); layout_vertical.PackStart (this.content_wrapper, true, true, 0); Add (layout_vertical); - ShowAll (); - - UpdateChooser (null); - UpdateContent (null); // Hook up the controller events + Controller.HideWindowEvent += delegate { + Application.Invoke (delegate { + HideAll (); + }); + }; + + Controller.ShowWindowEvent += delegate { + Application.Invoke (delegate { + ShowAll (); + Present (); + + UpdateChooser (null); + UpdateContent (null); + }); + }; + Controller.UpdateChooserEvent += delegate (string [] folders) { Application.Invoke (delegate { UpdateChooser (folders); @@ -131,10 +156,11 @@ namespace SparkleShare { Controller.UpdateSizeInfoEvent += delegate (string size, string history_size) { Application.Invoke (delegate { - this.size_label.Markup = "Size: " + size + " " + - "History: " + history_size; + this.size_label.Markup = "Size: " + size; + this.history_label.Markup = "History: " + history_size; this.size_label.ShowAll (); + this.history_label.ShowAll (); }); }; } @@ -207,9 +233,8 @@ namespace SparkleShare { html = html.Replace ("", SparkleUIHelpers.GdkColorToHex (Style.Background (StateType.Normal))); html = html.Replace ("", SparkleUIHelpers.GdkColorToHex (Style.Foreground (StateType.Insensitive))); html = html.Replace ("", SparkleUIHelpers.GdkColorToHex (Style.Foreground (StateType.Insensitive))); - html = html.Replace ("", "file://" + - new string [] {SparkleUI.AssetsPath, "icons", - "hicolor", "32x32", "status", "avatar-default.png"}.Combine ()); + html = html.Replace ("", "file://" + + new string [] {SparkleUI.AssetsPath, "pixmaps"}.Combine ()); html = html.Replace ("", "file://" + new string [] {SparkleUI.AssetsPath, "icons", "hicolor", "12x12", "status", "document-added.png"}.Combine ()); @@ -223,6 +248,8 @@ namespace SparkleShare { new string [] {SparkleUI.AssetsPath, "icons", "hicolor", "12x12", "status", "document-moved.png"}.Combine ()); +Console.WriteLine (html); + Application.Invoke (delegate { this.spinner.Stop (); this.web_view.LoadString (html, null, null, "file://"); @@ -236,13 +263,6 @@ namespace SparkleShare { } - public void Close (object o, DeleteEventArgs args) - { - HideAll (); - args.RetVal = true; - } - - private MenuBar CreateShortcutsBar () { // Adds a hidden menubar that contains to enable keyboard @@ -261,15 +281,15 @@ namespace SparkleShare { AddAccelGroup (accel_group); // Close on Esc - close_1.AddAccelerator ("activate", accel_group, new AccelKey (Gdk.Key.W, Gdk.ModifierType.ControlMask, - AccelFlags.Visible)); + close_1.AddAccelerator ("activate", accel_group, new AccelKey (Gdk.Key.W, + Gdk.ModifierType.ControlMask, AccelFlags.Visible)); - close_1.Activated += delegate { HideAll (); }; + close_1.Activated += delegate { Controller.WindowClosed (); }; // Close on Ctrl+W - close_2.AddAccelerator ("activate", accel_group, new AccelKey (Gdk.Key.Escape, Gdk.ModifierType.None, - AccelFlags.Visible)); - close_2.Activated += delegate { HideAll (); }; + close_2.AddAccelerator ("activate", accel_group, new AccelKey (Gdk.Key.Escape, + Gdk.ModifierType.None, AccelFlags.Visible)); + close_2.Activated += delegate { Controller.WindowClosed (); }; file_menu.Append (close_1); file_menu.Append (close_2); diff --git a/SparkleShare/SparkleEventLogController.cs b/SparkleShare/SparkleEventLogController.cs index c4243eac..97b6fefd 100755 --- a/SparkleShare/SparkleEventLogController.cs +++ b/SparkleShare/SparkleEventLogController.cs @@ -28,6 +28,12 @@ namespace SparkleShare { public class SparkleEventLogController { + public event ShowWindowEventHandler ShowWindowEvent; + public delegate void ShowWindowEventHandler (); + + public event HideWindowEventHandler HideWindowEvent; + public delegate void HideWindowEventHandler (); + public event UpdateContentEventEventHandler UpdateContentEvent; public delegate void UpdateContentEventEventHandler (string html); @@ -146,6 +152,11 @@ namespace SparkleShare { public SparkleEventLogController () { + Program.Controller.ShowEventLogWindowEvent += delegate { + if (ShowWindowEvent != null) + ShowWindowEvent (); + }; + Program.Controller.AvatarFetched += delegate { if (UpdateContentEvent != null) UpdateContentEvent (HTML); @@ -178,7 +189,14 @@ namespace SparkleShare { } - public static void LinkClicked (string url) + public void WindowClosed () + { + if (HideWindowEvent != null) + HideWindowEvent (); + } + + + public void LinkClicked (string url) { if (url.StartsWith (Path.VolumeSeparatorChar.ToString ())) { Program.Controller.OpenFile (url); diff --git a/SparkleShare/SparkleInvite.cs b/SparkleShare/SparkleInvite.cs index ca660648..2252c242 100644 --- a/SparkleShare/SparkleInvite.cs +++ b/SparkleShare/SparkleInvite.cs @@ -18,10 +18,8 @@ using System; using System.IO; using System.Net; -using System.Net.Sockets; using System.Text; using System.Xml; -using System.Threading; using SparkleLib; @@ -29,32 +27,31 @@ namespace SparkleShare { public class SparkleInvite { - public readonly Uri FullAddress; - public readonly string Token; + public string Address { get; private set; } + public string RemotePath { get; private set; } + public Uri AcceptUrl { get; private set; } + public Uri AnnouncementsUrl { get; private set; } - public string Host { - get { - return FullAddress.Host; - } - } - public string Path { + public bool IsValid { get { - return FullAddress.AbsolutePath; + return (!string.IsNullOrEmpty (Address) && + !string.IsNullOrEmpty (RemotePath)); } } - public SparkleInvite (string host, string path, string token) + public SparkleInvite (string address, string remote_path, + string accept_url) { - if (path.StartsWith ("/")) - path = path.Substring (1); + Initialize (address, remote_path, accept_url, null); + } - if (!host.EndsWith ("/")) - host = host + "/"; - FullAddress = new Uri ("ssh://" + host + path); - Token = token; + public SparkleInvite (string address, string remote_path, + string accept_url, string announcements_url) + { + Initialize (address, remote_path, accept_url, announcements_url); } @@ -63,166 +60,81 @@ namespace SparkleShare { XmlDocument xml_document = new XmlDocument (); XmlNode node; - string host = "", path = "", token = ""; + string address = ""; + string remote_path = ""; + string accept_url = ""; + string announcements_url = ""; try { xml_document.Load (xml_file_path); - node = xml_document.SelectSingleNode ("/sparkleshare/invite/host/text()"); - if (node != null) { host = node.Value; } + node = xml_document.SelectSingleNode ("/sparkleshare/invite/address/text()"); + if (node != null) { address = node.Value; } - node = xml_document.SelectSingleNode ("/sparkleshare/invite/path/text()"); - if (node != null) { path = node.Value; } + node = xml_document.SelectSingleNode ("/sparkleshare/invite/remote_path/text()"); + if (node != null) { remote_path = node.Value; } - node = xml_document.SelectSingleNode ("/sparkleshare/invite/token/text()"); - if (node != null) { token = node.Value; } + node = xml_document.SelectSingleNode ("/sparkleshare/invite/accept_url/text()"); + if (node != null) { accept_url = node.Value; } + + node = xml_document.SelectSingleNode ("/sparkleshare/invite/announcements_url/text()"); + if (node != null) { announcements_url = node.Value; } + + Initialize (address, remote_path, accept_url, announcements_url); } catch (XmlException e) { SparkleHelpers.DebugInfo ("Invite", "Invalid XML: " + e.Message); return; } - - - if (path.StartsWith ("/")) - path = path.Substring (1); - - if (!host.EndsWith ("/")) - host = host + "/"; - - FullAddress = new Uri ("ssh://" + host + path); - Token = token; - } - } - - - public class SparkleInviteListener { - - public event InviteReceivedHandler InviteReceived; - public delegate void InviteReceivedHandler (SparkleInvite invite); - - private Thread thread; - private TcpListener tcp_listener; - - - public SparkleInviteListener (int port) - { - this.tcp_listener = new TcpListener (IPAddress.Loopback, port); - this.thread = new Thread(new ThreadStart (Listen)); } - public void Start () + public bool Accept () { - this.thread.Start (); - } + if (AcceptUrl == null) + return true; + + try { + WebRequest request = WebRequest.Create (AcceptUrl); + + request.Method = "POST"; + request.ContentType = "application/x-www-form-urlencoded"; + string post_data = "pubkey=" + SparkleConfig.DefaultConfig.User.PublicKey; + byte [] post_bytes = Encoding.UTF8.GetBytes (post_data); + request.ContentLength = post_bytes.Length; + + Stream data_stream = request.GetRequestStream (); + data_stream.Write (post_bytes, 0, post_bytes.Length); + data_stream.Close (); + + WebResponse response = request.GetResponse (); + response.Close (); - private void Listen () - { - this.tcp_listener.Start (); - - while (true) - { - // Blocks until a client connects - TcpClient client = this.tcp_listener.AcceptTcpClient (); - - // Create a thread to handle communications - Thread client_thread = new Thread (HandleClient); - client_thread.Start (client); - } - } - - - private void HandleClient (object client) - { - TcpClient tcp_client = (TcpClient) client; - NetworkStream client_stream = tcp_client.GetStream (); - - byte [] message = new byte [4096]; - int bytes_read; - - while (true) - { - bytes_read = 0; - - try { - // Blocks until the client sends a message - bytes_read = client_stream.Read (message, 0, 4096); - - } catch { - Console.WriteLine ("Socket error..."); - } - - // The client has disconnected - if (bytes_read == 0) - break; - - ASCIIEncoding encoding = new ASCIIEncoding (); - string received_message = encoding.GetString (message, 0, bytes_read); - string invite_xml = ""; - - if (received_message.StartsWith (Uri.UriSchemeHttp) || - received_message.StartsWith (Uri.UriSchemeHttps)) { - - WebClient web_client = new WebClient (); - - try { - // Fetch the invite file - byte [] buffer = web_client.DownloadData (received_message); - SparkleHelpers.DebugInfo ("Invite", "Received: " + received_message); - - invite_xml = ASCIIEncoding.ASCII.GetString (buffer); - - } catch (WebException e) { - SparkleHelpers.DebugInfo ("Invite", "Failed downloading: " + - received_message + " " + e.Message); - continue; - } - - } else if (received_message.StartsWith (Uri.UriSchemeFile)) { - try { - received_message = received_message.Replace (Uri.UriSchemeFile + "://", ""); - invite_xml = File.ReadAllText (received_message); - - } catch { - SparkleHelpers.DebugInfo ("Invite", "Failed opening: " + received_message); - continue; - } + if ((response as HttpWebResponse).StatusCode == HttpStatusCode.OK) { + SparkleHelpers.DebugInfo ("Invite", "Uploaded public key to " + AcceptUrl); + return true; } else { - SparkleHelpers.DebugInfo ("Invite", - "Path to invite must use either the file:// or http(s):// scheme"); - - continue; + SparkleHelpers.DebugInfo ("Invite", "Failed uploading public key to " + AcceptUrl); + return false; } - XmlDocument xml_document = new XmlDocument (); - XmlNode node; + } catch (WebException e) { + SparkleHelpers.DebugInfo ("Invite", "Failed uploading public key to " + AcceptUrl + ": " + e.Message); - string host = "", path = "", token = ""; - - try { - xml_document.LoadXml (invite_xml); - - node = xml_document.SelectSingleNode ("/sparkleshare/invite/host/text()"); - if (node != null) { host = node.Value; } - - node = xml_document.SelectSingleNode ("/sparkleshare/invite/path/text()"); - if (node != null) { path = node.Value; } - - node = xml_document.SelectSingleNode ("/sparkleshare/invite/token/text()"); - if (node != null) { token = node.Value; } - - } catch (XmlException e) { - SparkleHelpers.DebugInfo ("Invite", "Invalid XML: " + received_message + " " + e.Message); - return; - } - - if (InviteReceived != null) - InviteReceived (new SparkleInvite (host, path, token)); + return false; } + } - tcp_client.Close (); + + private void Initialize (string address, string remote_path, + string accept_url, string announcements_url) + { + Address = address; + RemotePath = remote_path; + AcceptUrl = new Uri (accept_url); + AnnouncementsUrl = new Uri (announcements_url); } } } diff --git a/SparkleShare/SparklePlugin.cs b/SparkleShare/SparklePlugin.cs index 3868438b..b3d2db81 100644 --- a/SparkleShare/SparklePlugin.cs +++ b/SparkleShare/SparklePlugin.cs @@ -49,6 +49,12 @@ namespace SparkleShare { } } + public string AnnouncementsUrl { + get { + return GetValue ("info", "announcements_url"); + } + } + public string Address { get { return GetValue ("address", "value"); diff --git a/SparkleShare/SparkleSetup.cs b/SparkleShare/SparkleSetup.cs index 9eb6d69e..29578ac2 100755 --- a/SparkleShare/SparkleSetup.cs +++ b/SparkleShare/SparkleSetup.cs @@ -31,9 +31,6 @@ namespace SparkleShare { public SparkleSetupController Controller = new SparkleSetupController (); - private string SecondaryTextColor; - private string SecondaryTextColorSelected; - private ProgressBar progress_bar = new ProgressBar (); @@ -46,15 +43,18 @@ namespace SparkleShare { public SparkleSetup () : base () { - SecondaryTextColor = SparkleUIHelpers.GdkColorToHex (Style.Foreground (StateType.Insensitive)); - SecondaryTextColorSelected = - SparkleUIHelpers.GdkColorToHex ( - MixColors ( - new TreeView ().Style.Foreground (StateType.Selected), - new TreeView ().Style.Background (StateType.Selected), - 0.15 - ) - ); + Controller.HideWindowEvent += delegate { + Application.Invoke (delegate { + HideAll (); + }); + }; + + Controller.ShowWindowEvent += delegate { + Application.Invoke (delegate { + ShowAll (); + Present (); + }); + }; Controller.ChangePageEvent += delegate (PageType type, string [] warnings) { Application.Invoke (delegate { @@ -64,8 +64,8 @@ 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) { @@ -172,8 +172,10 @@ namespace SparkleShare { tree.AppendColumn (service_column); - SparkleEntry path_entry = new SparkleEntry (); - SparkleEntry address_entry = new SparkleEntry (); + Entry address_entry = new Entry (); + Entry path_entry = new Entry (); + Label address_example = new Label ("1") { Xalign = 0, UseMarkup = true }; + Label path_example = new Label ("2") { Xalign = 0, UseMarkup = true }; // Select the first plugin by default @@ -186,18 +188,11 @@ namespace SparkleShare { string example_text, FieldState state) { Application.Invoke (delegate { - address_entry.Text = text; - address_entry.Sensitive = (state == FieldState.Enabled); + address_entry.Text = text; + address_entry.Sensitive = (state == FieldState.Enabled); + address_example.Markup = "" + example_text + ""; - if (string.IsNullOrEmpty (example_text)) - address_entry.ExampleText = null; - else - address_entry.ExampleText = example_text; - - if (string.IsNullOrEmpty (text)) - address_entry.ExampleTextActive = true; - else - address_entry.ExampleTextActive = false; }); }; @@ -205,20 +200,13 @@ namespace SparkleShare { string example_text, FieldState state) { Application.Invoke (delegate { - path_entry.Text = text; - path_entry.Sensitive = (state == FieldState.Enabled); - - if (string.IsNullOrEmpty (example_text)) - path_entry.ExampleText = null; - else - path_entry.ExampleText = example_text; - - if (string.IsNullOrEmpty (text)) - path_entry.ExampleTextActive = true; - else - path_entry.ExampleTextActive = false; + path_entry.Text = text; + path_entry.Sensitive = (state == FieldState.Enabled); + path_example.Markup = "" + example_text + ""; }); }; + // Update the address field text when the selection changes tree.CursorChanged += delegate (object sender, EventArgs e) { @@ -272,11 +260,12 @@ namespace SparkleShare { }; layout_address.PackStart (new Label () { - Markup = "" + _("Address") + "", + Markup = "" + _("Address:") + "", Xalign = 0 }, true, true, 0); - layout_address.PackStart (address_entry, true, true, 0); + layout_address.PackStart (address_entry, false, false, 0); + layout_address.PackStart (address_example, false, false, 0); path_entry.Completion = new EntryCompletion(); @@ -293,11 +282,12 @@ namespace SparkleShare { }; layout_path.PackStart (new Label () { - Markup = "" + _("Remote Path") + "", + Markup = "" + _("Remote Path:") + "", Xalign = 0 }, true, true, 0); - layout_path.PackStart (path_entry, true, true, 0); + layout_path.PackStart (path_entry, false, false, 0); + layout_path.PackStart (path_example, false, false, 0); layout_fields.PackStart (layout_address); layout_fields.PackStart (layout_path); @@ -312,10 +302,9 @@ namespace SparkleShare { Button cancel_button = new Button (_("Cancel")); cancel_button.Clicked += delegate { - Close (); + Controller.PageCancelled (); }; - // Sync button Button add_button = new Button (_("Add")); add_button.Clicked += delegate { @@ -325,10 +314,72 @@ namespace SparkleShare { Controller.AddPageCompleted (server, folder_name); }; + Controller.UpdateAddProjectButtonEvent += delegate (bool button_enabled) { + Application.Invoke (delegate { + add_button.Sensitive = button_enabled; + }); + }; + AddButton (cancel_button); AddButton (add_button); - Controller.CheckAddPage (address_entry.Text, path_entry.Text, tree.SelectedRow); + Controller.CheckAddPage (address_entry.Text, path_entry.Text, 1); + + break; + } + + case PageType.Invite: { + + Header = _("You've reveived an invite!"); + Description = _("Do you want to add this project to SparkleShare?"); + + + Table table = new Table (2, 3, true) { + RowSpacing = 6, + ColumnSpacing = 6 + }; + + Label address_label = new Label (_("Address:")) { + Xalign = 1 + }; + + Label path_label = new Label (_("Remote Path:")) { + Xalign = 1 + }; + + Label address_value = new Label ("" + Controller.PendingInvite.Address + "") { + UseMarkup = true, + Xalign = 0 + }; + + Label path_value = new Label ("" + Controller.PendingInvite.RemotePath + "") { + UseMarkup = true, + Xalign = 0 + }; + + table.Attach (address_label, 0, 1, 0, 1); + table.Attach (address_value, 1, 2, 0, 1); + table.Attach (path_label, 0, 1, 1, 2); + table.Attach (path_value, 1, 2, 1, 2); + + VBox wrapper = new VBox (false, 9); + wrapper.PackStart (table, true, false, 0); + + Button cancel_button = new Button (_("Cancel")); + + cancel_button.Clicked += delegate { + Controller.PageCancelled (); + }; + + Button add_button = new Button (_("Add")); + + add_button.Clicked += delegate { + Controller.InvitePageCompleted (); + }; + + AddButton (cancel_button); + AddButton (add_button); + Add (wrapper); break; } @@ -455,14 +506,13 @@ namespace SparkleShare { Button open_folder_button = new Button (_("Open Folder")); open_folder_button.Clicked += delegate { - Program.Controller.OpenSparkleShareFolder (System.IO.Path.GetFileName (Controller.PreviousPath)); + Controller.OpenFolderClicked (); }; Button finish_button = new Button (_("Finish")); finish_button.Clicked += delegate { - Controller.FinishedPageCompleted (); - Close (); + Controller.FinishPageCompleted (); }; @@ -502,8 +552,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 { @@ -527,8 +577,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 { @@ -545,8 +595,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 { @@ -563,29 +613,25 @@ 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"); Button finish_button = new Button (_("Finish")); finish_button.Clicked += delegate { - Close (); + Controller.FinishPageCompleted (); }; - VBox box = new VBox (false, 0); - box.Add (slide); - box.Add (label); + check_button = new CheckButton ("Add SparkleShare to startup items"); - Add (box); + check_button.Toggled += delegate { + Controller.StartupItemChanged (check_button.Active); + }; + + Add (slide); + AddOption (check_button); AddButton (finish_button); break; @@ -615,16 +661,6 @@ namespace SparkleShare { (cell as CellRendererText).Markup = markup; } - - - private Gdk.Color MixColors (Gdk.Color first_color, Gdk.Color second_color, double ratio) - { - return new Gdk.Color ( - Convert.ToByte ((255 * (Math.Min (65535, first_color.Red * (1.0 - ratio) + second_color.Red * ratio))) / 65535), - Convert.ToByte ((255 * (Math.Min (65535, first_color.Green * (1.0 - ratio) + second_color.Green * ratio))) / 65535), - Convert.ToByte ((255 * (Math.Min (65535, first_color.Blue * (1.0 - ratio) + second_color.Blue * ratio))) / 65535) - ); - } } diff --git a/SparkleShare/SparkleSetupController.cs b/SparkleShare/SparkleSetupController.cs index 1b0cc3c6..2f2fadf0 100755 --- a/SparkleShare/SparkleSetupController.cs +++ b/SparkleShare/SparkleSetupController.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; +using System.Threading; using SparkleLib; @@ -27,6 +28,7 @@ namespace SparkleShare { public enum PageType { Setup, Add, + Invite, Syncing, Error, Finished, @@ -41,6 +43,12 @@ namespace SparkleShare { public class SparkleSetupController { + public event ShowWindowEventHandler ShowWindowEvent; + public delegate void ShowWindowEventHandler (); + + public event HideWindowEventHandler HideWindowEvent; + public delegate void HideWindowEventHandler (); + public event ChangePageEventHandler ChangePageEvent; public delegate void ChangePageEventHandler (PageType page, string [] warnings); @@ -58,12 +66,18 @@ namespace SparkleShare { string example_text, FieldState state); public event ChangePathFieldEventHandler ChangePathFieldEvent; - public delegate void ChangePathFieldEventHandler (string text, - string example_text, FieldState state); + public delegate void ChangePathFieldEventHandler (string text, string example_text, FieldState state); public readonly List Plugins = new List (); public SparklePlugin SelectedPlugin; + public SparkleInvite PendingInvite { get; private set; } + public int TutorialPageNumber { get; private set; } + public string PreviousUrl { get; private set; } + public string PreviousAddress { get; private set; } + public string PreviousPath { get; private set; } + public string SyncingFolder { get; private set; } + public int SelectedPluginIndex { get { @@ -71,42 +85,6 @@ namespace SparkleShare { } } - public int TutorialPageNumber { - get { - return this.tutorial_page_number; - } - } - - public string PreviousUrl { - get { - return this.previous_url; - } - } - - public string PreviousAddress { - get { - return this.previous_address; - } - } - - public string PreviousPath { - get { - return this.previous_path; - } - } - - public string SyncingFolder { - get { - return this.syncing_folder; - } - } - - public PageType PreviousPage { - get { - return this.previous_page; - } - } - public string GuessedUserName { get { return Program.Controller.UserName; @@ -123,16 +101,19 @@ namespace SparkleShare { } - private string previous_address = ""; - private string previous_path = ""; - private string previous_url = ""; - private string syncing_folder = ""; - private int tutorial_page_number = 1; - private PageType previous_page; + private string saved_address = ""; + private string saved_remote_path = ""; + private bool create_startup_item = true; public SparkleSetupController () { + TutorialPageNumber = 0; + PreviousAddress = ""; + PreviousPath = ""; + PreviousUrl = ""; + SyncingFolder = ""; + string local_plugins_path = SparkleHelpers.CombineMore ( Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData), "sparkleshare", "plugins"); @@ -152,16 +133,57 @@ namespace SparkleShare { SelectedPlugin = Plugins [0]; - ChangePageEvent += delegate (PageType page, string [] warning) { - this.previous_page = page; + + Program.Controller.InviteReceived += delegate (SparkleInvite invite) { + if (ChangePageEvent != null) + ChangePageEvent (PageType.Invite, null); + + if (ShowWindowEvent != null) + ShowWindowEvent (); + }; + + + Program.Controller.ShowSetupWindowEvent += delegate (PageType page_type) { + if (PendingInvite != null) { + if (ShowWindowEvent != null) + ShowWindowEvent (); + + return; + } + + if (page_type == PageType.Add) { + if (!Program.Controller.FirstRun && + (TutorialPageNumber == 0 || + TutorialPageNumber > 4)) { + + if (ChangePageEvent != null) + ChangePageEvent (page_type, null); + + if (ShowWindowEvent != null) + ShowWindowEvent (); + + SelectedPluginChanged (SelectedPluginIndex); + + } + + return; + } + + if (ChangePageEvent != null) + ChangePageEvent (page_type, null); + + if (ShowWindowEvent != null) + ShowWindowEvent (); }; } - public void ShowSetupPage () + public void PageCancelled () { - if (ChangePageEvent != null) - ChangePageEvent (PageType.Setup, null); + PendingInvite = null; + + if (HideWindowEvent != null) + HideWindowEvent (); } @@ -185,16 +207,8 @@ namespace SparkleShare { Program.Controller.GenerateKeyPair (); Program.Controller.ImportPrivateKey (); - Program.Controller.UpdateState (); - if (ChangePageEvent != null) - ChangePageEvent (PageType.Tutorial, null); - } - - - public void TutorialPageCompleted () - { - this.tutorial_page_number++; + TutorialPageNumber = 1; if (ChangePageEvent != null) ChangePageEvent (PageType.Tutorial, null); @@ -203,101 +217,34 @@ namespace SparkleShare { public void TutorialSkipped () { - this.tutorial_page_number = 4; + TutorialPageNumber = 4; if (ChangePageEvent != null) ChangePageEvent (PageType.Tutorial, null); } - public void ShowAddPage () + public void StartupItemChanged (bool create_startup_item) { - if (ChangePageEvent != null) - ChangePageEvent (PageType.Add, null); - - SelectedPluginChanged (SelectedPluginIndex); + this.create_startup_item = create_startup_item; } - public void CheckAddPage (string address, string remote_path, int selected_plugin) + public void TutorialPageCompleted () { - if (SelectedPluginIndex != selected_plugin) - SelectedPluginChanged (selected_plugin); + TutorialPageNumber++; - address = address.Trim (); - remote_path = remote_path.Trim (); + if (TutorialPageNumber == 5) { + if (HideWindowEvent != null) + HideWindowEvent (); - bool fields_valid = address != null && address.Trim().Length > 0 && - remote_path != null && remote_path.Trim().Length > 0; + if (this.create_startup_item) + Program.Controller.CreateStartupItem (); - if (UpdateAddProjectButtonEvent != null) - UpdateAddProjectButtonEvent (fields_valid); - } - - - public void AddPageCompleted (string address, string path) - { - this.syncing_folder = Path.GetFileNameWithoutExtension (path); - this.previous_address = address; - this.previous_path = path; - - if (ChangePageEvent != null) - ChangePageEvent (PageType.Syncing, null); - - // TODO: Remove events afterwards - - Program.Controller.FolderFetched += delegate (string [] warnings) { + } else { if (ChangePageEvent != null) - ChangePageEvent (PageType.Finished, warnings); - - this.previous_address = ""; - this.syncing_folder = ""; - this.previous_url = ""; - SelectedPlugin = Plugins [0]; - }; - - Program.Controller.FolderFetchError += delegate (string remote_url) { - this.previous_url = remote_url; - - if (ChangePageEvent != null) - ChangePageEvent (PageType.Error, null); - - this.syncing_folder = ""; - }; - - Program.Controller.FolderFetching += delegate (double percentage) { - if (UpdateProgressBarEvent != null) - UpdateProgressBarEvent (percentage); - }; - - Program.Controller.FetchFolder (address, path); - } - - - public void ErrorPageCompleted () - { - if (ChangePageEvent != null) - ChangePageEvent (PageType.Add, null); - } - - - public void SyncingCancelled () - { - Program.Controller.StopFetcher (); - - if (ChangePageEvent != null) - ChangePageEvent (PageType.Add, null); - } - - - // TODO: public void WindowClosed () { } - - - public void FinishedPageCompleted () - { - this.previous_address = ""; - this.previous_path = ""; - Program.Controller.UpdateState (); + ChangePageEvent (PageType.Tutorial, null); + } } @@ -311,10 +258,10 @@ namespace SparkleShare { } else if (SelectedPlugin.AddressExample != null) { if (ChangeAddressFieldEvent != null) - ChangeAddressFieldEvent ("", SelectedPlugin.AddressExample, FieldState.Enabled); + ChangeAddressFieldEvent (this.saved_address, SelectedPlugin.AddressExample, FieldState.Enabled); } else { if (ChangeAddressFieldEvent != null) - ChangeAddressFieldEvent ("", "", FieldState.Enabled); + ChangeAddressFieldEvent (this.saved_address, "", FieldState.Enabled); } if (SelectedPlugin.Path != null) { @@ -323,15 +270,175 @@ namespace SparkleShare { } else if (SelectedPlugin.PathExample != null) { if (ChangePathFieldEvent != null) - ChangePathFieldEvent ("", SelectedPlugin.PathExample, FieldState.Enabled); + ChangePathFieldEvent (this.saved_remote_path, SelectedPlugin.PathExample, FieldState.Enabled); } else { if (ChangePathFieldEvent != null) - ChangePathFieldEvent ("", "", FieldState.Enabled); + ChangePathFieldEvent (this.saved_remote_path, "", FieldState.Enabled); } } + public void CheckAddPage (string address, string remote_path, int selected_plugin) + { + if (SelectedPluginIndex != selected_plugin) + SelectedPluginChanged (selected_plugin); + + address = address.Trim (); + remote_path = remote_path.Trim (); + + if (selected_plugin == 0) + this.saved_address = address; + + this.saved_remote_path = remote_path; + + bool fields_valid = address != null && address.Trim ().Length > 0 && + remote_path != null && remote_path.Trim ().Length > 0; + + if (UpdateAddProjectButtonEvent != null) + UpdateAddProjectButtonEvent (fields_valid); + } + + + public void AddPageCompleted (string address, string path) + { + SyncingFolder = Path.GetFileNameWithoutExtension (path); + PreviousAddress = address; + PreviousPath = path; + + if (ChangePageEvent != null) + ChangePageEvent (PageType.Syncing, null); + + // TODO: Remove events afterwards + + Program.Controller.FolderFetched += delegate (string [] warnings) { + if (ChangePageEvent != null) + ChangePageEvent (PageType.Finished, warnings); + + PreviousAddress = ""; + SyncingFolder = ""; + PreviousUrl = ""; + SelectedPlugin = Plugins [0]; + }; + + Program.Controller.FolderFetchError += delegate (string remote_url) { + Thread.Sleep (1000); + PreviousUrl = remote_url; + + if (ChangePageEvent != null) + ChangePageEvent (PageType.Error, null); + + SyncingFolder = ""; + }; + + Program.Controller.FolderFetching += delegate (double percentage) { + if (UpdateProgressBarEvent != null) + UpdateProgressBarEvent (percentage); + }; + + Program.Controller.FetchFolder (address, path, SelectedPlugin.AnnouncementsUrl); + } + + + public void InvitePageCompleted () + { + SyncingFolder = Path.GetFileNameWithoutExtension (PendingInvite.RemotePath); + PreviousAddress = PendingInvite.Address; + // TODO: trailing slash should work + PreviousPath = PendingInvite.RemotePath; + + if (ChangePageEvent != null) + ChangePageEvent (PageType.Syncing, null); + + if (!PendingInvite.Accept ()) { + if (ChangePageEvent != null) + ChangePageEvent (PageType.Error, null); + + return; + } + + + // TODO: Remove events afterwards + + Program.Controller.FolderFetched += delegate (string [] warnings) { + if (ChangePageEvent != null) + ChangePageEvent (PageType.Finished, warnings); + + PreviousAddress = ""; + SyncingFolder = ""; + PreviousUrl = ""; + SelectedPlugin = Plugins [0]; + + PendingInvite = null; + }; + + Program.Controller.FolderFetchError += delegate (string remote_url) { + Thread.Sleep (1000); + PreviousUrl = remote_url; + + if (ChangePageEvent != null) + ChangePageEvent (PageType.Error, null); + + SyncingFolder = ""; + }; + + Program.Controller.FolderFetching += delegate (double percentage) { + if (UpdateProgressBarEvent != null) + UpdateProgressBarEvent (percentage); + }; + + Program.Controller.FetchFolder (PendingInvite.Address, + PendingInvite.RemotePath, PendingInvite.AnnouncementsUrl.ToString ()); + } + + + public void SyncingCancelled () + { + Program.Controller.StopFetcher (); + + if (ChangePageEvent == null) + return; + + if (PendingInvite != null) + ChangePageEvent (PageType.Invite, null); + else + ChangePageEvent (PageType.Add, null); + } + + + public void ErrorPageCompleted () + { + if (ChangePageEvent == null) + return; + + if (PendingInvite != null) + ChangePageEvent (PageType.Invite, null); + else + ChangePageEvent (PageType.Add, null); + } + + + public void OpenFolderClicked () + { + Program.Controller.OpenSparkleShareFolder ( + Path.GetFileName (PreviousPath)); + + FinishPageCompleted (); + } + + + public void FinishPageCompleted () + { + PreviousAddress = ""; + PreviousPath = ""; + + Program.Controller.UpdateState (); + + if (HideWindowEvent != null) + HideWindowEvent (); + } + + private bool IsValidEmail (string email) { Regex regex = new Regex (@"^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$", diff --git a/SparkleShare/SparkleSetupWindow.cs b/SparkleShare/SparkleSetupWindow.cs index 3ef464c8..1f4f347b 100755 --- a/SparkleShare/SparkleSetupWindow.cs +++ b/SparkleShare/SparkleSetupWindow.cs @@ -29,13 +29,18 @@ namespace SparkleShare { public class SparkleSetupWindow : Window { + // TODO: caps private HBox HBox; private VBox VBox; private VBox Wrapper; + private VBox OptionArea; private HButtonBox Buttons; public string Header; public string Description; + + public string SecondaryTextColor; + public string SecondaryTextColorSelected; public Container Content; @@ -48,25 +53,43 @@ namespace SparkleShare { WindowPosition = WindowPosition.Center; Deletable = false; - SetSizeRequest (680, 440); + SecondaryTextColor = SparkleUIHelpers.GdkColorToHex (Style.Foreground (StateType.Insensitive)); + + SecondaryTextColorSelected = + SparkleUIHelpers.GdkColorToHex ( + MixColors ( + new TreeView ().Style.Foreground (StateType.Selected), + new TreeView ().Style.Background (StateType.Selected), + 0.15 + ) + ); - DeleteEvent += delegate (object o, DeleteEventArgs args) { - args.RetVal = true; - Close (); - }; + SetSizeRequest (680, 400); - HBox = new HBox (false, 6); + HBox = new HBox (false, 0); VBox = new VBox (false, 0); Wrapper = new VBox (false, 0) { - BorderWidth = 30 + BorderWidth = 0 + }; + + OptionArea = new VBox (false, 0) { + BorderWidth = 0 }; Buttons = CreateButtonBox (); + + HBox layout_horizontal = new HBox (false , 0) { + BorderWidth = 0 + }; + + layout_horizontal.PackStart (OptionArea, true, true, 0); + layout_horizontal.PackStart (Buttons, false, false, 0); + VBox.PackStart (Wrapper, true, true, 0); - VBox.PackStart (Buttons, false, false, 0); + VBox.PackStart (layout_horizontal, false, false, 15); EventBox box = new EventBox (); Gdk.Color bg_color = new Gdk.Color (); @@ -79,7 +102,7 @@ namespace SparkleShare { box.Add (side_splash); HBox.PackStart (box, false, false, 0); - HBox.PackStart (VBox, true, true, 0); + HBox.PackStart (VBox, true, true, 30); base.Add (HBox); } @@ -88,7 +111,7 @@ namespace SparkleShare { private HButtonBox CreateButtonBox () { return new HButtonBox () { - BorderWidth = 12, + BorderWidth = 0, Layout = ButtonBoxStyle.End, Spacing = 6 }; @@ -102,11 +125,18 @@ namespace SparkleShare { } + public void AddOption (Widget widget) + { + OptionArea.Add (widget); + ShowAll (); + } + + new public void Add (Widget widget) { Label header = new Label ("" + Header + "") { UseMarkup = true, - Xalign = 0 + Xalign = 0, }; Label description = new Label (Description) { @@ -115,6 +145,7 @@ namespace SparkleShare { }; VBox layout_vertical = new VBox (false, 0); + layout_vertical.PackStart (new Label (""), false, false, 6); layout_vertical.PackStart (header, false, false, 0); if (!string.IsNullOrEmpty (Description)) @@ -142,15 +173,24 @@ namespace SparkleShare { ShowAll (); } + new public void ShowAll () { Present (); base.ShowAll (); } - - public void Close () + + + private Gdk.Color MixColors (Gdk.Color first_color, Gdk.Color second_color, double ratio) { - HideAll (); + return new Gdk.Color ( + Convert.ToByte ((255 * (Math.Min (65535, first_color.Red * (1.0 - ratio) + + second_color.Red * ratio))) / 65535), + Convert.ToByte ((255 * (Math.Min (65535, first_color.Green * (1.0 - ratio) + + second_color.Green * ratio))) / 65535), + Convert.ToByte ((255 * (Math.Min (65535, first_color.Blue * (1.0 - ratio) + + second_color.Blue * ratio))) / 65535) + ); } } } diff --git a/SparkleShare/SparkleStatusIcon.cs b/SparkleShare/SparkleStatusIcon.cs index 81ccb866..b69c36e3 100644 --- a/SparkleShare/SparkleStatusIcon.cs +++ b/SparkleShare/SparkleStatusIcon.cs @@ -75,7 +75,7 @@ namespace SparkleShare { if (Controller.Folders.Length == 0) this.state_text = _("Welcome to SparkleShare!"); else - this.state_text = _("Up to date") + Controller.FolderSize; + this.state_text = _("Files up to date") + Controller.FolderSize; CreateMenu (); @@ -99,7 +99,7 @@ namespace SparkleShare { if (Controller.Folders.Length == 0) this.state_text = _("Welcome to SparkleShare!"); else - this.state_text = _("Up to date") + Controller.FolderSize; + this.state_text = _("Files up to date") + Controller.FolderSize; #if HAVE_APP_INDICATOR this.indicator.IconName = "process-syncing-sparkleshare-i"; @@ -209,7 +209,7 @@ namespace SparkleShare { }; folder_item.Activated += delegate { - Program.Controller.OpenSparkleShareFolder (); + Controller.SparkleShareClicked (); }; this.menu.Add (folder_item); @@ -249,41 +249,20 @@ namespace SparkleShare { // Opens the wizard to add a new remote folder MenuItem sync_item = new MenuItem (_("Add Hosted Project…")); - - if (Program.Controller.FirstRun) - sync_item.Sensitive = false; sync_item.Activated += delegate { - Application.Invoke (delegate { - - if (SparkleUI.Setup == null) { - SparkleUI.Setup = new SparkleSetup (); - SparkleUI.Setup.Controller.ShowAddPage (); - } - - if (!SparkleUI.Setup.Visible) - SparkleUI.Setup.Controller.ShowAddPage (); - - //SparkleUI.Intro.ShowAll (); - //SparkleUI.Intro.Present (); - }); + Controller.AddHostedProjectClicked (); }; this.menu.Add (sync_item); this.menu.Add (new SeparatorMenuItem ()); - MenuItem recent_events_item = new MenuItem (_("Open Recent Events")); + MenuItem recent_events_item = new MenuItem (_("View Recent Changes…")); recent_events_item.Sensitive = (Controller.Folders.Length > 0); recent_events_item.Activated += delegate { - Application.Invoke (delegate { - if (SparkleUI.EventLog == null) - SparkleUI.EventLog = new SparkleEventLog (); - - SparkleUI.EventLog.ShowAll (); - SparkleUI.EventLog.Present (); - }); + Controller.OpenRecentEventsClicked (); }; this.menu.Add (recent_events_item); @@ -307,13 +286,7 @@ namespace SparkleShare { MenuItem about_item = new MenuItem (_("About SparkleShare")); about_item.Activated += delegate { - Application.Invoke (delegate { - if (SparkleUI.About == null) - SparkleUI.About = new SparkleAbout (); - - SparkleUI.About.ShowAll (); - SparkleUI.About.Present (); - }); + Controller.AboutClicked (); }; this.menu.Add (about_item); @@ -342,7 +315,7 @@ namespace SparkleShare { private EventHandler OpenFolderDelegate (string name) { return delegate { - Program.Controller.OpenSparkleShareFolder (name); + Controller.SubfolderClicked (name); }; } diff --git a/SparkleShare/SparkleStatusIconController.cs b/SparkleShare/SparkleStatusIconController.cs index aa67810e..05671aec 100755 --- a/SparkleShare/SparkleStatusIconController.cs +++ b/SparkleShare/SparkleStatusIconController.cs @@ -129,5 +129,35 @@ namespace SparkleShare { UpdateMenuEvent (IconState.Error); }; } + + + public void SparkleShareClicked () + { + Program.Controller.OpenSparkleShareFolder (); + } + + + public void SubfolderClicked (string subfolder) + { + Program.Controller.OpenSparkleShareFolder (subfolder); + } + + + public void AddHostedProjectClicked () + { + Program.Controller.ShowSetupWindow (PageType.Add); + } + + + public void OpenRecentEventsClicked () + { + Program.Controller.ShowEventLogWindow (); + } + + + public void AboutClicked () + { + Program.Controller.ShowAboutWindow (); + } } } diff --git a/SparkleShare/SparkleUI.cs b/SparkleShare/SparkleUI.cs index be435328..17618ce2 100644 --- a/SparkleShare/SparkleUI.cs +++ b/SparkleShare/SparkleUI.cs @@ -41,6 +41,7 @@ namespace SparkleShare { public static SparkleBubbles Bubbles; public static SparkleSetup Setup; public static SparkleAbout About; + public static string AssetsPath = new string [] {Defines.PREFIX, "share", "sparkleshare"}.Combine (); @@ -62,13 +63,14 @@ namespace SparkleShare { Catalog.Init (Defines.GETTEXT_PACKAGE, Defines.LOCALE_DIR); #endif - StatusIcon = new SparkleStatusIcon (); + Setup = new SparkleSetup (); + EventLog = new SparkleEventLog (); + About = new SparkleAbout (); Bubbles = new SparkleBubbles (); - - if (Program.Controller.FirstRun) { - Setup = new SparkleSetup (); - Setup.Controller.ShowSetupPage (); - } + StatusIcon = new SparkleStatusIcon (); + + if (Program.Controller.FirstRun) + Program.Controller.ShowSetupWindow (PageType.Setup); } diff --git a/SparkleShare/sparkleshare-invite-open.cs b/SparkleShare/sparkleshare-invite-open.cs new file mode 100644 index 00000000..7a8b812f --- /dev/null +++ b/SparkleShare/sparkleshare-invite-open.cs @@ -0,0 +1,66 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +using System; +using System.IO; +using System.Net; + +namespace SparkleShare { + + public class SparkleShare { + + public static void Main (string [] args) { + + new SparkleInviteOpen (args [0]); + } + } + + + public class SparkleInviteOpen { + + public SparkleInviteOpen (string url) + { + string safe_url = url.Replace ("sparkleshare://", "https://"); + string unsafe_url = url.Replace ("sparkleshare://", "http://"); + string xml = ""; + + WebClient web_client = new WebClient (); + + try { + xml = web_client.DownloadString (safe_url); + + } catch { + Console.WriteLine ("Failed downloading invite: " + safe_url); + + try { + xml = web_client.DownloadString (safe_url); + + } catch { + Console.WriteLine ("Failed downloading invite: " + unsafe_url); + } + } + + string home_path = Environment.GetFolderPath (Environment.SpecialFolder.Personal); + string target_path = Path.Combine (home_path, "SparkleShare"); + + if (xml.Contains ("")) { + File.WriteAllText (target_path, xml); + Console.WriteLine ("Downloaded invite: " + safe_url); + } + } + } +} diff --git a/configure.ac b/configure.ac index ac6a1f62..0d4adcd5 100755 --- a/configure.ac +++ b/configure.ac @@ -1,9 +1,9 @@ dnl Process this file with autoconf to produce a configure script. m4_define([sparkleshare_version], - [0.8.2]) + [0.8.3]) m4_define([sparkleshare_asm_version], - [0.8.2]) + [0.8.3]) AC_PREREQ([2.54]) AC_INIT([SparkleShare], sparkleshare_version) diff --git a/data/Makefile.am b/data/Makefile.am index cea4d45f..cf1520b3 100755 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -9,6 +9,17 @@ dist_pixmaps_DATA = \ tutorial-slide-2.png \ tutorial-slide-3.png \ tutorial-slide-4.png \ + avatar-a.png \ + avatar-b.png \ + avatar-c.png \ + avatar-d.png \ + avatar-e.png \ + avatar-f.png \ + avatar-g.png \ + avatar-h.png \ + avatar-i.png \ + avatar-j.png \ + avatar-k.png \ about.png pixmapsdir = $(pkgdatadir)/pixmaps/ diff --git a/data/avatar-a.png b/data/avatar-a.png new file mode 100644 index 00000000..4ffc65a4 Binary files /dev/null and b/data/avatar-a.png differ diff --git a/data/avatar-b.png b/data/avatar-b.png new file mode 100644 index 00000000..891fce67 Binary files /dev/null and b/data/avatar-b.png differ diff --git a/data/avatar-c.png b/data/avatar-c.png new file mode 100644 index 00000000..17cc5ef7 Binary files /dev/null and b/data/avatar-c.png differ diff --git a/data/avatar-d.png b/data/avatar-d.png new file mode 100644 index 00000000..af35c7de Binary files /dev/null and b/data/avatar-d.png differ diff --git a/data/avatar-e.png b/data/avatar-e.png new file mode 100644 index 00000000..31a98e12 Binary files /dev/null and b/data/avatar-e.png differ diff --git a/data/avatar-f.png b/data/avatar-f.png new file mode 100644 index 00000000..59cc2e55 Binary files /dev/null and b/data/avatar-f.png differ diff --git a/data/avatar-g.png b/data/avatar-g.png new file mode 100644 index 00000000..6abe1253 Binary files /dev/null and b/data/avatar-g.png differ diff --git a/data/avatar-h.png b/data/avatar-h.png new file mode 100644 index 00000000..14dd39f0 Binary files /dev/null and b/data/avatar-h.png differ diff --git a/data/avatar-i.png b/data/avatar-i.png new file mode 100644 index 00000000..2f9cc3e3 Binary files /dev/null and b/data/avatar-i.png differ diff --git a/data/avatar-j.png b/data/avatar-j.png new file mode 100644 index 00000000..7187ca19 Binary files /dev/null and b/data/avatar-j.png differ diff --git a/data/avatar-k.png b/data/avatar-k.png new file mode 100644 index 00000000..afdc3fe7 Binary files /dev/null and b/data/avatar-k.png differ diff --git a/data/html/protocol-handler-test/add-to-sparkleshare-button.png b/data/html/protocol-handler-test/add-to-sparkleshare-button.png new file mode 100644 index 00000000..be46a091 Binary files /dev/null and b/data/html/protocol-handler-test/add-to-sparkleshare-button.png differ diff --git a/data/html/protocol-handler-test/invite.xml b/data/html/protocol-handler-test/invite.xml new file mode 100644 index 00000000..5c4f9d18 --- /dev/null +++ b/data/html/protocol-handler-test/invite.xml @@ -0,0 +1,9 @@ + + + +
ssh://git@github.com/
+ /hbons/Stuff + http://www.sparkleshare.org/test.php +
+
+ diff --git a/data/html/protocol-handler-test/protocol-handler-test.htm b/data/html/protocol-handler-test/protocol-handler-test.htm new file mode 100644 index 00000000..9e0a1226 --- /dev/null +++ b/data/html/protocol-handler-test/protocol-handler-test.htm @@ -0,0 +1,38 @@ + + + SparkleShare Protocol Handler Test + + + +
+ hbons's stuff on Github + + Add to SparkleShare + +
+ + + diff --git a/data/icons/Makefile.am b/data/icons/Makefile.am index d09cc805..da21e519 100755 --- a/data/icons/Makefile.am +++ b/data/icons/Makefile.am @@ -24,7 +24,7 @@ app_theme_icons = \ places,folder-sparkleshare-256.png \ places,folder-sparkleshare-32.png \ places,folder-sparkleshare-48.png \ - status,sparkleshare-syncing-error-24.png \ + status,sparkleshare-syncing-error-24.png \ status,avatar-default-16.png \ status,avatar-default-22.png \ status,avatar-default-24.png \ diff --git a/data/plugins/own-server.xml.in b/data/plugins/own-server.xml.in index 678cddff..c3f854b5 100644 --- a/data/plugins/own-server.xml.in +++ b/data/plugins/own-server.xml.in @@ -9,7 +9,7 @@
- domain name or IP address + [user@]hostname[:port]
@@ -17,4 +17,3 @@
- diff --git a/data/src/avatars.svg b/data/src/avatars.svg new file mode 100644 index 00000000..1fcc93a6 --- /dev/null +++ b/data/src/avatars.svg @@ -0,0 +1,676 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/tutorial-slide-4.png b/data/tutorial-slide-4.png index ae642773..315179b6 100755 Binary files a/data/tutorial-slide-4.png and b/data/tutorial-slide-4.png differ