diff --git a/NEWS b/NEWS index 07176044..f4eadf4e 100755 --- a/NEWS +++ b/NEWS @@ -1,3 +1,14 @@ +0.8.1 for Linux and Mac (Sun Jan 29): + + Hylke: + - Disable the Quit menu item when a sync is going on + - Show remote url when hovering project names in the log + - Fix the event log on Linux + - Allow server ports to be specified once again + - Open Folder button after setup now takes you to SparkleShare/subfolder + - Close event log on Cmd+W on Mac + + 0.8.0 for Linux and Mac (Sun Jan 22): Hylke: diff --git a/SparkleLib/Git/SparkleFetcherGit.cs b/SparkleLib/Git/SparkleFetcherGit.cs index d8e3b0e9..1d975916 100755 --- a/SparkleLib/Git/SparkleFetcherGit.cs +++ b/SparkleLib/Git/SparkleFetcherGit.cs @@ -51,7 +51,7 @@ namespace SparkleLib { if (!uri.Scheme.Equals ("ssh") && !uri.Scheme.Equals ("git")) { - uri = new Uri ("ssh://" + server); + uri = new Uri ("ssh://" + uri); } @@ -72,8 +72,10 @@ namespace SparkleLib { uri = new Uri ("ssh://git@gnome.org/git" + uri.AbsolutePath); } else { - if (string.IsNullOrEmpty (uri.UserInfo)) - uri = new Uri (uri.Scheme + "://git@" + uri.Host + uri.AbsolutePath); + if (string.IsNullOrEmpty (uri.UserInfo)) { + uri = new Uri (uri.Scheme + "://git@" + uri.Host + ":" + uri.Port + uri.AbsolutePath); + uri = new Uri (uri.ToString ().Replace (":-1", "")); + } } @@ -221,75 +223,11 @@ namespace SparkleLib { SparkleHelpers.CombineMore (this.target_folder, ".git", "info")); // File that lists the files we want git to ignore - string exlude_rules_file_path = Path.Combine (info.FullName, "exclude"); - TextWriter writer = new StreamWriter (exlude_rules_file_path); + string exclude_rules_file_path = Path.Combine (info.FullName, "exclude"); + TextWriter writer = new StreamWriter (exclude_rules_file_path); - // gedit and emacs - writer.WriteLine ("*~"); - - // Firefox and Chromium temporary download files - writer.WriteLine ("*.part"); - writer.WriteLine ("*.crdownload"); - - // vi(m) - writer.WriteLine (".*.sw[a-z]"); - writer.WriteLine ("*.un~"); - writer.WriteLine ("*.swp"); - writer.WriteLine ("*.swo"); - - // KDE - writer.WriteLine (".directory"); - - // Mac OS X - writer.WriteLine (".DS_Store"); - writer.WriteLine ("Icon?"); - writer.WriteLine ("._*"); - writer.WriteLine (".Spotlight-V100"); - writer.WriteLine (".Trashes"); - - // Omnigraffle - writer.WriteLine ("*(Autosaved).graffle"); - - // Windows - writer.WriteLine ("Thumbs.db"); - writer.WriteLine ("Desktop.ini"); - - // MS Office - writer.WriteLine ("~*.tmp"); - writer.WriteLine ("~*.TMP"); - writer.WriteLine ("*~*.tmp"); - writer.WriteLine ("*~*.TMP"); - writer.WriteLine ("~*.ppt"); - writer.WriteLine ("~*.PPT"); - writer.WriteLine ("~*.pptx"); - writer.WriteLine ("~*.PPTX"); - writer.WriteLine ("~*.xls"); - writer.WriteLine ("~*.XLS"); - writer.WriteLine ("~*.xlsx"); - writer.WriteLine ("~*.XLSX"); - writer.WriteLine ("~*.doc"); - writer.WriteLine ("~*.DOC"); - writer.WriteLine ("~*.docx"); - writer.WriteLine ("~*.DOCX"); - - // CVS - writer.WriteLine ("*/CVS/*"); - writer.WriteLine (".cvsignore"); - writer.WriteLine ("*/.cvsignore"); - - // Subversion - writer.WriteLine ("/.svn/*"); - writer.WriteLine ("*/.svn/*"); - - // Mercurial - writer.WriteLine ("/.hg/*"); - writer.WriteLine ("*/.hg/*"); - writer.WriteLine ("*/.hgignore"); - - // Bazaar - writer.WriteLine ("/.bzr/*"); - writer.WriteLine ("*/.bzr/*"); - writer.WriteLine ("*/.bzrignore"); + foreach (string exclude_rule in ExcludeRules) + writer.WriteLine (exclude_rule); writer.Close (); diff --git a/SparkleLib/Git/SparkleGit.cs b/SparkleLib/Git/SparkleGit.cs index 88199245..a2390f69 100644 --- a/SparkleLib/Git/SparkleGit.cs +++ b/SparkleLib/Git/SparkleGit.cs @@ -32,6 +32,7 @@ namespace SparkleLib { StartInfo.RedirectStandardOutput = true; StartInfo.UseShellExecute = false; StartInfo.WorkingDirectory = path; + StartInfo.CreateNoWindow = true; if (!string.IsNullOrEmpty (ExecPath)) StartInfo.Arguments = "--exec-path=\"" + ExecPath + "\" " + args; diff --git a/SparkleLib/Git/SparkleRepoGit.cs b/SparkleLib/Git/SparkleRepoGit.cs index c02fc38d..52e166a8 100644 --- a/SparkleLib/Git/SparkleRepoGit.cs +++ b/SparkleLib/Git/SparkleRepoGit.cs @@ -26,8 +26,9 @@ namespace SparkleLib { public class SparkleRepoGit : SparkleRepoBase { - public SparkleRepoGit (string path, SparkleBackend backend) : - base (path, backend) { } + public SparkleRepoGit (string path) : base (path) + { + } private string identifier = null; @@ -71,7 +72,7 @@ namespace SparkleLib { public override double Size { get { - string file_path = SparkleHelpers.CombineMore (LocalPath, ".git", "repo_size"); + string file_path = new string [] {LocalPath, ".git", "repo_size"}.Combine (); try { return double.Parse (File.ReadAllText (file_path)); @@ -85,7 +86,7 @@ namespace SparkleLib { public override double HistorySize { get { - string file_path = SparkleHelpers.CombineMore(LocalPath, ".git", "repo_history_size"); + string file_path = new string [] {LocalPath, ".git", "repo_history_size"}.Combine (); try { return double.Parse (File.ReadAllText (file_path)); @@ -105,8 +106,8 @@ namespace SparkleLib { double history_size = CalculateSize ( new DirectoryInfo (Path.Combine (LocalPath, ".git"))); - string size_file_path = SparkleHelpers.CombineMore(LocalPath, ".git", "repo_size"); - string history_size_file_path = SparkleHelpers.CombineMore(LocalPath, ".git", "repo_history_size"); + string size_file_path = new string [] {LocalPath, ".git", "repo_size"}.Combine (); + string history_size_file_path = new string [] {LocalPath, ".git", "repo_history_size"}.Combine (); File.WriteAllText (size_file_path, size.ToString ()); File.WriteAllText (history_size_file_path, history_size.ToString ()); @@ -169,7 +170,7 @@ namespace SparkleLib { public override bool CheckForRemoteChanges () { SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Checking for remote changes..."); - SparkleGit git = new SparkleGit (LocalPath, "ls-remote origin master"); + SparkleGit git = new SparkleGit (LocalPath, "ls-remote " + Url + " master"); git.Start (); git.WaitForExit (); @@ -201,7 +202,7 @@ namespace SparkleLib { SparkleGit git = new SparkleGit (LocalPath, "push --progress " + // Redirects progress stats to standarderror - "origin master"); + Url + " master"); git.StartInfo.RedirectStandardError = true; git.Start (); @@ -258,7 +259,7 @@ namespace SparkleLib { public override bool SyncDown () { - SparkleGit git = new SparkleGit (LocalPath, "fetch --progress"); + SparkleGit git = new SparkleGit (LocalPath, "fetch --progress " + Url); git.StartInfo.RedirectStandardError = true; git.Start (); @@ -623,11 +624,12 @@ 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.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.Timestamp = new DateTime (int.Parse (match.Groups [4].Value), int.Parse (match.Groups [5].Value), int.Parse (match.Groups [6].Value), diff --git a/SparkleLib/Makefile.am b/SparkleLib/Makefile.am index 3dd3ac2f..92a45ea8 100755 --- a/SparkleLib/Makefile.am +++ b/SparkleLib/Makefile.am @@ -9,6 +9,7 @@ SOURCES = \ SparkleBackend.cs \ SparkleChangeSet.cs \ SparkleConfig.cs \ + SparkleExtensions.cs \ SparkleFetcherBase.cs \ SparkleHelpers.cs \ SparkleListenerBase.cs \ diff --git a/SparkleLib/SparkleChangeSet.cs b/SparkleLib/SparkleChangeSet.cs index a24faaaa..bc173ac3 100755 --- a/SparkleLib/SparkleChangeSet.cs +++ b/SparkleLib/SparkleChangeSet.cs @@ -30,6 +30,7 @@ namespace SparkleLib { public DateTime Timestamp; public DateTime FirstTimestamp; public bool IsMagical = false; + public Uri Url; public List Added = new List (); public List Deleted = new List (); diff --git a/SparkleLib/SparkleExtensions.cs b/SparkleLib/SparkleExtensions.cs new file mode 100755 index 00000000..38e30e0a --- /dev/null +++ b/SparkleLib/SparkleExtensions.cs @@ -0,0 +1,35 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons (hylkebons@gmail.com) +// +// 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 (http://www.gnu.org/licenses/). + + +using System; +using System.IO; + +namespace SparkleLib { + + public static class Extensions { + + public static string Combine (this String [] parts) + { + string new_path = ""; + + foreach (string part in parts) + new_path = Path.Combine (new_path, part); + + return new_path; + } + } +} diff --git a/SparkleLib/SparkleFetcherBase.cs b/SparkleLib/SparkleFetcherBase.cs index da69976d..da7ce962 100755 --- a/SparkleLib/SparkleFetcherBase.cs +++ b/SparkleLib/SparkleFetcherBase.cs @@ -16,8 +16,8 @@ using System; -using System.IO; using System.Diagnostics; +using System.IO; using System.Security.AccessControl; using System.Text.RegularExpressions; using System.Threading; @@ -37,22 +37,94 @@ namespace SparkleLib { public event FailedEventHandler Failed; public event ProgressChangedEventHandler ProgressChanged; + public string [] ExcludeRules; + protected string target_folder; protected string remote_url; private Thread thread; - + public SparkleFetcherBase (string server, string remote_folder, string target_folder) { this.target_folder = target_folder; this.remote_url = server + "/" + remote_folder; + + ExcludeRules = new string [] { + // gedit and emacs + "*~", + + // Firefox and Chromium temporary download files + "*.part", + "*.crdownload", + + // vi(m) + ".*.sw[a-z]", + "*.un~", + "*.swp", + "*.swo", + + // KDE + ".directory", + + // Mac OS X + ".DS_Store", + "Icon?", + "._*", + ".Spotlight-V100", + ".Trashes", + + // Omnigraffle + "*(Autosaved).graffle", + + // Windows + "Thumbs.db", + "Desktop.ini", + + // MS Office + "~*.tmp", + "~*.TMP", + "*~*.tmp", + "*~*.TMP", + "~*.ppt", + "~*.PPT", + "~*.pptx", + "~*.PPTX", + "~*.xls", + "~*.XLS", + "~*.xlsx", + "~*.XLSX", + "~*.doc", + "~*.DOC", + "~*.docx", + "~*.DOCX", + + // CVS + "*/CVS/*", + ".cvsignore", + "*/.cvsignore", + + // Subversion + "/.svn/*", + "*/.svn/*", + + // Mercurial + "/.hg/*", + "*/.hg/*", + "*/.hgignore", + + // Bazaar + "/.bzr/*", + "*/.bzr/*", + "*/.bzrignore" + }; } public abstract bool Fetch (); public abstract string [] Warnings { get; } + // Clones the remote repository public void Start () { diff --git a/SparkleLib/SparkleLib.csproj b/SparkleLib/SparkleLib.csproj index a0ac9494..1c708116 100755 --- a/SparkleLib/SparkleLib.csproj +++ b/SparkleLib/SparkleLib.csproj @@ -49,6 +49,7 @@ + diff --git a/SparkleLib/SparkleListenerBase.cs b/SparkleLib/SparkleListenerBase.cs index 1770c04a..6d370bf5 100755 --- a/SparkleLib/SparkleListenerBase.cs +++ b/SparkleLib/SparkleListenerBase.cs @@ -64,7 +64,7 @@ namespace SparkleLib { SparkleHelpers.DebugInfo ("ListenerFactory", "Refered to existing listener for " + announce_uri); - listener.AlsoListenTo (folder_identifier); + listener.AlsoListenToBase (folder_identifier); return (SparkleListenerBase) listener; } } @@ -90,40 +90,52 @@ namespace SparkleLib { // listens for change notifications public abstract class SparkleListenerBase { - // We've connected to the server public event ConnectedEventHandler Connected; public delegate void ConnectedEventHandler (); - // We've disconnected from the server public event DisconnectedEventHandler Disconnected; public delegate void DisconnectedEventHandler (); - // We've been notified about a remote - // change by the channel - public event AnnouncementEventHandler Announcement; - public delegate void AnnouncementEventHandler (SparkleAnnouncement announcement); + public event ReceivedEventHandler Received; + public delegate void ReceivedEventHandler (SparkleAnnouncement announcement); + + public readonly Uri Server; + public abstract void Connect (); - public abstract void Announce (SparkleAnnouncement announcent); - public abstract void AlsoListenTo (string folder_identifier); public abstract bool IsConnected { get; } + public abstract bool IsConnecting { get; } + protected abstract void Announce (SparkleAnnouncement announcent); + protected abstract void AlsoListenTo (string folder_identifier); + protected List channels = new List (); - protected Dictionary> recent_announcements = new Dictionary> (); - protected int max_recent_announcements = 10; - protected Dictionary queue_up = new Dictionary (); - protected Dictionary queue_down = new Dictionary (); - protected bool is_connecting; - protected Uri server; - protected Timer reconnect_timer = new Timer { Interval = 60 * 1000, Enabled = true }; + + + private int max_recent_announcements = 10; + + private Dictionary> recent_announcements = + new Dictionary> (); + + private Dictionary queue_up = + new Dictionary (); + + private Dictionary queue_down = + new Dictionary (); + + private Timer reconnect_timer = new Timer { + Interval = 60 * 1000, + Enabled = true + }; public SparkleListenerBase (Uri server, string folder_identifier) { - this.server = server; + Server = server; + this.channels.Add (folder_identifier); this.reconnect_timer.Elapsed += delegate { - if (!IsConnected && !this.is_connecting) + if (!IsConnected && !IsConnecting) Reconnect (); }; @@ -133,29 +145,46 @@ namespace SparkleLib { public void AnnounceBase (SparkleAnnouncement announcement) { - if (!this.IsRecentAnnounement (announcement)) { + if (!IsRecentAnnouncement (announcement)) { if (IsConnected) { SparkleHelpers.DebugInfo ("Listener", - "Announcing message " + announcement.Message + " to " + announcement.FolderIdentifier + " on " + this.server); + "Announcing message " + announcement.Message + " to " + + announcement.FolderIdentifier + " on " + Server); Announce (announcement); - this.AddRecentAnnouncement (announcement); + AddRecentAnnouncement (announcement); + } else { - SparkleHelpers.DebugInfo ("Listener", "Can't send message to " + this.server + ". Queuing message"); + SparkleHelpers.DebugInfo ("Listener", + "Can't send message to " + + Server + ". Queuing message"); + this.queue_up [announcement.FolderIdentifier] = announcement; } } else { SparkleHelpers.DebugInfo ("Listener", - "Already processed message " + announcement.Message + " to " + announcement.FolderIdentifier + " from " + this.server); + "Already processed message " + announcement.Message + " to " + + announcement.FolderIdentifier + " from " + Server); } + } + + public void AlsoListenToBase (string channel) + { + if (!this.channels.Contains (channel) && IsConnected) { + SparkleHelpers.DebugInfo ("Listener", + "Subscribing to channel " + channel); + + this.channels.Add (channel); + AlsoListenTo (channel); + } } public void Reconnect () { - SparkleHelpers.DebugInfo ("Listener", "Trying to reconnect to " + this.server); + SparkleHelpers.DebugInfo ("Listener", "Trying to reconnect to " + Server); Connect (); } @@ -168,7 +197,8 @@ namespace SparkleLib { Connected (); if (this.queue_up.Count > 0) { - SparkleHelpers.DebugInfo ("Listener", "Delivering " + this.queue_up.Count + " queued messages..."); + SparkleHelpers.DebugInfo ("Listener", + "Delivering " + this.queue_up.Count + " queued messages..."); foreach (KeyValuePair item in this.queue_up) { SparkleAnnouncement announcement = item.Value; @@ -192,34 +222,46 @@ namespace SparkleLib { public void OnAnnouncement (SparkleAnnouncement announcement) { SparkleHelpers.DebugInfo ("Listener", - "Got message " + announcement.Message + " from " + announcement.FolderIdentifier + " on " + this.server); + "Got message " + announcement.Message + " from " + + announcement.FolderIdentifier + " on " + Server); - if (IsRecentAnnounement(announcement) ){ + if (IsRecentAnnouncement (announcement)) { SparkleHelpers.DebugInfo ("Listener", "Ignoring previously processed message " + announcement.Message + - " from " + announcement.FolderIdentifier + " on " + this.server); + " from " + announcement.FolderIdentifier + " on " + Server); return; } SparkleHelpers.DebugInfo ("Listener", - "Processing message " + announcement.Message + " from " + announcement.FolderIdentifier + " on " + this.server); + "Processing message " + announcement.Message + " from " + + announcement.FolderIdentifier + " on " + Server); AddRecentAnnouncement (announcement); this.queue_down [announcement.FolderIdentifier] = announcement; - if (Announcement != null) - Announcement (announcement); + if (Received != null) + Received (announcement); } - private bool IsRecentAnnounement (SparkleAnnouncement announcement) + public virtual void Dispose () { - if (!HasRecentAnnouncements (announcement.FolderIdentifier)) { + this.reconnect_timer.Dispose (); + } + + + private bool IsRecentAnnouncement (SparkleAnnouncement announcement) + { + if (!this.recent_announcements + .ContainsKey (announcement.FolderIdentifier)) { + return false; } else { - foreach (SparkleAnnouncement recent_announcement in GetRecentAnnouncements (announcement.FolderIdentifier)) { + foreach (SparkleAnnouncement recent_announcement in + GetRecentAnnouncements (announcement.FolderIdentifier)) { + if (recent_announcement.Message.Equals (announcement.Message)) return true; } @@ -240,39 +282,15 @@ namespace SparkleLib { private void AddRecentAnnouncement (SparkleAnnouncement announcement) { - List recent_announcements = this.GetRecentAnnouncements (announcement.FolderIdentifier); + List recent_announcements = + GetRecentAnnouncements (announcement.FolderIdentifier); - if (!IsRecentAnnounement (announcement)) + if (!IsRecentAnnouncement (announcement)) recent_announcements.Add (announcement); if (recent_announcements.Count > this.max_recent_announcements) - recent_announcements.RemoveRange (0, (recent_announcements.Count - this.max_recent_announcements)); - } - - - private bool HasRecentAnnouncements (string folder_identifier) - { - return this.recent_announcements.ContainsKey (folder_identifier); - } - - - public virtual void Dispose () - { - this.reconnect_timer.Dispose (); - } - - - public Uri Server { - get { - return this.server; - } - } - - - public bool IsConnecting { - get { - return this.is_connecting; - } + recent_announcements.RemoveRange (0, + (recent_announcements.Count - this.max_recent_announcements)); } } } diff --git a/SparkleLib/SparkleListenerTcp.cs b/SparkleLib/SparkleListenerTcp.cs index 15268a94..1849802c 100755 --- a/SparkleLib/SparkleListenerTcp.cs +++ b/SparkleLib/SparkleListenerTcp.cs @@ -28,30 +28,31 @@ namespace SparkleLib { public class SparkleListenerTcp : SparkleListenerBase { - private Thread thread; - - // these are shared - private readonly Object mutex = new Object(); private Socket socket; - private bool connected; + private Object socket_lock = new Object (); + private Thread thread; + private bool is_connected = false; + private bool is_connecting = false; + public SparkleListenerTcp (Uri server, string folder_identifier) : base (server, folder_identifier) { - base.channels.Add (folder_identifier); - this.connected = false; } public override bool IsConnected { get { - bool result = false; + lock (this.socket_lock) + return this.is_connected; + } + } - lock (this.mutex) { - result = this.connected; - } - return result; + public override bool IsConnecting { + get { + lock (this.socket_lock) + return this.is_connecting; } } @@ -61,21 +62,29 @@ namespace SparkleLib { { SparkleHelpers.DebugInfo ("ListenerTcp", "Connecting to " + Server.Host); - base.is_connecting = true; + this.is_connecting = true; this.thread = new Thread ( new ThreadStart (delegate { try { // Connect and subscribe to the channel int port = Server.Port; - if (port < 0) port = 9999; - lock (this.mutex) { - this.socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + if (port < 0) + port = 9999; + + + lock (this.socket_lock) { + this.socket = new Socket (AddressFamily.InterNetwork, + SocketType.Stream, ProtocolType.Tcp) { + + ReceiveTimeout = 30 * 1000 + }; + this.socket.Connect (Server.Host, port); - base.is_connecting = false; - this.connected = true; + this.is_connecting = false; + this.is_connected = true; OnConnected (); @@ -85,6 +94,7 @@ namespace SparkleLib { } } + byte [] bytes = new byte [4096]; // List to the channels, this blocks the thread @@ -93,20 +103,26 @@ namespace SparkleLib { if (bytes_read > 0) { string received = Encoding.UTF8.GetString (bytes); - string line = received.Substring (0, received.IndexOf ("\n")); + string line = received.Substring (0, received.IndexOf ("\n")); + if (!line.Contains ("!")) continue; + string folder_identifier = line.Substring (0, line.IndexOf ("!")); - string message = this.CleanMessage (line.Substring (line.IndexOf ("!") + 1)); - if (!folder_identifier.Equals("debug") && - !String.IsNullOrEmpty(message)) + string message = CleanMessage (line.Substring (line.IndexOf ("!") + 1)); + + if (!folder_identifier.Equals ("debug") && + !String.IsNullOrEmpty (message)) { + OnAnnouncement (new SparkleAnnouncement (folder_identifier, message)); + } + } else { SparkleHelpers.DebugInfo ("ListenerTcp", "Error on socket"); - lock (this.mutex) { + lock (this.socket_lock) { this.socket.Close (); - this.connected = false; + this.is_connected = false; OnDisconnected (); } @@ -117,6 +133,8 @@ namespace SparkleLib { } catch (SocketException e) { SparkleHelpers.DebugInfo ("ListenerTcp", "Could not connect to " + Server + ": " + e.Message); + this.is_connected = false; + this.is_connecting = false; OnDisconnected (); } @@ -127,46 +145,44 @@ namespace SparkleLib { } - public override void AlsoListenTo (string folder_identifier) + protected override void AlsoListenTo (string folder_identifier) { - string channel = folder_identifier; + string to_send = "subscribe " + folder_identifier + "\n"; - if (!base.channels.Contains (channel)) { - base.channels.Add (channel); - - if (IsConnected) { - SparkleHelpers.DebugInfo ("ListenerTcp", "Subscribing to channel " + channel); - - string to_send = "subscribe " + folder_identifier + "\n"; - - try { - lock (this.mutex) { - this.socket.Send (Encoding.UTF8.GetBytes (to_send)); - } - - } catch (SocketException e) { - SparkleHelpers.DebugInfo ("ListenerTcp", "Could not connect to " + Server + ": " + e.Message); - OnDisconnected (); - } + try { + lock (this.socket_lock) { + this.socket.Send (Encoding.UTF8.GetBytes (to_send)); } + + } catch (SocketException e) { + SparkleHelpers.DebugInfo ("ListenerTcp", + "Could not connect to " + Server + ": " + e.Message); + + this.is_connected = false; + this.is_connecting = false; + + OnDisconnected (); } } - public override void Announce (SparkleAnnouncement announcement) + protected override void Announce (SparkleAnnouncement announcement) { string to_send = "announce " + announcement.FolderIdentifier + " " + announcement.Message + "\n"; try { - - lock (this.mutex) { + lock (this.socket_lock) this.socket.Send (Encoding.UTF8.GetBytes (to_send)); - } - } catch (SocketException e) { - SparkleHelpers.DebugInfo ("ListenerTcp", "Could not connect to " + Server + ": " + e.Message); - OnDisconnected (); + } catch (SocketException e) { + SparkleHelpers.DebugInfo ("ListenerTcp", + "Could not connect to " + Server + ": " + e.Message); + + this.is_connected = false; + this.is_connecting = false; + + OnDisconnected (); } } @@ -175,12 +191,16 @@ namespace SparkleLib { { this.thread.Abort (); this.thread.Join (); + base.Dispose (); } - private string CleanMessage(string message) + + private string CleanMessage (string message) { - return message.Trim ().Replace ("\n", "").Replace ("\0", ""); + return message.Trim () + .Replace ("\n", "") + .Replace ("\0", ""); } } } diff --git a/SparkleLib/SparkleRepoBase.cs b/SparkleLib/SparkleRepoBase.cs index 74f367af..6cf73a1e 100755 --- a/SparkleLib/SparkleRepoBase.cs +++ b/SparkleLib/SparkleRepoBase.cs @@ -57,9 +57,9 @@ namespace SparkleLib { protected bool is_buffering = false; protected bool server_online = true; - public readonly SparkleBackend Backend; public readonly string LocalPath; public readonly string Name; + public readonly Uri Url; public abstract bool AnyDifferences { get; } public abstract string Identifier { get; } @@ -92,11 +92,12 @@ namespace SparkleLib { public event ChangesDetectedEventHandler ChangesDetected; - public SparkleRepoBase (string path, SparkleBackend backend) + public SparkleRepoBase (string path) { - LocalPath = path; - Name = Path.GetFileName (LocalPath); - Backend = backend; + LocalPath = path; + Name = Path.GetFileName (LocalPath); + Url = new Uri (SparkleConfig.DefaultConfig.GetUrlForFolder (Name)); + this.poll_interval = this.short_interval; SyncStatusChanged += delegate (SyncStatus status) { @@ -298,7 +299,7 @@ namespace SparkleLib { }; // Fetch changes when there is a message in the irc channel - this.listener.Announcement += delegate (SparkleAnnouncement announcement) { + this.listener.Received += delegate (SparkleAnnouncement announcement) { string identifier = Identifier; if (announcement.FolderIdentifier.Equals (identifier) && diff --git a/SparkleShare/Mac/Makefile.am b/SparkleShare/Mac/Makefile.am index 6beab296..5091b192 100755 --- a/SparkleShare/Mac/Makefile.am +++ b/SparkleShare/Mac/Makefile.am @@ -1,4 +1,5 @@ EXTRA_DIST = \ + config \ AppDelegate.cs \ Growl.framework \ Growl.plist \ diff --git a/SparkleShare/Mac/SparkleEventLog.cs b/SparkleShare/Mac/SparkleEventLog.cs index ca9412e6..c46f53fd 100755 --- a/SparkleShare/Mac/SparkleEventLog.cs +++ b/SparkleShare/Mac/SparkleEventLog.cs @@ -46,6 +46,8 @@ namespace SparkleShare { private NSTextField size_label_value; private NSTextField history_label; private NSTextField history_label_value; + private NSButton hidden_close_button; + public SparkleEventLog (IntPtr handle) : base (handle) { } @@ -68,6 +70,19 @@ namespace SparkleShare { BackingType = NSBackingStore.Buffered; + this.hidden_close_button = new NSButton () { + Frame = new RectangleF (0, 0, 0, 0), + KeyEquivalentModifierMask = NSEventModifierMask.CommandKeyMask, + KeyEquivalent = "w" + }; + + this.hidden_close_button.Activated += delegate { + PerformClose (this); + }; + + ContentView.AddSubview (this.hidden_close_button); + + this.size_label = new NSTextField () { Alignment = NSTextAlignment.Right, BackgroundColor = NSColor.WindowBackground, @@ -237,7 +252,7 @@ namespace SparkleShare { public class SparkleEventsDelegate : NSWindowDelegate { - + public override bool WindowShouldClose (NSObject sender) { (sender as SparkleEventLog).OrderOut (this); diff --git a/SparkleShare/Mac/SparkleSetup.cs b/SparkleShare/Mac/SparkleSetup.cs index a884b072..9d890127 100755 --- a/SparkleShare/Mac/SparkleSetup.cs +++ b/SparkleShare/Mac/SparkleSetup.cs @@ -462,10 +462,9 @@ namespace SparkleShare { case PageType.Finished: { - Header = "Project succesfully added!"; - Description = "Now you can access the files from " + - "‘" + Controller.SyncingFolder + "’ in " + - "your SparkleShare folder."; + Header = "Project ‘" + Path.GetFileName (Controller.PreviousPath) + + "’ succesfully added!"; + Description = "Access the files from your SparkleShare folder."; if (warnings != null) { WarningImage = NSImage.ImageNamed ("NSCaution"); @@ -505,7 +504,7 @@ namespace SparkleShare { }; OpenFolderButton.Activated += delegate { - Program.Controller.OpenSparkleShareFolder (Controller.SyncingFolder); + Program.Controller.OpenSparkleShareFolder (Path.GetFileName (Controller.PreviousPath)); }; Buttons.Add (FinishButton); diff --git a/SparkleShare/Mac/SparkleSetupWindow.cs b/SparkleShare/Mac/SparkleSetupWindow.cs index 4aa27f42..1441071b 100755 --- a/SparkleShare/Mac/SparkleSetupWindow.cs +++ b/SparkleShare/Mac/SparkleSetupWindow.cs @@ -87,7 +87,9 @@ namespace SparkleShare { MakeKeyAndOrderFront (this); OrderFrontRegardless (); - Program.UI.UpdateDockIconVisibility (); + + if (Program.UI != null) + Program.UI.UpdateDockIconVisibility (); } @@ -146,7 +148,9 @@ namespace SparkleShare { { base.OrderOut (this); NSApplication.SharedApplication.RemoveWindowsItem (this); - Program.UI.UpdateDockIconVisibility (); + + if (Program.UI != null) + Program.UI.UpdateDockIconVisibility (); return; } diff --git a/SparkleShare/Mac/SparkleShare.csproj b/SparkleShare/Mac/SparkleShare.csproj index fbf786bc..0a62e312 100755 --- a/SparkleShare/Mac/SparkleShare.csproj +++ b/SparkleShare/Mac/SparkleShare.csproj @@ -11,7 +11,7 @@ SparkleShare SparkleShare v4.0 - 0.8.0 + 0.8.1 true diff --git a/SparkleShare/Mac/SparkleShare.sln b/SparkleShare/Mac/SparkleShare.sln index 6de6c1e6..fc841f19 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.0 + version = 0.8.1 EndGlobalSection EndGlobal diff --git a/SparkleShare/Mac/SparkleStatusIcon.cs b/SparkleShare/Mac/SparkleStatusIcon.cs index 55d45537..0d89e9b1 100755 --- a/SparkleShare/Mac/SparkleStatusIcon.cs +++ b/SparkleShare/Mac/SparkleStatusIcon.cs @@ -91,6 +91,15 @@ namespace SparkleShare { Menu.Delegate = new SparkleStatusIconMenuDelegate (); } + Controller.UpdateQuitItemEvent += delegate (bool quit_item_enabled) { + InvokeOnMainThread (delegate { + if (QuitMenuItem != null) { + QuitMenuItem.Enabled = quit_item_enabled; + StatusItem.Menu.Update (); + } + }); + }; + Controller.UpdateMenuEvent += delegate (IconState state) { InvokeOnMainThread (delegate { using (var a = new NSAutoreleasePool ()) { @@ -137,6 +146,8 @@ namespace SparkleShare { break; } + + StatusItem.Menu.Update (); } }); }; @@ -310,8 +321,8 @@ namespace SparkleShare { QuitMenuItem = new NSMenuItem () { - Title = "Quit", - Enabled = true + Title = "Quit", + Enabled = Controller.QuitItemEnabled }; QuitMenuItem.Activated += delegate { diff --git a/SparkleShare/Mac/SparkleUI.cs b/SparkleShare/Mac/SparkleUI.cs index ab4163d7..43e9f62f 100755 --- a/SparkleShare/Mac/SparkleUI.cs +++ b/SparkleShare/Mac/SparkleUI.cs @@ -69,6 +69,8 @@ namespace SparkleShare { if (Program.Controller.FirstRun) { Setup = new SparkleSetup (); Setup.Controller.ShowSetupPage (); + + UpdateDockIconVisibility (); } } } diff --git a/SparkleShare/SparkleBubblesController.cs b/SparkleShare/SparkleBubblesController.cs index 3fe424e4..1dcf0a1c 100755 --- a/SparkleShare/SparkleBubblesController.cs +++ b/SparkleShare/SparkleBubblesController.cs @@ -29,7 +29,7 @@ namespace SparkleShare { public SparkleBubblesController () { Program.Controller.ConflictNotificationRaised += delegate { - ShowBubble ("Ouch! Mid-air collision!", + ShowBubble ("Conflict detected.", "Don't worry, SparkleShare made a copy of each conflicting file.", null); }; diff --git a/SparkleShare/SparkleControllerBase.cs b/SparkleShare/SparkleControllerBase.cs index 9c160e63..9457b579 100644 --- a/SparkleShare/SparkleControllerBase.cs +++ b/SparkleShare/SparkleControllerBase.cs @@ -262,8 +262,7 @@ namespace SparkleShare { public abstract string EventLogHTML { get; } public abstract string DayEntryHTML { get; } public abstract string EventEntryHTML { get; } - - + public string GetHTMLLog (List change_sets) { List activity_days = new List (); @@ -456,6 +455,7 @@ namespace SparkleShare { .Replace ("", change_set_avatar) .Replace ("", timestamp) .Replace ("", change_set.Folder) + .Replace ("", change_set.Url.ToString ()) .Replace ("", change_set.Revision) .Replace ("", AssignColor (change_set.Folder)) .Replace ("", comments); @@ -570,16 +570,23 @@ namespace SparkleShare { // Adds a repository to the list of repositories private void AddRepository (string folder_path) { - if (folder_path.Equals (SparkleConfig.DefaultConfig.TmpPath)) - return; + SparkleRepoBase repo = null; + string folder_name = Path.GetFileName (folder_path); + string backend = SparkleConfig.DefaultConfig.GetBackendForFolder (folder_name); - string folder_name = Path.GetFileName (folder_path); - string backend = SparkleConfig.DefaultConfig.GetBackendForFolder (folder_name); + try { + repo = (SparkleRepoBase) Activator.CreateInstance ( + Type.GetType ("SparkleLib.SparkleRepo" + backend + ", SparkleLib"), + folder_path + ); + + } catch { + SparkleHelpers.DebugInfo ("Controller", + "Failed to load \"" + backend + "\" backend for \"" + folder_name + "\""); - if (backend == null) return; - - SparkleRepoBase repo = new SparkleRepoGit (folder_path, SparkleBackend.DefaultBackend); + } + repo.NewChangeSet += delegate (SparkleChangeSet change_set) { @@ -624,6 +631,7 @@ namespace SparkleShare { UpdateState (); }; + Repositories.Add (repo); repo.Initialize (); } @@ -770,6 +778,7 @@ namespace SparkleShare { process.StartInfo.UseShellExecute = false; process.StartInfo.FileName = "ssh-add"; process.StartInfo.Arguments = "\"" + key_file_path + "\""; + process.StartInfo.CreateNoWindow = true; process.Start (); process.WaitForExit (); @@ -817,7 +826,7 @@ namespace SparkleShare { string key_file_path = Path.Combine (keys_path, key_file_name); if (File.Exists (key_file_path)) { - SparkleHelpers.DebugInfo ("Config", "Key already exists ('" + key_file_name + "'), " + + SparkleHelpers.DebugInfo ("Auth", "Key already exists ('" + key_file_name + "'), " + "leaving it untouched"); return; } @@ -830,10 +839,11 @@ namespace SparkleShare { EnableRaisingEvents = true }; - process.StartInfo.WorkingDirectory = keys_path; - process.StartInfo.UseShellExecute = false; + process.StartInfo.WorkingDirectory = keys_path; + process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; - process.StartInfo.FileName = "ssh-keygen"; + process.StartInfo.FileName = "ssh-keygen"; + process.StartInfo.CreateNoWindow = true; // -t is the crypto type // -P is the password (none) @@ -843,8 +853,8 @@ namespace SparkleShare { process.Start (); process.WaitForExit (); - SparkleHelpers.DebugInfo ("Config", "Created private key '" + key_file_name + "'"); - SparkleHelpers.DebugInfo ("Config", "Created public key '" + key_file_name + ".pub'"); + SparkleHelpers.DebugInfo ("Auth", "Created private key '" + key_file_name + "'"); + SparkleHelpers.DebugInfo ("Auth", "Created public key '" + key_file_name + ".pub'"); // Add some restrictions to what the key can // do when uploaded to the server @@ -877,7 +887,7 @@ namespace SparkleShare { if (!Directory.Exists (avatar_path)) { Directory.CreateDirectory (avatar_path); - SparkleHelpers.DebugInfo ("Config", "Created '" + avatar_path + "'"); + SparkleHelpers.DebugInfo ("Avatar", "Created '" + avatar_path + "'"); } foreach (string raw_email in emails) { @@ -923,11 +933,11 @@ namespace SparkleShare { lock (this.avatar_lock) File.WriteAllBytes (avatar_file_path, buffer); - SparkleHelpers.DebugInfo ("Controller", "Fetched gravatar for " + email); + SparkleHelpers.DebugInfo ("Avatar", "Fetched gravatar for " + email); } } catch (WebException e) { - SparkleHelpers.DebugInfo ("Controller", "Failed fetching gravatar for " + email); + SparkleHelpers.DebugInfo ("Avatar", "Failed fetching gravatar for " + email); // Stop downloading further avatars if we have no internet access if (e.Status == WebExceptionStatus.Timeout){ @@ -971,7 +981,7 @@ namespace SparkleShare { public void FetchFolder (string server, string remote_folder) { - server = server.Trim (); + server = server.Trim (); remote_folder = remote_folder.Trim (); string tmp_path = SparkleConfig.DefaultConfig.TmpPath; @@ -980,26 +990,42 @@ namespace SparkleShare { File.SetAttributes (tmp_path, File.GetAttributes (tmp_path) | FileAttributes.Hidden); } + // Strip the '.git' from the name string canonical_name = Path.GetFileNameWithoutExtension (remote_folder); string tmp_folder = Path.Combine (tmp_path, canonical_name); + string backend = Path.GetExtension (remote_folder); - string backend = null; + if (!string.IsNullOrEmpty (backend)) { + backend = backend.Substring (1); -/* if (remote_folder.EndsWith (".hg")) { - remote_folder = remote_folder.Substring (0, (remote_folder.Length - 3)); - fetcher = new SparkleFetcherHg (server, remote_folder, tmp_folder); - backend = "Hg"; + char [] letters = backend.ToCharArray (); + letters [0] = char.ToUpper (letters [0]); + backend = new string (letters); - } else if (remote_folder.EndsWith (".scp")) { - remote_folder = remote_folder.Substring (0, (remote_folder.Length - 4)); - fetcher = new SparkleFetcherScp (server, remote_folder, tmp_folder); - backend = "Scp"; - - } else {*/ - this.fetcher = new SparkleFetcherGit (server, remote_folder, tmp_folder); + } else { backend = "Git"; - //} + } + + + try { + this.fetcher = (SparkleFetcherBase) Activator.CreateInstance ( + Type.GetType ("SparkleLib.SparkleFetcher" + backend + ", SparkleLib"), + server, + remote_folder, + tmp_folder + ); + + } catch { + SparkleHelpers.DebugInfo ("Controller", + "Failed to load \"" + backend + "\" backend for \"" + canonical_name + "\""); + + if (FolderFetchError != null) + FolderFetchError (Path.Combine (server, remote_folder)); + + return; + } + bool target_folder_exists = Directory.Exists ( Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, canonical_name)); @@ -1046,7 +1072,6 @@ namespace SparkleShare { } }; - this.fetcher.Failed += delegate { if (FolderFetchError != null) FolderFetchError (this.fetcher.RemoteUrl); @@ -1057,7 +1082,6 @@ namespace SparkleShare { Directory.Delete (tmp_path, true); }; - this.fetcher.ProgressChanged += delegate (double percentage) { if (FolderFetching != null) FolderFetching (percentage); diff --git a/SparkleShare/SparkleEventLog.cs b/SparkleShare/SparkleEventLog.cs index 5886a5ede..b9f39580 100755 --- a/SparkleShare/SparkleEventLog.cs +++ b/SparkleShare/SparkleEventLog.cs @@ -174,8 +174,9 @@ namespace SparkleShare { TreeIter iter; this.combo_box.GetActiveIter (out iter); string selection = (string) this.combo_box.Model.GetValue (iter, 0); + TreePath path = this.combo_box.Model.GetPath (iter); - if (selection.Equals (_("All Folders"))) + if (path.Indices [0] == 0) Controller.SelectedFolder = null; else Controller.SelectedFolder = selection; @@ -224,7 +225,7 @@ namespace SparkleShare { Application.Invoke (delegate { this.spinner.Stop (); - this.web_view.LoadString (html, null, null, "file:///"); + this.web_view.LoadString (html, null, null, "file://"); this.content_wrapper.Remove (this.content_wrapper.Child); this.content_wrapper.Add (this.scrolled_window); this.content_wrapper.ShowAll (); diff --git a/SparkleShare/SparkleEventLogController.cs b/SparkleShare/SparkleEventLogController.cs index 457733ec..c4243eac 100755 --- a/SparkleShare/SparkleEventLogController.cs +++ b/SparkleShare/SparkleEventLogController.cs @@ -66,8 +66,8 @@ namespace SparkleShare { // A short delay is less annoying than // a flashing window - if (watch.ElapsedMilliseconds < 500) - Thread.Sleep (500 - (int) watch.ElapsedMilliseconds); + if (watch.ElapsedMilliseconds < 750) + Thread.Sleep (750 - (int) watch.ElapsedMilliseconds); if (UpdateContentEvent != null) UpdateContentEvent (html); diff --git a/SparkleShare/SparkleSetup.cs b/SparkleShare/SparkleSetup.cs index 1a314f88..9eb6d69e 100755 --- a/SparkleShare/SparkleSetup.cs +++ b/SparkleShare/SparkleSetup.cs @@ -441,20 +441,21 @@ namespace SparkleShare { UrgencyHint = true; if (!HasToplevelFocus) { - string title = String.Format (_("‘{0}’ has been successfully added"), Controller.SyncingFolder); + string title = _("Project successfully added!"); string subtext = ""; SparkleUI.Bubbles.Controller.ShowBubble (title, subtext, null); } - Header = _("Project successfully added!"); + Header = _("Project ‘" + System.IO.Path.GetFileName (Controller.PreviousPath) + + "’ successfully added!"); Description = _("Access the files from your SparkleShare folder."); // A button that opens the synced folder Button open_folder_button = new Button (_("Open Folder")); open_folder_button.Clicked += delegate { - Program.Controller.OpenSparkleShareFolder (Controller.SyncingFolder); + Program.Controller.OpenSparkleShareFolder (System.IO.Path.GetFileName (Controller.PreviousPath)); }; Button finish_button = new Button (_("Finish")); diff --git a/SparkleShare/SparkleStatusIcon.cs b/SparkleShare/SparkleStatusIcon.cs index 86d36f84..a678b419 100644 --- a/SparkleShare/SparkleStatusIcon.cs +++ b/SparkleShare/SparkleStatusIcon.cs @@ -33,11 +33,13 @@ namespace SparkleShare { public SparkleStatusIconController Controller = new SparkleStatusIconController (); + // TODO: fix case private Timer Animation; private Gdk.Pixbuf [] AnimationFrames; private int FrameNumber; private string StateText; private Menu Menu; + private MenuItem quit_item; #if HAVE_APP_INDICATOR private ApplicationIndicator indicator; @@ -78,58 +80,70 @@ namespace SparkleShare { CreateMenu (); + + Controller.UpdateQuitItemEvent += delegate (bool quit_item_enabled) { + Application.Invoke (delegate { + if (this.quit_item != null) { + this.quit_item.Sensitive = quit_item_enabled; + Menu.ShowAll (); + } + }); + }; + Controller.UpdateMenuEvent += delegate (IconState state) { Application.Invoke (delegate { - switch (state) { - case IconState.Idle: + switch (state) { + case IconState.Idle: - Animation.Stop (); + Animation.Stop (); - if (Controller.Folders.Length == 0) - StateText = _("Welcome to SparkleShare!"); - else - StateText = _("Up to date") + Controller.FolderSize; + if (Controller.Folders.Length == 0) + StateText = _("Welcome to SparkleShare!"); + else + StateText = _("Up to date") + Controller.FolderSize; - #if HAVE_APP_INDICATOR - this.indicator.IconName = "process-syncing-sparkleshare-i"; - #else - this.status_icon.Pixbuf = AnimationFrames [0]; - #endif + #if HAVE_APP_INDICATOR + this.indicator.IconName = "process-syncing-sparkleshare-i"; + #else + this.status_icon.Pixbuf = AnimationFrames [0]; + #endif - UpdateStateText (); - CreateMenu (); + UpdateStateText (); + CreateMenu (); - break; + break; - case IconState.Syncing: + case IconState.Syncing: - StateText = _("Syncing… ") + - Controller.ProgressPercentage + "% " + - Controller.ProgressSpeed; + StateText = _("Syncing… ") + + Controller.ProgressPercentage + "% " + + Controller.ProgressSpeed; - UpdateStateText (); + UpdateStateText (); - if (!Animation.Enabled) - Animation.Start (); + if (!Animation.Enabled) + Animation.Start (); - break; + break; - case IconState.Error: + case IconState.Error: - Animation.Stop (); + Animation.Stop (); - StateText = _("Not everything is synced"); - UpdateStateText (); - CreateMenu (); - - #if HAVE_APP_INDICATOR - this.indicator.IconName = "sparkleshare-syncing-error"; - #else - this.status_icon.Pixbuf = SparkleUIHelpers.GetIcon ("sparkleshare-syncing-error", 24); - #endif + StateText = _("Not everything is synced"); + UpdateStateText (); + CreateMenu (); - break; - } + #if HAVE_APP_INDICATOR + this.indicator.IconName = "sparkleshare-syncing-error"; + #else + this.status_icon.Pixbuf = SparkleUIHelpers.GetIcon ("sparkleshare-syncing-error", 24); + #endif + + break; + } + + Menu.ShowAll (); }); }; } @@ -311,13 +325,15 @@ namespace SparkleShare { Menu.Add (new SeparatorMenuItem ()); // A menu item that quits the application - MenuItem quit_item = new MenuItem (_("Quit")); + this.quit_item = new MenuItem (_("Quit")) { + Sensitive = Controller.QuitItemEnabled + }; - quit_item.Activated += delegate { + this.quit_item.Activated += delegate { Program.Controller.Quit (); }; - Menu.Add (quit_item); + Menu.Add (this.quit_item); Menu.ShowAll (); #if HAVE_APP_INDICATOR diff --git a/SparkleShare/SparkleStatusIconController.cs b/SparkleShare/SparkleStatusIconController.cs index e2a43999..aa67810e 100755 --- a/SparkleShare/SparkleStatusIconController.cs +++ b/SparkleShare/SparkleStatusIconController.cs @@ -38,6 +38,9 @@ namespace SparkleShare { public event UpdateMenuEventHandler UpdateMenuEvent; public delegate void UpdateMenuEventHandler (IconState state); + public event UpdateQuitItemEventHandler UpdateQuitItemEvent; + public delegate void UpdateQuitItemEventHandler (bool quit_item_enabled); + public IconState CurrentState = IconState.Idle; public string [] Folders { @@ -76,6 +79,14 @@ namespace SparkleShare { } } + public bool QuitItemEnabled { + get { + return (CurrentState != IconState.Syncing && + CurrentState != IconState.SyncingDown && + CurrentState != IconState.SyncingUp); + } + } + public SparkleStatusIconController () { @@ -89,6 +100,9 @@ namespace SparkleShare { if (CurrentState != IconState.Error) CurrentState = IconState.Idle; + if (UpdateQuitItemEvent != null) + UpdateQuitItemEvent (QuitItemEnabled); + if (UpdateMenuEvent != null) UpdateMenuEvent (CurrentState); }; @@ -97,6 +111,9 @@ namespace SparkleShare { Program.Controller.OnSyncing += delegate { CurrentState = IconState.Syncing; + if (UpdateQuitItemEvent != null) + UpdateQuitItemEvent (QuitItemEnabled); + if (UpdateMenuEvent != null) UpdateMenuEvent (IconState.Syncing); }; @@ -105,6 +122,9 @@ namespace SparkleShare { Program.Controller.OnError += delegate { CurrentState = IconState.Error; + if (UpdateQuitItemEvent != null) + UpdateQuitItemEvent (QuitItemEnabled); + if (UpdateMenuEvent != null) UpdateMenuEvent (IconState.Error); }; diff --git a/SparkleShare/sparkleshare.in b/SparkleShare/sparkleshare.in index 3e71f404..619f98b5 100755 --- a/SparkleShare/sparkleshare.in +++ b/SparkleShare/sparkleshare.in @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash if [[ $UID -eq 0 ]]; then echo "Cannot run as root. Things would go utterly wrong." diff --git a/configure.ac b/configure.ac index 2c4cf28d..c88fdda9 100755 --- a/configure.ac +++ b/configure.ac @@ -1,13 +1,13 @@ dnl Process this file with autoconf to produce a configure script. m4_define([sparkleshare_version], - [0.8.0]) + [0.8.1]) m4_define([sparkleshare_asm_version], - [0.8.0]) + [0.8.1]) AC_PREREQ([2.54]) AC_INIT([SparkleShare], sparkleshare_version) -AM_INIT_AUTOMAKE([1.11 dist-bzip2 dist-zip foreign tar-ustar]) +AM_INIT_AUTOMAKE([1.11 dist-bzip2 dist-zip foreign tar-pax]) AM_MAINTAINER_MODE dnl Export Version Info diff --git a/data/html/event-entry.html b/data/html/event-entry.html index b9d4bdaf..e5189fb2 100755 --- a/data/html/event-entry.html +++ b/data/html/event-entry.html @@ -1,6 +1,6 @@
-
+
diff --git a/data/html/event-log.html b/data/html/event-log.html index bb1bc03d..50f0cdc9 100755 --- a/data/html/event-log.html +++ b/data/html/event-log.html @@ -88,23 +88,23 @@