From 9516f53b7039981199dc322800184e3d37b90044 Mon Sep 17 00:00:00 2001 From: Hylke Bons Date: Sat, 16 Oct 2010 23:48:50 +0100 Subject: [PATCH] Restructure to be more MVC like --- SparkleLib/Defines.cs.in | 1 + SparkleLib/SparkleEvents.cs | 6 +- SparkleLib/SparkleRepo.cs | 2 +- SparkleShare/Makefile.am | 1 + SparkleShare/SparkleController.cs | 625 ++++++++++++++++++++++++++++++ SparkleShare/SparkleIntro.cs | 4 +- SparkleShare/SparkleLog.cs | 10 +- SparkleShare/SparkleShare.cs | 42 +- SparkleShare/SparkleStatusIcon.cs | 464 +++++++++------------- SparkleShare/SparkleUI.cs | 518 +++---------------------- 10 files changed, 877 insertions(+), 796 deletions(-) create mode 100644 SparkleShare/SparkleController.cs diff --git a/SparkleLib/Defines.cs.in b/SparkleLib/Defines.cs.in index 29905e12..f5beeba7 100644 --- a/SparkleLib/Defines.cs.in +++ b/SparkleLib/Defines.cs.in @@ -24,6 +24,7 @@ namespace SparkleLib { public const string LOCALE_DIR = "@prefix@/share/locale"; public const string GETTEXT_PACKAGE = "@GETTEXT_PACKAGE@"; public const string PREFIX = "@prefix@"; + public const string OPEN_COMMAND = "xdg-open"; } diff --git a/SparkleLib/SparkleEvents.cs b/SparkleLib/SparkleEvents.cs index abf4aee5..e469b79c 100644 --- a/SparkleLib/SparkleEvents.cs +++ b/SparkleLib/SparkleEvents.cs @@ -42,15 +42,15 @@ namespace SparkleLib { public string Author; public string Email; public string Message; - public string RepositoryName; + public string RepositoryPath; - public NewCommitArgs (string author, string email, string message, string repository_name) + public NewCommitArgs (string author, string email, string message, string repository_path) { Author = author; Email = email; Message = message; - RepositoryName = repository_name; + RepositoryPath = repository_path; } diff --git a/SparkleLib/SparkleRepo.cs b/SparkleLib/SparkleRepo.cs index 8f033aed..bdfc88a3 100644 --- a/SparkleLib/SparkleRepo.cs +++ b/SparkleLib/SparkleRepo.cs @@ -789,7 +789,7 @@ namespace SparkleLib { Commit commit = Head.CurrentCommit; NewCommitArgs new_commit_args = new NewCommitArgs (commit.Author.Name, commit.Author.EmailAddress, - commit.Message, Name); + commit.Message, LocalPath); if (NewCommit != null) NewCommit (this, new_commit_args); diff --git a/SparkleShare/Makefile.am b/SparkleShare/Makefile.am index 7dbf791a..caa77a1b 100644 --- a/SparkleShare/Makefile.am +++ b/SparkleShare/Makefile.am @@ -9,6 +9,7 @@ LINK = $(REF_SPARKLESHARE) SOURCES = \ SparkleBubble.cs \ + SparkleController.cs \ SparkleEntry.cs \ SparkleInfobar.cs \ SparkleIntro.cs \ diff --git a/SparkleShare/SparkleController.cs b/SparkleShare/SparkleController.cs new file mode 100644 index 00000000..9fa10aee --- /dev/null +++ b/SparkleShare/SparkleController.cs @@ -0,0 +1,625 @@ +// SparkleShare, an instant update workflow to Git. +// 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 Mono.Unix; +using Mono.Unix.Native; +using SparkleLib; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; + +namespace SparkleShare { + + public class SparkleController { + + public List Repositories; + public string FolderSize; + + + public event RepositoryListChangedEventHandler RepositoryListChanged; + public delegate void RepositoryListChangedEventHandler (); + + public event FolderSizeChangedEventHandler FolderSizeChanged; + public delegate void FolderSizeChangedEventHandler (string folder_size); + + public event OnIdleEventHandler OnIdle; + public delegate void OnIdleEventHandler (); + + public event OnSyncingEventHandler OnSyncing; + public delegate void OnSyncingEventHandler (); + + public event OnErrorEventHandler OnError; + public delegate void OnErrorEventHandler (); + + public event OnFirstRunEventHandler OnFirstRun; + public delegate void OnFirstRunEventHandler (); + + public event OnInvitationEventHandler OnInvitation; + public delegate void OnInvitationEventHandler (string invitation_file_path); + + public event ConflictNotificationRaisedEventHandler ConflictNotificationRaised; + public delegate void ConflictNotificationRaisedEventHandler (); + + public event NotificationRaisedEventHandler NotificationRaised; + public delegate void NotificationRaisedEventHandler (string author, string email, string message, + string repository_path); + + + public SparkleController () + { + + SetProcessName ("sparkleshare"); + + InstallLauncher (); + EnableSystemAutostart (); + + // Create the SparkleShare folder and add it to the bookmarks + if (CreateSparkleShareFolder ()) + AddToBookmarks (); + + FolderSize = GetFolderSize (); + + // Watch the SparkleShare folder + FileSystemWatcher watcher = new FileSystemWatcher (SparklePaths.SparklePath) { + IncludeSubdirectories = false, + EnableRaisingEvents = true, + Filter = "*" + }; + + // Remove the repository when a delete event occurs + watcher.Deleted += delegate (object o, FileSystemEventArgs args) { + + RemoveRepository (args.FullPath); + + }; + + // Add the repository when a create event occurs + watcher.Created += delegate (object o, FileSystemEventArgs args) { + + // Handle invitations when the user saves an + // invitation into the SparkleShare folder + if (args.Name.EndsWith (".invitation")) { + + if (OnInvitation != null) + OnInvitation (args.FullPath); + + } else if (Directory.Exists (Path.Combine (args.FullPath, ".git"))) { + + AddRepository (args.FullPath); + + } + + }; + + + CreateConfigurationFolders (); + + string global_config_file_path = SparkleHelpers.CombineMore (SparklePaths.SparkleConfigPath, "config"); + + // Show the introduction screen if SparkleShare isn't configured + if (!File.Exists (global_config_file_path)) { + + if (OnFirstRun != null) + OnFirstRun (); + + } else { + + SparkleShare.UserName = SparkleShare.GetUserName (); + SparkleShare.UserEmail = SparkleShare.GetUserEmail (); + + SparkleShare.AddKey (); + + } + + Thread thread = new Thread ( + new ThreadStart (PopulateRepositories) + ); + + thread.Start (); + + } + + + // Creates a folder in the user's home folder to store configuration + private void CreateConfigurationFolders () + { + + if (!Directory.Exists (SparklePaths.SparkleTmpPath)) + Directory.CreateDirectory (SparklePaths.SparkleTmpPath); + + string config_path = SparklePaths.SparkleConfigPath; + string local_icon_path = SparklePaths.SparkleLocalIconPath; + + if (!Directory.Exists (config_path)) { + + // Create a folder to store settings + Directory.CreateDirectory (config_path); + SparkleHelpers.DebugInfo ("Config", "Created '" + config_path + "'"); + + // Create a folder to store the avatars + Directory.CreateDirectory (local_icon_path); + SparkleHelpers.DebugInfo ("Config", "Created '" + local_icon_path + "'"); + + string notify_setting_file = SparkleHelpers.CombineMore (config_path, "sparkleshare.notify"); + + // Enable notifications by default + if (!File.Exists (notify_setting_file)) + File.Create (notify_setting_file); + + } + + } + + + // Creates a .desktop entry in autostart folder to + // start SparkleShare automatically at login + private void EnableSystemAutostart () + { + + string autostart_path = SparkleHelpers.CombineMore (SparklePaths.HomePath, ".config", "autostart"); + string desktopfile_path = SparkleHelpers.CombineMore (autostart_path, "sparkleshare.desktop"); + + if (!File.Exists (desktopfile_path)) { + + if (!Directory.Exists (autostart_path)) + Directory.CreateDirectory (autostart_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 (); + + // Give the launcher the right permissions so it can be launched by the user + Syscall.chmod (desktopfile_path, FilePermissions.S_IRWXU); + + SparkleHelpers.DebugInfo ("Config", "Created '" + desktopfile_path + "'"); + + } + + } + + + // Installs a launcher so the user can launch SparkleShare + // from the Internet category if needed + private void InstallLauncher () + { + + string apps_path = SparkleHelpers.CombineMore (SparklePaths.HomePath, ".local", "share", "applications"); + string desktopfile_path = SparkleHelpers.CombineMore (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 + Syscall.chmod (desktopfile_path, FilePermissions.S_IRWXU); + + SparkleHelpers.DebugInfo ("Config", "Created '" + desktopfile_path + "'"); + + } + + } + + + // Adds the SparkleShare folder to the user's + // list of bookmarked places + private void AddToBookmarks () + { + + string bookmarks_file_path = Path.Combine (SparklePaths.HomePath, ".gtk-bookmarks"); + string sparkleshare_bookmark = "file://" + SparklePaths.SparklePath + " SparkleShare"; + + if (File.Exists (bookmarks_file_path)) { + + StreamReader reader = new StreamReader (bookmarks_file_path); + string bookmarks = reader.ReadToEnd (); + reader.Close (); + + if (!bookmarks.Contains (sparkleshare_bookmark)) { + + TextWriter writer = File.AppendText (bookmarks_file_path); + writer.WriteLine ("file://" + SparklePaths.SparklePath + " SparkleShare"); + writer.Close (); + + } + + } else { + + StreamWriter writer = new StreamWriter (bookmarks_file_path); + writer.WriteLine ("file://" + SparklePaths.SparklePath + " SparkleShare"); + writer.Close (); + + } + + } + + + // Creates the SparkleShare folder in the user's home folder + private bool CreateSparkleShareFolder () + { + + if (!Directory.Exists (SparklePaths.SparklePath)) { + + Directory.CreateDirectory (SparklePaths.SparklePath); + SparkleHelpers.DebugInfo ("Config", "Created '" + SparklePaths.SparklePath + "'"); + + string icon_file_path = SparkleHelpers.CombineMore (Defines.PREFIX, "share", "icons", "hicolor", + "48x48", "apps", "folder-sparkleshare.png"); + + string gvfs_command_path = SparkleHelpers.CombineMore (Path.VolumeSeparatorChar.ToString (), + "usr", "bin", "gvfs-set-attribute"); + + // Add a special icon to the SparkleShare folder + if (File.Exists (gvfs_command_path)) { + + Process process = new Process (); + + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.UseShellExecute = false; + + process.StartInfo.FileName = "gvfs-set-attribute"; + process.StartInfo.Arguments = SparklePaths.SparklePath + " metadata::custom-icon " + + "file://" + icon_file_path; + process.Start (); + + } + + return true; + + } + + return false; + + } + + + // Fires events for the current syncing state + private void UpdateState () + { + + foreach (SparkleRepo repo in Repositories) { + + if (repo.IsSyncing || repo.IsBuffering) { + + if (OnSyncing != null) + OnSyncing (); + + return; + + } else if (repo.HasUnsyncedChanges) { + + if (OnError != null) + OnError (); + + return; + + } + + } + + + if (OnIdle != null) + OnIdle (); + + + FolderSize = GetFolderSize (); + + if (FolderSizeChanged != null) + FolderSizeChanged (FolderSize); + + } + + + // Adds a repository to the list of repositories + private void AddRepository (string folder_path) + { + + // Check if the folder is a Git repository + if (!Directory.Exists (SparkleHelpers.CombineMore (folder_path, ".git"))) + return; + + SparkleRepo repo = new SparkleRepo (folder_path); + + repo.NewCommit += delegate (object o, NewCommitArgs args) { + if (NotificationsEnabled && NotificationRaised != null) + NotificationRaised (args.Author, args.Email, args.Message, args.RepositoryPath); + }; + + repo.FetchingStarted += delegate { + UpdateState (); + }; + + repo.FetchingFinished += delegate { + UpdateState (); + }; + + repo.FetchingFailed += delegate { + UpdateState (); + }; + + repo.ChangesDetected += delegate { + UpdateState (); + }; + + repo.PushingStarted += delegate { + UpdateState (); + }; + + repo.PushingFinished += delegate { + UpdateState (); + }; + + repo.CommitEndedUpEmpty += delegate { + UpdateState (); + }; + + repo.PushingFailed += delegate { + UpdateState (); + }; + + repo.ConflictDetected += delegate { + if (ConflictNotificationRaised != null) + ConflictNotificationRaised (); + }; + + Repositories.Add (repo); + + + if (RepositoryListChanged != null) + RepositoryListChanged (); + + } + + + // Removes a repository from the list of repositories and + // updates the statusicon menu + private void RemoveRepository (string folder_path) + { + + string repo_name = Path.GetFileName (folder_path); + + for (int i = 0; i < Repositories.Count; i++) { + + SparkleRepo repo = Repositories [i]; + + if (repo.Name.Equals (repo_name)) { + + Repositories.Remove (repo); + repo.Dispose (); + repo = null; + break; + + } + + } + + + if (RepositoryListChanged != null) + RepositoryListChanged (); + + } + + + // Updates the list of repositories with all the + // folders in the SparkleShare folder + private void PopulateRepositories () + { + + Repositories = new List (); + + foreach (string folder_path in Directory.GetDirectories (SparklePaths.SparklePath)) + AddRepository (folder_path); + + if (RepositoryListChanged != null) + RepositoryListChanged (); + + } + + + public bool NotificationsEnabled { + + get { + + string notify_setting_file_path = SparkleHelpers.CombineMore (SparklePaths.SparkleConfigPath, + "sparkleshare.notify"); + + return File.Exists (notify_setting_file_path); + + } + + } + + + public void ToggleNotifications () { + + string notify_setting_file_path = SparkleHelpers.CombineMore (SparklePaths.SparkleConfigPath, + "sparkleshare.notify"); + + if (File.Exists (notify_setting_file_path)) + File.Delete (notify_setting_file_path); + else + File.Create (notify_setting_file_path); + + } + + + private string GetFolderSize () + { + + double folder_size = CalculateFolderSize (new DirectoryInfo (SparklePaths.SparklePath)); + return FormatFolderSize (folder_size); + + } + + + // Recursively gets a folder's size in bytes + private double CalculateFolderSize (DirectoryInfo parent) + { + + if (!Directory.Exists (parent.ToString ())) + return 0; + + double size = 0; + + // Ignore the temporary 'rebase-apply' and '.tmp' directories. This prevents potential + // crashes when files are being queried whilst the files have already been deleted. + if (parent.Name.Equals ("rebase-apply") || + parent.Name.Equals (".tmp")) + return 0; + + foreach (FileInfo file in parent.GetFiles()) { + + if (!file.Exists) + return 0; + + size += file.Length; + + } + + foreach (DirectoryInfo directory in parent.GetDirectories()) + size += CalculateFolderSize (directory); + + return size; + + } + + + // Format a file size nicely with small caps. + // Example: 1048576 becomes "1 ᴍʙ" + private string FormatFolderSize (double byte_count) + { + + if (byte_count >= 1099511627776) + + return String.Format ("{0:##.##} ᴛʙ", Math.Round (byte_count / 1099511627776, 1)); + + 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)); + + else if (byte_count >= 1024) + + return String.Format ("{0:##.##} ᴋʙ", Math.Round (byte_count / 1024, 1)); + + else + + return byte_count.ToString () + " bytes"; + + } + + + public void OpenSparkleShareFolder () + { + + Process process = new Process (); + process.StartInfo.Arguments = SparklePaths.SparklePath; + + string open_command_path = SparkleHelpers.CombineMore (Path.VolumeSeparatorChar.ToString (), + "usr", "bin"); + + if (File.Exists (Path.Combine (open_command_path, "xdg-open"))) { + + process.StartInfo.FileName = "xdg-open"; + + } else if (File.Exists (Path.Combine (open_command_path, "gnome-open"))) { + + process.StartInfo.FileName = "gnome-open"; + + } else if (File.Exists (Path.Combine (open_command_path, "open"))) { + + process.StartInfo.FileName = "open"; + + } else { + + return; + + } + + process.Start (); + + } + + + // Sets the unix process name to 'sparkleshare' instead of 'mono' + private void SetProcessName (string name) + { + + try { + + if (prctl (15, Encoding.ASCII.GetBytes (name + "\0"), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero) != 0) { + + throw new ApplicationException ("Error setting process name: " + + Mono.Unix.Native.Stdlib.GetLastError ()); + + } + + } catch (EntryPointNotFoundException) { + + Console.WriteLine ("SetProcessName: Entry point not found"); + + } + + } + + + // Strange magic needed by SetProcessName + [DllImport ("libc")] + private static extern int prctl (int option, byte [] arg2, IntPtr arg3, IntPtr arg4, IntPtr arg5); + + // Quits the program + public void Quit () + { + + foreach (SparkleRepo repo in Repositories) + repo.Dispose (); + + // Remove the process ID file + File.Delete (SparkleHelpers.CombineMore (SparklePaths.SparkleTmpPath, "sparkleshare.pid")); + + Environment.Exit (0); + + } + + } + +} diff --git a/SparkleShare/SparkleIntro.cs b/SparkleShare/SparkleIntro.cs index 75f94dcc..62276c4a 100644 --- a/SparkleShare/SparkleIntro.cs +++ b/SparkleShare/SparkleIntro.cs @@ -270,7 +270,7 @@ namespace SparkleShare { FolderEntry.Changed += CheckServerForm; - Label folder_label = new Label ("" + _("Folder Name:") + "") { + Label folder_label = new Label ("" + _("Remote Folder Name:") + "") { UseMarkup = true, Xalign = 1 }; @@ -577,7 +577,7 @@ namespace SparkleShare { if (SparkleUI.StatusIcon == null) SparkleUI.StatusIcon = new SparkleStatusIcon (); else - SparkleUI.StatusIcon.CreateMenu (); + SparkleUI.StatusIcon.UpdateMenu (); Destroy (); diff --git a/SparkleShare/SparkleLog.cs b/SparkleShare/SparkleLog.cs index 986b0980..0a46a033 100644 --- a/SparkleShare/SparkleLog.cs +++ b/SparkleShare/SparkleLog.cs @@ -114,7 +114,7 @@ namespace SparkleShare { open_folder_button.Clicked += delegate (object o, EventArgs args) { Process process = new Process (); - process.StartInfo.FileName = "xdg-open"; + process.StartInfo.FileName = Defines.OPEN_COMMAND; process.StartInfo.Arguments = LocalPath.Replace (" ", "\\ "); // Escape space-characters process.Start (); @@ -143,7 +143,7 @@ namespace SparkleShare { public void Close () { - foreach (SparkleRepo repo in SparkleUI.Repositories) { + foreach (SparkleRepo repo in SparkleShare.Controller.Repositories) { if (repo.LocalPath.Equals (LocalPath)) { @@ -184,7 +184,7 @@ namespace SparkleShare { List commits = new List (); - foreach (SparkleRepo repo in SparkleUI.Repositories) { + foreach (SparkleRepo repo in SparkleShare.Controller.Repositories) { // Get commits from the repository if (repo.LocalPath.Equals (LocalPath)) { @@ -239,7 +239,7 @@ namespace SparkleShare { VBox layout_vertical = new VBox (false, 0); - if (SparkleUI.Repositories.Find ( + if (SparkleShare.Controller.Repositories.Find ( delegate (SparkleRepo r) { return r.LocalPath.Equals (LocalPath) && r.HasUnsyncedChanges; } ) != null) { @@ -253,7 +253,7 @@ namespace SparkleShare { } else { - if (SparkleUI.Repositories.Find ( + if (SparkleShare.Controller.Repositories.Find ( delegate (SparkleRepo r) { return r.LocalPath.Equals (LocalPath) && r.HasUnsyncedChanges; } ) != null) { diff --git a/SparkleShare/SparkleShare.cs b/SparkleShare/SparkleShare.cs index 5923cce4..36e39d53 100644 --- a/SparkleShare/SparkleShare.cs +++ b/SparkleShare/SparkleShare.cs @@ -28,7 +28,8 @@ namespace SparkleShare { // This is SparkleShare! public class SparkleShare { - public static SparkleUI SparkleUI; + public static SparkleController Controller; + public static SparkleUI UI; public static string UserName; public static string UserEmail; @@ -46,23 +47,6 @@ namespace SparkleShare { // Use translations Catalog.Init (Defines.GETTEXT_PACKAGE, Defines.LOCALE_DIR); - // Check whether git is installed - Process process = new Process (); - process.StartInfo.FileName = "git"; - process.StartInfo.RedirectStandardOutput = true; - process.StartInfo.UseShellExecute = false; - process.Start (); - - if (process.StandardOutput.ReadToEnd ().IndexOf ("version") == -1) { - - Console.WriteLine (_("Git wasn't found.")); - Console.WriteLine (_("You can get Git from http://git-scm.com/.")); - - Environment.Exit (0); - - } - - UnixUserInfo user_info = new UnixUserInfo (UnixEnvironment.UserName); // Don't allow running as root @@ -76,13 +60,13 @@ namespace SparkleShare { } - bool HideUI = false; - bool ShowHelp = false; + bool hide_ui = false; + bool show_help = false; var p = new OptionSet () { - { "d|disable-gui", _("Don't show the notification icon"), v => HideUI = v != null }, + { "d|disable-gui", _("Don't show the notification icon"), v => hide_ui = v != null }, { "v|version", _("Show this help text"), v => { PrintVersion (); } }, - { "h|help", _("Print version information"), v => ShowHelp = v != null } + { "h|help", _("Print version information"), v => show_help = v != null } }; try { @@ -97,17 +81,19 @@ namespace SparkleShare { } - if (ShowHelp) - DisplayHelp (p); - - SparkleUI = new SparkleUI (HideUI); - SparkleUI.Run (); + if (show_help) + ShowHelp (p); + Controller = new SparkleController (); +if (!hide_ui){ + UI = new SparkleUI (); +UI.Run (); +} } // Prints the help output - public static void DisplayHelp (OptionSet option_set) + public static void ShowHelp (OptionSet option_set) { Console.WriteLine (" "); diff --git a/SparkleShare/SparkleStatusIcon.cs b/SparkleShare/SparkleStatusIcon.cs index e120408f..fc339ed6 100644 --- a/SparkleShare/SparkleStatusIcon.cs +++ b/SparkleShare/SparkleStatusIcon.cs @@ -27,22 +27,17 @@ namespace SparkleShare { // The statusicon that stays in the // user's notification area - public class SparkleStatusIcon : StatusIcon - { - - private Menu Menu; - private MenuItem StatusMenuItem; - private string StateText; + public class SparkleStatusIcon : StatusIcon { private Timer Animation; private Gdk.Pixbuf [] AnimationFrames; private int FrameNumber; - - private double FolderSize; - + private string StateText; + private Menu Menu; // Short alias for the translations - public static string _ (string s) { + public static string _ (string s) + { return Catalog.GetString (s); } @@ -50,27 +45,50 @@ namespace SparkleShare { public SparkleStatusIcon () : base () { - SparkleUI.OpenLogs = new List (); - - FolderSize = GetFolderSize (new DirectoryInfo (SparklePaths.SparklePath)); - FrameNumber = 0; AnimationFrames = CreateAnimationFrames (); Animation = CreateAnimation (); - StateText = ""; - StatusMenuItem = new MenuItem (); + Activate += ShowMenu; // Primary mouse button click + PopupMenu += ShowMenu; // Secondary mouse button click - CreateMenu (); + SetNormalState (); + UpdateMenu (); - // Primary mouse button click - Activate += ShowMenu; - // Secondary mouse button click - PopupMenu += ShowMenu; + SparkleShare.Controller.FolderSizeChanged += delegate { + Application.Invoke (delegate { + UpdateMenu (); + }); + }; + + SparkleShare.Controller.RepositoryListChanged += delegate { + Application.Invoke (delegate { + SetNormalState (); + UpdateMenu (); + }); + }; - SetIdleState (); - ShowState (); + SparkleShare.Controller.OnIdle += delegate { + Application.Invoke (delegate { + SetNormalState (); + UpdateMenu (); + }); + }; + + SparkleShare.Controller.OnSyncing += delegate { + Application.Invoke (delegate { + SetAnimationState (); + UpdateMenu (); + }); + }; + + SparkleShare.Controller.OnError += delegate { + Application.Invoke (delegate { + SetNormalState (true); + UpdateMenu (); + }); + }; } @@ -91,7 +109,7 @@ namespace SparkleShare { } - // Creates the Animation that handles the syncing animation. + // Creates the Animation that handles the syncing animation private Timer CreateAnimation () { @@ -107,9 +125,7 @@ namespace SparkleShare { FrameNumber = 0; Application.Invoke (delegate { - - SetPixbuf (AnimationFrames [FrameNumber]); - + Pixbuf = AnimationFrames [FrameNumber]; }); }; @@ -119,148 +135,36 @@ namespace SparkleShare { } - // A method reference that makes sure that - // opening the event log for each repository - // works correctly. - private EventHandler OpenLogDelegate (string path) - { - - return delegate { - - SparkleLog log = SparkleUI.OpenLogs.Find (delegate (SparkleLog l) { return l.LocalPath.Equals (path); }); - - // Check whether the log is already open, - // create a new one if that's not the case or - // present it to the user if it is - if (log == null) { - - log = new SparkleLog (path); - - log.Hidden += delegate { - - SparkleUI.OpenLogs.Remove (log); - log.Destroy (); - - }; - - SparkleUI.OpenLogs.Add (log); - - } - - log.ShowAll (); - log.Present (); - - }; - - } - - - // Recursively gets a folder's size in bytes - private double GetFolderSize (DirectoryInfo parent) - { - - if (!Directory.Exists (parent.ToString ())) - return 0; - - double size = 0; - - // Ignore the temporary 'rebase-apply' and '.tmp' directories. - // This prevents potential crashes when files are being - // queried whilst the files have already been deleted. - if (parent.Name.Equals ("rebase-apply") || - parent.Name.Equals (".tmp")) - return 0; - - foreach (FileInfo file in parent.GetFiles()) { - - if (!file.Exists) - return 0; - - size += file.Length; - - } - - foreach (DirectoryInfo directory in parent.GetDirectories()) - size += GetFolderSize (directory); - - return size; - - } - - - private void UpdateFolderSize () - { - - FolderSize = GetFolderSize (new DirectoryInfo (SparklePaths.SparklePath)); - - } - - - // Format a file size nicely with small caps. - // Example: 1048576 becomes "1 ᴍʙ" - private string FormatFileSize (double byte_count) - { - - if (byte_count >= 1099511627776) - - return String.Format ("{0:##.##} ᴛʙ", Math.Round (byte_count / 1099511627776, 1)); - - 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)); - - else if (byte_count >= 1024) - - return String.Format ("{0:##.##} ᴋʙ", Math.Round (byte_count / 1024, 1)); - - else - - return byte_count.ToString () + " bytes"; - - } - - // Creates the menu that is popped up when the - // user clicks the statusicon - public void CreateMenu () + // user clicks the status icon + public void UpdateMenu () { - Menu = new Menu (); + Menu = new Menu (); - // The menu item showing the status and size of the SparkleShare folder - StatusMenuItem = new MenuItem (StateText) { - Sensitive = false - }; + // The menu item showing the status and size of the SparkleShare folder + MenuItem status_menu_item = new MenuItem (StateText) { + Sensitive = false + }; - Menu.Add (StatusMenuItem); - Menu.Add (new SeparatorMenuItem ()); + // A menu item that provides a link to the SparkleShare folder + Gtk.Action folder_action = new Gtk.Action ("", "SparkleShare") { + IconName = "folder-sparkleshare", + IsImportant = true + }; - // A menu item that provides a link to the SparkleShare folder - Gtk.Action folder_action = new Gtk.Action ("", "SparkleShare") { - IconName = "folder-sparkleshare", - IsImportant = true - }; + folder_action.Activated += delegate { + SparkleShare.Controller.OpenSparkleShareFolder (); + }; - folder_action.Activated += delegate { + Menu.Add (status_menu_item); + Menu.Add (new SeparatorMenuItem ()); + Menu.Add (folder_action.CreateMenuItem ()); - Process process = new Process (); - process.StartInfo.FileName = "xdg-open"; - process.StartInfo.Arguments = SparklePaths.SparklePath; - process.Start (); - - }; - - Menu.Add (folder_action.CreateMenuItem ()); - - - if (SparkleUI.Repositories.Count > 0) { + if (SparkleShare.Controller.Repositories.Count > 0) { // Creates a menu item for each repository with a link to their logs - foreach (SparkleRepo repo in SparkleUI.Repositories) { + foreach (SparkleRepo repo in SparkleShare.Controller.Repositories) { folder_action = new Gtk.Action ("", repo.Name) { IconName = "folder", @@ -270,7 +174,7 @@ namespace SparkleShare { if (repo.HasUnsyncedChanges) folder_action.IconName = "dialog-error"; - folder_action.Activated += OpenLogDelegate (repo.LocalPath); + folder_action.Activated += OpenEventLogDelegate (repo.LocalPath); MenuItem menu_item = (MenuItem) folder_action.CreateMenuItem (); @@ -292,160 +196,105 @@ namespace SparkleShare { } // Opens the wizard to add a new remote folder - MenuItem add_item = new MenuItem (_("Sync Remote Folder…")); + MenuItem sync_item = new MenuItem (_("Sync Remote Folder…")); - add_item.Activated += delegate { + sync_item.Activated += delegate { + Application.Invoke (delegate { SparkleIntro intro = new SparkleIntro (); + intro.ShowServerForm (); - // Only show the server form in the wizard - intro.ShowServerForm (true); + }); + }; - }; - - Menu.Add (add_item); - Menu.Add (new SeparatorMenuItem ()); + Menu.Add (sync_item); + Menu.Add (new SeparatorMenuItem ()); // A checkbutton to toggle whether or not to show notifications CheckMenuItem notify_item = new CheckMenuItem (_("Show Notifications")); + + if (SparkleShare.Controller.NotificationsEnabled) + notify_item.Active = true; - // Whether notifications are shown depends existence of this file - string notify_setting_file_path = SparkleHelpers.CombineMore (SparklePaths.SparkleConfigPath, - "sparkleshare.notify"); - - if (File.Exists (notify_setting_file_path)) - notify_item.Active = true; + notify_item.Toggled += delegate { + SparkleShare.Controller.ToggleNotifications (); + }; - notify_item.Toggled += delegate { + Menu.Add (notify_item); + Menu.Add (new SeparatorMenuItem ()); - if (File.Exists (notify_setting_file_path)) - File.Delete (notify_setting_file_path); - else - File.Create (notify_setting_file_path); - - }; - - Menu.Add (notify_item); - Menu.Add (new SeparatorMenuItem ()); - - // A menu item that takes the use to sparkleshare.org + // A menu item that takes the user to http://www.sparkleshare.org/ MenuItem about_item = new MenuItem (_("Visit Website")); - about_item.Activated += delegate { + about_item.Activated += delegate { - Process process = new Process (); + Process process = new Process (); + process.StartInfo.FileName = "xdg-open"; + process.StartInfo.Arguments = "http://www.sparkleshare.org/"; + process.Start (); - process.StartInfo.FileName = "xdg-open"; - process.StartInfo.Arguments = "http://www.sparkleshare.org/"; + }; - process.Start (); + Menu.Add (about_item); + Menu.Add (new SeparatorMenuItem ()); - }; + // A menu item that quits the application + MenuItem quit_item = new MenuItem (_("Quit")); - Menu.Add (about_item); - Menu.Add (new SeparatorMenuItem ()); + quit_item.Activated += delegate { + SparkleShare.Controller.Quit (); + }; - // A menu item that quits the application - MenuItem quit_item = new MenuItem (_("Quit")); - quit_item.Activated += Quit; + Menu.Add (quit_item); - Menu.Add (quit_item); + Menu.ShowAll (); } + // A method reference that makes sure that opening the + // event log for each repository works correctly + private EventHandler OpenEventLogDelegate (string path) + { + + return delegate { + + SparkleLog log = SparkleUI.OpenLogs.Find (delegate (SparkleLog l) { return l.LocalPath.Equals (path); }); + + // Check whether the log is already open, create a new one if + //that's not the case or present it to the user if it is + if (log == null) { + + log = new SparkleLog (path); + + log.Hidden += delegate { + + SparkleUI.OpenLogs.Remove (log); + log.Destroy (); + + }; + + SparkleUI.OpenLogs.Add (log); + + } + + log.ShowAll (); + log.Present (); + + }; + + } + + + // Makes the menu visible private void ShowMenu (object o, EventArgs args) { - CreateMenu (); - Menu.ShowAll (); Menu.Popup (null, null, SetPosition, 0, Global.CurrentEventTime); } - // Shows the state and keeps the number of syncing repositories in mind - public void ShowState () - { - - UpdateFolderSize (); - - foreach (SparkleRepo repo in SparkleUI.Repositories) - - if (repo.IsSyncing || repo.IsBuffering) { - - SetSyncingState (); - break; - - } else { - - SetIdleState (); - - } - - // Use the new status text - (StatusMenuItem.Children [0] as Label).Text = StateText; - Menu.ShowAll (); - - } - - - // Changes the state to idle for when there's no syncing going on - private void SetIdleState () - { - - Animation.Stop (); - - int unsynced_repo_count = 0; - foreach (SparkleRepo repo in SparkleUI.Repositories) { - if (repo.HasUnsyncedChanges) - unsynced_repo_count++; - } - - if (unsynced_repo_count > 0) { - - Application.Invoke (delegate { SetPixbuf (SparkleUIHelpers.GetIcon ("sparkleshare-syncing-error", 24)); }); - - if (unsynced_repo_count == 1) - StateText = _("One of your folders failed to sync"); - else - StateText = _("Some folders failed to sync"); - - } else { - - Application.Invoke (delegate { SetPixbuf (AnimationFrames [0]); }); - - if (SparkleUI.Repositories.Count > 0) - StateText = _("Up to date") + " (" + FormatFileSize (FolderSize) + ")"; - else - StateText = _("Welcome to SparkleShare!"); - - } - - } - - - // Changes the status icon to the syncing animation - private void SetSyncingState () - { - - StateText = _("Syncing…"); - - if (!Animation.Enabled) - Animation.Start (); - - } - - - // Updates the icon used for the statusicon - private void SetPixbuf (Gdk.Pixbuf pixbuf) - { - - Pixbuf = pixbuf; - - } - - // Makes sure the menu pops up in the right position private void SetPosition (Menu menu, out int x, out int y, out bool push_in) { @@ -455,16 +304,53 @@ namespace SparkleShare { } - // Quits the program - private void Quit (object o, EventArgs args) + // The state when there's nothing going on + private void SetNormalState () { - foreach (SparkleRepo repo in SparkleUI.Repositories) - repo.Dispose (); + SetNormalState (false); - // Remove the process id file - File.Delete (SparkleHelpers.CombineMore (SparklePaths.SparkleTmpPath, "sparkleshare.pid")); - Application.Quit (); + } + + + // The state when there's nothing going on + private void SetNormalState (bool error) + { + + Animation.Stop (); + + if (SparkleShare.Controller.Repositories.Count == 0) { + + StateText = _("No folders yet"); + Pixbuf = AnimationFrames [0]; + + } else { + + if (error) { + + StateText = _("Not everything is synced"); + Pixbuf = SparkleUIHelpers.GetIcon ("sparkleshare-syncing-error", 24); + + } else { + + StateText = _("Up to date") + " (" + SparkleShare.Controller.FolderSize + ")"; + Pixbuf = AnimationFrames [0]; + + } + + } + + } + + + // The state when animating + private void SetAnimationState () + { + + StateText = _("Syncing…"); + + if (!Animation.Enabled) + Animation.Start (); } diff --git a/SparkleShare/SparkleUI.cs b/SparkleShare/SparkleUI.cs index cb32fe19..98afcf45 100644 --- a/SparkleShare/SparkleUI.cs +++ b/SparkleShare/SparkleUI.cs @@ -17,7 +17,6 @@ using Gtk; using Mono.Unix; using Mono.Unix.Native; -using SparkleLib; using System; using System.Collections.Generic; using System.Diagnostics; @@ -30,10 +29,10 @@ namespace SparkleShare { public class SparkleUI { - public static List Repositories; public static SparkleStatusIcon StatusIcon; public static List OpenLogs; + // Short alias for the translations public static string _(string s) { @@ -41,97 +40,71 @@ namespace SparkleShare { } - public SparkleUI (bool HideUI) + public SparkleUI () { // Initialize the application - Gtk.Application.Init (); + Application.Init (); - // Set the process name to something differen than 'mono' - SetProcessName ("sparkleshare"); + // Create the statusicon + StatusIcon = new SparkleStatusIcon (); + + // Keep track of event logs are open + SparkleUI.OpenLogs = new List (); - // The list of repositories - Repositories = new List (); - - InstallLauncher (); - EnableSystemAutostart (); - - // Create the SparkleShare folder and add it to the bookmarks - if (CreateSparkleShareFolder ()) - AddToBookmarks (); - - - // Watch the SparkleShare folder - FileSystemWatcher watcher = new FileSystemWatcher (SparklePaths.SparklePath) { - IncludeSubdirectories = false, - EnableRaisingEvents = true, - Filter = "*" - }; - - // Remove the repository when a delete event occurs - watcher.Deleted += delegate (object o, FileSystemEventArgs args) { - - RemoveRepository (args.FullPath); - - }; - - // Add the repository when a create event occurs - watcher.Created += delegate (object o, FileSystemEventArgs args) { - - // Handle invitations when the user saves an - // invitation into the SparkleShare folder - if (args.Name.EndsWith (".invitation")) { - - Application.Invoke (delegate { - - SparkleInvitation invitation = new SparkleInvitation (args.FullPath); - invitation.Present (); - - }); - - } else if (Directory.Exists (args.FullPath)) { - - AddRepository (args.FullPath); - - } - - }; - - - CreateConfigurationFolders (); - - // Don't create the window and status icon when - // the --disable-gui command line argument was given - if (!HideUI) { - - string global_config_file_path = SparkleHelpers.CombineMore (SparklePaths.SparkleConfigPath, "config"); - - // Show the introduction screen if SparkleShare isn't configured - if (!File.Exists (global_config_file_path)) { + SparkleShare.Controller.OnFirstRun += delegate { + Application.Invoke (delegate { SparkleIntro intro = new SparkleIntro (); intro.ShowAll (); - } else { + }); + }; - SparkleShare.UserName = SparkleShare.GetUserName (); - SparkleShare.UserEmail = SparkleShare.GetUserEmail (); + SparkleShare.Controller.OnInvitation += delegate (string invitation_file_path) { + Application.Invoke (delegate { - SparkleShare.AddKey (); + SparkleInvitation invitation = new SparkleInvitation (invitation_file_path); + invitation.Present (); - } + }); + }; - // Create the statusicon - StatusIcon = new SparkleStatusIcon (); + // Show a bubble when there are new changes + SparkleShare.Controller.NotificationRaised += delegate (string author, string email, string message, + string repository_path) { - } + Application.Invoke (delegate { + SparkleBubble bubble = new SparkleBubble (author, message) { + Icon = SparkleUIHelpers.GetAvatar (email, 32) + }; - Thread thread = new Thread ( - new ThreadStart (PopulateRepositories) - ); + bubble.AddAction ("", "Show Events", delegate { + + SparkleLog log = new SparkleLog (repository_path); + log.ShowAll (); + + }); - thread.Start (); + bubble.Show (); + + }); + + }; + + // Show a bubble when there was a conflict + SparkleShare.Controller.ConflictNotificationRaised += delegate { + Application.Invoke (delegate { + + string title = _("Ouch! Mid-air collision!"); + string subtext = _("Don't worry, SparkleShare made a copy of each conflicting file."); + + SparkleBubble bubble = new SparkleBubble(title, subtext); + bubble.Show (); + + }); + }; } @@ -140,401 +113,10 @@ namespace SparkleShare { public void Run () { - Gtk.Application.Run (); + Application.Run (); } - - // Creates a folder in the user's home folder to store configuration - private void CreateConfigurationFolders () - { - - if (!Directory.Exists (SparklePaths.SparkleTmpPath)) - Directory.CreateDirectory (SparklePaths.SparkleTmpPath); - - string config_path = SparklePaths.SparkleConfigPath; - string local_icon_path = SparklePaths.SparkleLocalIconPath; - - if (!Directory.Exists (config_path)) { - - // Create a folder to store settings - Directory.CreateDirectory (config_path); - SparkleHelpers.DebugInfo ("Config", "Created '" + config_path + "'"); - - // Create a folder to store the avatars - Directory.CreateDirectory (local_icon_path); - SparkleHelpers.DebugInfo ("Config", "Created '" + local_icon_path + "'"); - - string notify_setting_file = SparkleHelpers.CombineMore (config_path, "sparkleshare.notify"); - - // Enable notifications by default - if (!File.Exists (notify_setting_file)) - File.Create (notify_setting_file); - - } - - } - - - // Creates a .desktop entry in autostart folder to - // start SparkleShare automatically at login - private void EnableSystemAutostart () - { - - string autostart_path = SparkleHelpers.CombineMore (SparklePaths.HomePath, ".config", "autostart"); - string desktopfile_path = SparkleHelpers.CombineMore (autostart_path, "sparkleshare.desktop"); - - if (!File.Exists (desktopfile_path)) { - - if (!Directory.Exists (autostart_path)) - Directory.CreateDirectory (autostart_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 (); - - // Give the launcher the right permissions so it can be launched by the user - Syscall.chmod (desktopfile_path, FilePermissions.S_IRWXU); - - SparkleHelpers.DebugInfo ("Config", "Created '" + desktopfile_path + "'"); - - } - - } - - - // Installs a launcher so the user can launch SparkleShare - // from the Internet category if needed - private void InstallLauncher () - { - - string apps_path = SparkleHelpers.CombineMore (SparklePaths.HomePath, ".local", "share", "applications"); - string desktopfile_path = SparkleHelpers.CombineMore (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 - Syscall.chmod (desktopfile_path, FilePermissions.S_IRWXU); - - SparkleHelpers.DebugInfo ("Config", "Created '" + desktopfile_path + "'"); - - } - - } - - - // Adds the SparkleShare folder to the user's - // list of bookmarked places - private void AddToBookmarks () - { - - string bookmarks_file_path = Path.Combine (SparklePaths.HomePath, ".gtk-bookmarks"); - string sparkleshare_bookmark = "file://" + SparklePaths.SparklePath + " SparkleShare"; - - if (File.Exists (bookmarks_file_path)) { - - StreamReader reader = new StreamReader (bookmarks_file_path); - string bookmarks = reader.ReadToEnd (); - reader.Close (); - - if (!bookmarks.Contains (sparkleshare_bookmark)) { - - TextWriter writer = File.AppendText (bookmarks_file_path); - writer.WriteLine ("file://" + SparklePaths.SparklePath + " SparkleShare"); - writer.Close (); - - } - - } else { - - StreamWriter writer = new StreamWriter (bookmarks_file_path); - writer.WriteLine ("file://" + SparklePaths.SparklePath + " SparkleShare"); - writer.Close (); - - } - - } - - - // Creates the SparkleShare folder in the user's home folder - private bool CreateSparkleShareFolder () - { - - if (!Directory.Exists (SparklePaths.SparklePath)) { - - Directory.CreateDirectory (SparklePaths.SparklePath); - SparkleHelpers.DebugInfo ("Config", "Created '" + SparklePaths.SparklePath + "'"); - - string icon_file_path = SparkleHelpers.CombineMore (Defines.PREFIX, "share", "icons", "hicolor", - "48x48", "apps", "folder-sparkleshare.png"); - - string gvfs_command_path = SparkleHelpers.CombineMore (Path.VolumeSeparatorChar.ToString (), - "usr", "bin", "gvfs-set-attribute"); - - // Add a special icon to the SparkleShare folder - if (File.Exists (gvfs_command_path)) { - - Process process = new Process (); - - process.StartInfo.RedirectStandardOutput = true; - process.StartInfo.UseShellExecute = false; - - process.StartInfo.FileName = "gvfs-set-attribute"; - process.StartInfo.Arguments = SparklePaths.SparklePath + " metadata::custom-icon " + - "file://" + icon_file_path; - process.Start (); - - } - - return true; - - } - - return false; - - } - - - // Shows a notification bubble when someone - // made a change to the repository - private void ShowNewCommitBubble (string author, string email, string message, string repository_name) { - - string notify_settings_file = SparkleHelpers.CombineMore (SparklePaths.SparkleConfigPath, - "sparkleshare.notify"); - - if (File.Exists (notify_settings_file)) { - - SparkleBubble bubble = new SparkleBubble (author, message) { - Icon = SparkleUIHelpers.GetAvatar (email, 32) - }; - - bubble.AddAction ("", "Show Events", delegate { - - string path = SparkleHelpers.CombineMore (SparklePaths.SparklePath, repository_name); - - SparkleLog log = new SparkleLog (path); - log.ShowAll (); - - }); - - bubble.Show (); - - } - - } - - - // Shows a notification bubble when there - // was a conflict - private void ShowConflictBubble (object o, EventArgs args) - { - - string title = _("Ouch! Mid-air collision!"); - string subtext = _("Don't worry, SparkleShare made a copy of each conflicting file."); - - SparkleBubble bubble = new SparkleBubble(title, subtext); - bubble.Show (); - - } - - - // Tells the statusicon to update its state - private void UpdateStatusIcon (object o, EventArgs args) - { - - StatusIcon.ShowState (); - - } - - - // Adds a repository to the list of repositories and - // updates the statusicon menu - private void AddRepository (string folder_path) - { - - // Check if the folder is a git repo - if (!Directory.Exists (SparkleHelpers.CombineMore (folder_path, ".git"))) - return; - - SparkleRepo repo = new SparkleRepo (folder_path); - - repo.NewCommit += delegate (object o, NewCommitArgs args) { - Application.Invoke (delegate { ShowNewCommitBubble (args.Author, args.Email, args.Message, - args.RepositoryName); }); - }; - - repo.Commited += delegate (object o, SparkleEventArgs args) { - Application.Invoke (delegate { CheckForUnicorns (args.Message); }); - }; - - repo.FetchingStarted += delegate { - Application.Invoke (UpdateStatusIcon); - }; - - repo.FetchingFinished += delegate { - Application.Invoke (UpdateStatusIcon); - }; - - repo.FetchingFailed += delegate { - Application.Invoke (UpdateStatusIcon); - }; - - repo.ChangesDetected += delegate { - Application.Invoke (UpdateStatusIcon); - }; - - repo.PushingStarted += delegate { - Application.Invoke (UpdateStatusIcon); - }; - - repo.PushingFinished += delegate { - Application.Invoke (UpdateStatusIcon); - }; - - repo.CommitEndedUpEmpty += delegate { - Application.Invoke (UpdateStatusIcon); - }; - - repo.PushingFailed += delegate { - Application.Invoke (UpdateStatusIcon); - }; - - repo.ConflictDetected += delegate { - Application.Invoke (ShowConflictBubble); - }; - - Repositories.Add (repo); - - if (StatusIcon != null) { - - Application.Invoke (delegate { - StatusIcon.CreateMenu (); - StatusIcon.ShowState (); - }); - - } - - } - - - // Removes a repository from the list of repositories and - // updates the statusicon menu - private void RemoveRepository (string folder_path) - { - - string repo_name = Path.GetFileName (folder_path); - - for (int i = 0; i < Repositories.Count; i++) { - - SparkleRepo repo = Repositories [i]; - - if (repo.Name.Equals (repo_name)) { - - repo.Dispose (); - Repositories.Remove (repo); - repo = null; - break; - - } - - } - - if (StatusIcon != null) { - - Application.Invoke (delegate { - StatusIcon.CreateMenu (); - StatusIcon.ShowState (); - }); - - } - - } - - - // Updates the list of repositories with all the - // folders in the SparkleShare folder - private void PopulateRepositories () - { - - Repositories = new List (); - - foreach (string folder_path in Directory.GetDirectories (SparklePaths.SparklePath)) - AddRepository (folder_path); - - if (StatusIcon != null) - Application.Invoke (delegate { StatusIcon.ShowState (); }); - - } - - - // Warns the user implicitly that unicorns are actually lethal creatures - private static void CheckForUnicorns (string message) { - - message = message.ToLower (); - - if (message.Contains ("unicorn") && (message.Contains (".png") || message.Contains (".jpg"))) { - - string title = _("Hold your ponies!"); - string subtext = _("SparkleShare is known to be insanely fast with " + - "pictures of unicorns. Please make sure your internets " + - "are upgraded to the latest version to avoid any problems."); - - SparkleBubble bubble = new SparkleBubble (title, subtext); - bubble.Show (); - - } - - } - - - // Sets the unix process name to 'sparkleshare' instead of 'mono' - private void SetProcessName (string name) - { - - try { - - if (prctl (15, Encoding.ASCII.GetBytes (name + "\0"), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero) != 0) { - - throw new ApplicationException ("Error setting process name: " + - Mono.Unix.Native.Stdlib.GetLastError ()); - - } - - } catch (EntryPointNotFoundException) { - - Console.WriteLine ("SetProcessName: Entry point not found"); - - } - - } - - - // Strange magic needed by SetProcessName - [DllImport ("libc")] - private static extern int prctl (int option, byte [] arg2, IntPtr arg3, IntPtr arg4, IntPtr arg5); - } }