diff --git a/AUTHORS b/AUTHORS index 9507963b..8f845076 100644 --- a/AUTHORS +++ b/AUTHORS @@ -13,6 +13,7 @@ Contributors: Jakub Steiner Lapo Calamandrei Łukasz Jernaś + Michael Monreal Oleg Khlystov Philipp Gildein Ruben Vermeersch diff --git a/SparkleLib/SparkleFetcher.cs b/SparkleLib/SparkleFetcher.cs index 86501627..378fac49 100644 --- a/SparkleLib/SparkleFetcher.cs +++ b/SparkleLib/SparkleFetcher.cs @@ -98,6 +98,7 @@ namespace SparkleLib { private void InstallUserInfo () { + // TODO: Use TargetFolder and move SparklePaths out of SparkleLib string global_config_file_path = SparkleHelpers.CombineMore (SparklePaths.SparkleConfigPath, "config"); if (File.Exists (global_config_file_path)) { diff --git a/SparkleLib/SparkleRepo.cs b/SparkleLib/SparkleRepo.cs index afd19580..15302761 100644 --- a/SparkleLib/SparkleRepo.cs +++ b/SparkleLib/SparkleRepo.cs @@ -23,8 +23,7 @@ using System.Timers; namespace SparkleLib { - public class SparkleRepo - { + public class SparkleRepo { private Process Process; private Timer FetchTimer; @@ -85,6 +84,8 @@ namespace SparkleLib { CurrentHash = GetCurrentHash (); Domain = GetDomain (RemoteOriginUrl); + if (CurrentHash == null) + CreateInitialCommit (); HasChanged = false; @@ -128,6 +129,9 @@ namespace SparkleLib { // since SparkleShare was stopped AddCommitAndPush (); + if (CurrentHash == null) + CurrentHash = GetCurrentHash (); + SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Idling..."); } @@ -278,7 +282,7 @@ namespace SparkleLib { SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Fetching changes..."); - process.StartInfo.Arguments = "fetch"; + process.StartInfo.Arguments = "fetch -v origin master"; process.Start (); @@ -306,11 +310,13 @@ namespace SparkleLib { public void Rebase () { + Add (); // TODO: Experiment for the "You have unstaged changes" bug + Watcher.EnableRaisingEvents = false; SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Rebasing changes..."); - Process.StartInfo.Arguments = "rebase -v origin/master"; + Process.StartInfo.Arguments = "rebase -v FETCH_HEAD"; Process.WaitForExit (); Process.Start (); @@ -409,7 +415,7 @@ namespace SparkleLib { SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Pushing changes..."); - Process.StartInfo.Arguments = "push"; + Process.StartInfo.Arguments = "push origin master"; Process.Start (); Process.WaitForExit (); @@ -466,6 +472,9 @@ namespace SparkleLib { public string GetDomain (string url) { + if (RemoteOriginUrl.Equals ("")) + return ""; + string domain = url.Substring (RemoteOriginUrl.IndexOf ("@") + 1); if (domain.IndexOf (":") > -1) @@ -482,19 +491,25 @@ namespace SparkleLib { public string GetCurrentHash () { - string current_hash; + Process process = new Process () { + EnableRaisingEvents = true + }; - Process process = new Process (); process.StartInfo.RedirectStandardOutput = true; - process.StartInfo.UseShellExecute = false; - process.StartInfo.FileName = "git"; - process.StartInfo.WorkingDirectory = LocalPath; - process.StartInfo.Arguments = "rev-list --max-count=1 HEAD"; - process.Start (); + process.StartInfo.UseShellExecute = false; + process.StartInfo.FileName = "git"; + process.StartInfo.WorkingDirectory = LocalPath; + process.StartInfo.Arguments = "rev-list --max-count=1 HEAD"; - current_hash = process.StandardOutput.ReadToEnd ().Trim (); - - return current_hash; + process.Start (); + process.WaitForExit (); + + string current_hash = process.StandardOutput.ReadToEnd ().Trim (); + + if (process.ExitCode != 0) + return null; + else + return current_hash; } @@ -551,6 +566,18 @@ namespace SparkleLib { } + // Create a first commit in case the user has cloned + // an empty repository + private void CreateInitialCommit () + { + + TextWriter writer = new StreamWriter (Path.Combine (LocalPath, "SparkleShare.txt")); + writer.WriteLine (":)"); + writer.Close (); + + } + + // Gets the url of the remote repo, example: "ssh://git@git.gnome.org/project" public string GetRemoteOriginUrl () { diff --git a/SparkleShare/Makefile.am b/SparkleShare/Makefile.am index f3183d46..12abb8a9 100644 --- a/SparkleShare/Makefile.am +++ b/SparkleShare/Makefile.am @@ -11,6 +11,8 @@ SOURCES = \ SparkleBubble.cs \ SparkleEntry.cs \ SparkleIntro.cs \ + SparkleInvitation.cs \ + SparkleLog.cs \ SparkleShare.cs \ SparkleSpinner.cs \ SparkleStatusIcon.cs \ diff --git a/SparkleShare/SparkleIntro.cs b/SparkleShare/SparkleIntro.cs index 9f04b2aa..a2cba78c 100644 --- a/SparkleShare/SparkleIntro.cs +++ b/SparkleShare/SparkleIntro.cs @@ -24,17 +24,18 @@ using System.Text.RegularExpressions; namespace SparkleShare { - public class SparkleIntro : Window { + public class SparkleIntro : SparkleWindow { private Entry NameEntry; private Entry EmailEntry; private SparkleEntry ServerEntry; private SparkleEntry FolderEntry; private Button NextButton; - private Button AddButton; - private bool StepTwoOnly; + private Button SyncButton; + private bool ServerFormOnly; private string SecondaryTextColor; + // Short alias for the translations public static string _ (string s) { @@ -42,517 +43,460 @@ namespace SparkleShare { } - public SparkleIntro () : base ("") + public SparkleIntro () : base () { - BorderWidth = 0; - IconName = "folder-sparkleshare"; - Resizable = true; - WindowPosition = WindowPosition.Center; + ServerFormOnly = false; + SecondaryTextColor = GdkColorToHex (Style.Foreground (StateType.Insensitive)); - StepTwoOnly = false; - - SetDefaultSize (640, 480); - - Window window = new Window (""); - SecondaryTextColor = GdkColorToHex (window.Style.Foreground (StateType.Insensitive)); - - ShowStepOne (); + ShowAccountForm (); } - private void ShowStepOne () + private void ShowAccountForm () { - HBox layout_horizontal = new HBox (false, 6); + Reset (); - Image side_splash = new Image (SparkleHelpers.CombineMore (Defines.PREFIX, "share", "pixmaps", - "side-splash.png")); + VBox layout_vertical = new VBox (false, 0); - VBox wrapper = new VBox (false, 0); + Label header = new Label ("" + + _("Welcome to SparkleShare!") + + "") { + UseMarkup = true, + Xalign = 0 + }; - VBox layout_vertical = new VBox (false, 0) { - BorderWidth = 30 + Label information = new Label (_("Before we can create a SparkleShare folder on this " + + "computer, we need a few bits of information from you.")) { + Xalign = 0, + Wrap = true + }; + + Table table = new Table (4, 2, true) { + RowSpacing = 6 + }; + + UnixUserInfo unix_user_info = new UnixUserInfo (UnixEnvironment.UserName); + + Label name_label = new Label ("" + _("Full Name:") + "") { + UseMarkup = true, + Xalign = 0 }; - Label header = new Label ("" + - _("Welcome to SparkleShare!") + - "") { - UseMarkup = true, - Xalign = 0 - }; - - Label information = new Label (_("Before we can create a SparkleShare folder on this " + - "computer, we need a few bits of information from you.")) { - Xalign = 0, - Wrap = true - }; - - Table table = new Table (4, 2, true) { - RowSpacing = 6 - }; - - UnixUserInfo unix_user_info = new UnixUserInfo (UnixEnvironment.UserName); - - Label name_label = new Label ("" + _("Full Name:") + "") { - UseMarkup = true, - Xalign = 0 - }; - - NameEntry = new Entry (unix_user_info.RealName); - NameEntry.Changed += delegate { - CheckStepOneFields (); - }; + NameEntry = new Entry (unix_user_info.RealName); + NameEntry.Changed += delegate { + CheckAccountForm (); + }; - EmailEntry = new Entry (GetUserEmail ()); - EmailEntry.Changed += delegate { - CheckStepOneFields (); - }; + EmailEntry = new Entry (GetUserEmail ()); + EmailEntry.Changed += delegate { + CheckAccountForm (); + }; - Label email_label = new Label ("" + _("Email:") + "") { - UseMarkup = true, - Xalign = 0 - }; + Label email_label = new Label ("" + _("Email:") + "") { + UseMarkup = true, + Xalign = 0 + }; - table.Attach (name_label, 0, 1, 0, 1); - table.Attach (NameEntry, 1, 2, 0, 1); - table.Attach (email_label, 0, 1, 1, 2); - table.Attach (EmailEntry, 1, 2, 1, 2); - - HButtonBox controls = new HButtonBox () { - BorderWidth = 12, - Layout = ButtonBoxStyle.End - }; + table.Attach (name_label, 0, 1, 0, 1); + table.Attach (NameEntry, 1, 2, 0, 1); + table.Attach (email_label, 0, 1, 1, 2); + table.Attach (EmailEntry, 1, 2, 1, 2); + + NextButton = new Button (_("Next")) { + Sensitive = false + }; + + NextButton.Clicked += delegate (object o, EventArgs args) { - NextButton = new Button (_("Next")) { - Sensitive = false - }; - - NextButton.Clicked += delegate (object o, EventArgs args) { + NextButton.Remove (NextButton.Child); + NextButton.Add (new Label (_("Configuring…"))); - NextButton.Remove (NextButton.Child); - NextButton.Add (new Label (_("Configuring…"))); + NextButton.Sensitive = false; + table.Sensitive = false; - NextButton.Sensitive = false; - table.Sensitive = false; + NextButton.ShowAll (); - NextButton.ShowAll (); + Configure (); + ShowServerForm (); - Configure (); - ShowStepTwo (); + }; + + AddButton (NextButton); - }; - - controls.Add (NextButton); + layout_vertical.PackStart (header, false, false, 0); + layout_vertical.PackStart (information, false, false, 21); + layout_vertical.PackStart (new Label (""), false, false, 0); + layout_vertical.PackStart (table, false, false, 0); - layout_vertical.PackStart (header, false, false, 0); - layout_vertical.PackStart (information, false, false, 21); - layout_vertical.PackStart (new Label (""), false, false, 0); - layout_vertical.PackStart (table, false, false, 0); -// layout_vertical.PackStart (check_button, false, false, 0); + Add (layout_vertical); - - wrapper.PackStart (layout_vertical, true, true, 0); - wrapper.PackStart (controls, false, true, 0); - - layout_horizontal.PackStart (side_splash, false, false, 0); - layout_horizontal.PackStart (wrapper, true, true, 0); - - Add (layout_horizontal); - - CheckStepOneFields (); + CheckAccountForm (); ShowAll (); } - public void ShowStepTwo (bool step_two_only) + public void ShowServerForm (bool server_form_only) { - StepTwoOnly = step_two_only; - ShowStepTwo (); + ServerFormOnly = server_form_only; + ShowServerForm (); } - public void ShowStepTwo () + public void ShowServerForm () { - Remove (Child); - - HBox layout_horizontal = new HBox (false, 6); - - Image side_splash = new Image (SparkleHelpers.CombineMore (Defines.PREFIX, "share", "pixmaps", - "side-splash.png")); - - VBox wrapper = new VBox (false, 0); + Reset (); - VBox layout_vertical = new VBox (false, 0) { - BorderWidth = 30 + VBox layout_vertical = new VBox (false, 0); + + Label header = new Label ("" + + _("Where is your remote folder?") + + "") { + UseMarkup = true, + Xalign = 0 + }; + + Table table = new Table (7, 2, false) { + RowSpacing = 12 + }; + + HBox layout_server = new HBox (true, 0); + + ServerEntry = new SparkleEntry () { + ExampleText = _("ssh://address-to-my-server/") + }; + + ServerEntry.Changed += CheckServerForm; + + RadioButton radio_button = new RadioButton ("" + _("On my own server:") + ""); + + layout_server.Add (radio_button); + layout_server.Add (ServerEntry); + + string github_text = "" + "Github" + "\n" + + "" + + _("Free hosting for Free and Open Source Software projects.") + "\n" + + _("Also has paid accounts for extra private space and bandwidth.") + + ""; + + RadioButton radio_button_github = new RadioButton (radio_button, github_text); + + (radio_button_github.Child as Label).UseMarkup = true; + (radio_button_github.Child as Label).Wrap = true; + + string gnome_text = "" + _("The GNOME Project") + "\n" + + "" + + _("GNOME is an easy to understand interface to your computer.") + "\n" + + _("Select this option if you’re a developer or designer working on GNOME.") + + ""; + + RadioButton radio_button_gnome = new RadioButton (radio_button, gnome_text); + + (radio_button_gnome.Child as Label).UseMarkup = true; + (radio_button_gnome.Child as Label).Wrap = true; + + string gitorious_text = "" + _("Gitorious") + "\n" + + "" + + _("Completely Free as in Freedom infrastructure.") + "\n" + + _("Free accounts for Free and Open Source projects.") + + ""; + RadioButton radio_button_gitorious = new RadioButton (radio_button, gitorious_text) { + Xalign = 0 }; - - Label header = new Label ("" + - _("Where is your remote folder?") + - "") { - UseMarkup = true, - Xalign = 0 + + (radio_button_gitorious.Child as Label).UseMarkup = true; + (radio_button_gitorious.Child as Label).Wrap = true; + + radio_button_github.Toggled += delegate { + + if (radio_button_github.Active) + FolderEntry.ExampleText = "Username/Folder"; + + }; + + radio_button_gitorious.Toggled += delegate { + + if (radio_button_gitorious.Active) + FolderEntry.ExampleText = "Project/Folder"; + + }; + + radio_button_gnome.Toggled += delegate { + + if (radio_button_gnome.Active) + FolderEntry.ExampleText = "Project"; + + }; + + + radio_button.Toggled += delegate { + + if (radio_button.Active) { + + FolderEntry.ExampleText = "Folder"; + ServerEntry.Sensitive = true; + CheckServerForm (); + + } else { + + ServerEntry.Sensitive = false; + CheckServerForm (); + + } + + ShowAll (); + + }; + + table.Attach (layout_server, 0, 2, 1, 2); + table.Attach (radio_button_github, 0, 2, 2, 3); + table.Attach (radio_button_gitorious, 0, 2, 3, 4); + table.Attach (radio_button_gnome, 0, 2, 4, 5); + + HBox layout_folder = new HBox (true, 0); + + FolderEntry = new SparkleEntry () { + ExampleText = "Folder" + }; + + FolderEntry.Changed += CheckServerForm; + + Label folder_label = new Label ("" + _("Folder Name:") + "") { + UseMarkup = true, + Xalign = 1 + }; + + (radio_button.Child as Label).UseMarkup = true; + + layout_folder.PackStart (folder_label, true, true, 12); + layout_folder.PackStart (FolderEntry, true, true, 0); + + SyncButton = new Button (_("Sync")); + + SyncButton.Clicked += delegate { + + string name = FolderEntry.Text; + + // Remove the starting slash if there is one + if (name.StartsWith ("/")) + name = name.Substring (1); + + string server = ""; + + if (name.EndsWith ("/")) + name = name.TrimEnd ("/".ToCharArray ()); + + if (radio_button.Active) { + + server = SparkleToGitUrl (ServerEntry.Text); + + // Remove the trailing slash if there is one + if (server.EndsWith ("/")) + server = server.TrimEnd ("/".ToCharArray ()); + + } + + + if (radio_button_gitorious.Active) { + + server = "ssh://git@gitorious.org"; + + if (!name.EndsWith (".git")) + name += ".git"; + + } + + if (radio_button_github.Active) + server = "ssh://git@github.com"; + + if (radio_button_gnome.Active) + server = "ssh://git@gnome.org/git/"; + + string canonical_name = System.IO.Path.GetFileNameWithoutExtension (name); + FolderEntry.Text = canonical_name; + + string url = server + "/" + name; + string tmp_folder = SparkleHelpers.CombineMore (SparklePaths.SparkleTmpPath, + canonical_name); + + SparkleFetcher fetcher = new SparkleFetcher (url, tmp_folder); + + SparkleHelpers.DebugInfo ("Git", "[" + name + "] Formed URL: " + url); + + fetcher.CloningStarted += delegate { + + SparkleHelpers.DebugInfo ("Git", "[" + canonical_name + "] Cloning Repository"); + }; - Table table = new Table (7, 2, false) { - RowSpacing = 12 - }; - HBox layout_server = new HBox (true, 0); + fetcher.CloningFinished += delegate { - ServerEntry = new SparkleEntry () { - ExampleText = _("ssh://address-to-my-server/") - }; - - ServerEntry.Changed += CheckStepTwoFields; + SparkleHelpers.DebugInfo ("Git", "[" + canonical_name + "] Repository cloned"); - RadioButton radio_button = new RadioButton ("" + _("On my own server:") + ""); + ClearAttributes (tmp_folder); - layout_server.Add (radio_button); - layout_server.Add (ServerEntry); - - string github_text = "" + "Github" + "\n" + - "" + - _("Free hosting for Free and Open Source Software projects.") + "\n" + - _("Also has paid accounts for extra private space and bandwidth.") + - ""; + try { - RadioButton radio_button_github = new RadioButton (radio_button, github_text); + bool folder_exists = Directory.Exists ( + SparkleHelpers.CombineMore (SparklePaths.SparklePath, canonical_name)); - (radio_button_github.Child as Label).UseMarkup = true; - (radio_button_github.Child as Label).Wrap = true; + int i = 1; + while (folder_exists) { - string gnome_text = "" + _("The GNOME Project") + "\n" + - "" + - _("GNOME is an easy to understand interface to your computer.") + "\n" + - _("Select this option if you’re a developer or designer working on GNOME.") + - ""; - - RadioButton radio_button_gnome = new RadioButton (radio_button, gnome_text); - - (radio_button_gnome.Child as Label).UseMarkup = true; - (radio_button_gnome.Child as Label).Wrap = true; - - string gitorious_text = "" + _("Gitorious") + "\n" + - "" + - _("Completely Free as in Freedom infrastructure.") + "\n" + - _("Free accounts for Free and Open Source projects.") + - ""; - RadioButton radio_button_gitorious = new RadioButton (radio_button, gitorious_text) { - Xalign = 0 - }; - - (radio_button_gitorious.Child as Label).UseMarkup = true; - (radio_button_gitorious.Child as Label).Wrap = true; - - radio_button_github.Toggled += delegate { - - if (radio_button_github.Active) - FolderEntry.ExampleText = "Username/Folder"; - - }; - - radio_button_gitorious.Toggled += delegate { - - if (radio_button_gitorious.Active) - FolderEntry.ExampleText = "Project/Folder"; - - }; - - radio_button_gnome.Toggled += delegate { - - if (radio_button_gnome.Active) - FolderEntry.ExampleText = "Project"; - - }; - - - radio_button.Toggled += delegate { - - if (radio_button.Active) { - - FolderEntry.ExampleText = "Folder"; - ServerEntry.Sensitive = true; - CheckStepTwoFields (); - - } else { - - ServerEntry.Sensitive = false; - CheckStepTwoFields (); + i++; + folder_exists = Directory.Exists ( + SparkleHelpers.CombineMore (SparklePaths.SparklePath, + canonical_name + " (" + i + ")")); } - ShowAll (); + string target_folder_name = canonical_name; - }; + if (i > 1) + target_folder_name += " (" + i + ")"; - table.Attach (layout_server, 0, 2, 1, 2); - table.Attach (radio_button_github, 0, 2, 2, 3); - table.Attach (radio_button_gitorious, 0, 2, 3, 4); - table.Attach (radio_button_gnome, 0, 2, 4, 5); + string target_folder_path; + target_folder_path = SparkleHelpers.CombineMore (SparklePaths.SparklePath, + target_folder_name); - HBox layout_folder = new HBox (true, 0); + Directory.Move (tmp_folder, target_folder_path); - FolderEntry = new SparkleEntry () { - ExampleText = "Folder" - }; - - FolderEntry.Changed += CheckStepTwoFields; + } catch (Exception e) { - Label folder_label = new Label ("" + _("Folder Name:") + "") { - UseMarkup = true, - Xalign = 1 - }; + SparkleHelpers.DebugInfo ("Git", + "[" + name + "] Error moving folder: " + e.Message); - (radio_button.Child as Label).UseMarkup = true; + } - layout_folder.PackStart (folder_label, true, true, 12); - layout_folder.PackStart (FolderEntry, true, true, 0); + Application.Invoke (delegate { ShowSuccessPage (); }); - - HButtonBox controls = new HButtonBox () { - BorderWidth = 12, - Layout = ButtonBoxStyle.End, - Spacing = 6 }; - AddButton = new Button (_("Sync")); - - AddButton.Clicked += delegate { - string name = FolderEntry.Text; + fetcher.CloningFailed += delegate { - // Remove the starting slash if there is one - if (name.StartsWith ("/")) - name = name.Substring (1); + SparkleHelpers.DebugInfo ("Git", "[" + canonical_name + "] Cloning failed"); - string server = ""; + if (Directory.Exists (tmp_folder)) { - if (radio_button.Active) { + ClearAttributes (tmp_folder); + Directory.Delete (tmp_folder, true); - server = SparkleToGitUrl (ServerEntry.Text); + SparkleHelpers.DebugInfo ("Config", + "[" + name + "] Deleted temporary directory"); - // Remove the trailing slash if there is one - if (server.EndsWith ("/")) - server = server.Trim ("/".ToCharArray ()); + } - } + Application.Invoke (delegate { ShowErrorPage (); }); - if (radio_button_gitorious.Active) - server = "ssh://git@gitorious.org"; + }; - if (radio_button_github.Active) - server = "ssh://git@github.com"; + ShowSyncingPage (); + fetcher.Clone (); - if (radio_button_gnome.Active) - server = "ssh://git@gnome.org"; - - if (!name.EndsWith (".git")) - name += ".git"; - - string canonical_name = System.IO.Path.GetFileNameWithoutExtension (name); - FolderEntry.Text = canonical_name; - - string url = server + "/" + name; - string tmp_folder = SparkleHelpers.CombineMore (SparklePaths.SparkleTmpPath, - canonical_name); - - SparkleFetcher fetcher = new SparkleFetcher (url, tmp_folder); - - Console.WriteLine (url); - - fetcher.CloningStarted += delegate { - - SparkleHelpers.DebugInfo ("Git", "[" + canonical_name + "] Cloning Repository"); - - }; + }; - fetcher.CloningFinished += delegate { + if (ServerFormOnly) { - SparkleHelpers.DebugInfo ("Git", "[" + canonical_name + "] Repository cloned"); + Button cancel_button = new Button (_("Cancel")); - ClearAttributes (tmp_folder); + cancel_button.Clicked += delegate { + Destroy (); + }; - try { - - bool folder_exists = Directory.Exists ( - SparkleHelpers.CombineMore (SparklePaths.SparklePath, canonical_name)); - - int i = 1; - while (folder_exists) { - - i++; - folder_exists = Directory.Exists ( - SparkleHelpers.CombineMore (SparklePaths.SparklePath, - canonical_name + " (" + i + ")")); - - } - - string target_folder_name = canonical_name; - - if (i > 1) - target_folder_name += " (" + i + ")"; - - Directory.Move (tmp_folder, - SparkleHelpers.CombineMore (SparklePaths.SparklePath, target_folder_name)); - - } catch (Exception e) { - - SparkleHelpers.DebugInfo ("Git", - "[" + name + "] Error moving folder: " + e.Message); - - } - - Application.Invoke (delegate { ShowFinishedStep (); }); - - }; + AddButton (cancel_button); - fetcher.CloningFailed += delegate { + } else { - SparkleHelpers.DebugInfo ("Git", "[" + canonical_name + "] Cloning failed"); + Button skip_button = new Button (_("Skip")); - if (Directory.Exists (tmp_folder)) { + skip_button.Clicked += delegate { + ShowCompletedPage (); + }; - ClearAttributes (tmp_folder); - Directory.Delete (tmp_folder, true); + AddButton (skip_button); - SparkleHelpers.DebugInfo ("Config", - "[" + name + "] Deleted temporary directory"); + } - } + AddButton (SyncButton); - Application.Invoke (delegate { ShowErrorStep (); }); + layout_vertical.PackStart (header, false, false, 0); + layout_vertical.PackStart (new Label (""), false, false, 3); + layout_vertical.PackStart (table, false, false, 0); + layout_vertical.PackStart (layout_folder, false, false, 6); - }; + Add (layout_vertical); - ShowStepTwoAndAHalf (); - fetcher.Clone (); - - }; - - Button skip_button = new Button (_("Skip")); - - skip_button.Clicked += delegate { - ShowStepThree (); - }; - - - if (!StepTwoOnly) - controls.Add (skip_button); - - controls.Add (AddButton); - - layout_vertical.PackStart (header, false, false, 0); - layout_vertical.PackStart (new Label (""), false, false, 3); - layout_vertical.PackStart (table, false, false, 0); - layout_vertical.PackStart (layout_folder, false, false, 6); - - wrapper.PackStart (layout_vertical, true, true, 0); - wrapper.PackStart (controls, false, true, 0); - - layout_horizontal.PackStart (side_splash, false, false, 0); - layout_horizontal.PackStart (wrapper, true, true, 0); - - Add (layout_horizontal); - - CheckStepTwoFields (); + CheckServerForm (); ShowAll (); } - private void ShowErrorStep () + private void ShowErrorPage () { - Remove (Child); - - HBox layout_horizontal = new HBox (false, 6); - - Image side_splash = new Image (SparkleHelpers.CombineMore (Defines.PREFIX, "share", "pixmaps", - "side-splash.png")); - - VBox wrapper = new VBox (false, 0); + Reset (); - VBox layout_vertical = new VBox (false, 0) { - BorderWidth = 30 + VBox layout_vertical = new VBox (false, 0); + + Label header = new Label ("" + + _("Something went wrong…") + + "\n") { + UseMarkup = true, + Xalign = 0 + }; + + Label information = new Label ("" + + _("Hey, it's an Alpha!") + + "") { + Xalign = 0, + Wrap = true, + UseMarkup = true + }; + + Button try_again_button = new Button (_("Try again…")) { + Sensitive = true }; - - Label header = new Label ("" + - _("Something went wrong…") + - "\n") { - UseMarkup = true, - Xalign = 0 - }; - - Label information = new Label ("" + - _("Hey, it's an Alpha!") + - "") { - Xalign = 0, - Wrap = true, - UseMarkup = true - }; + + try_again_button.Clicked += delegate (object o, EventArgs args) { - - HButtonBox controls = new HButtonBox () { - BorderWidth = 12, - Layout = ButtonBoxStyle.End - }; + ShowServerForm (); - Button try_again_button = new Button (_("Try again…")) { - Sensitive = true - }; - - try_again_button.Clicked += delegate (object o, EventArgs args) { + }; + + AddButton (try_again_button); - ShowStepTwo (); + layout_vertical.PackStart (header, false, false, 0); + layout_vertical.PackStart (information, false, false, 0); - }; - - controls.Add (try_again_button); - - layout_vertical.PackStart (header, false, false, 0); - layout_vertical.PackStart (information, false, false, 0); - - wrapper.PackStart (layout_vertical, true, true, 0); - wrapper.PackStart (controls, false, true, 0); - - layout_horizontal.PackStart (side_splash, false, false, 0); - layout_horizontal.PackStart (wrapper, true, true, 0); - - Add (layout_horizontal); + Add (layout_vertical); ShowAll (); - + } - private void ShowFinishedStep () + private void ShowSuccessPage () { - Remove (Child); + Reset (); - HBox layout_horizontal = new HBox (false, 6); + VBox layout_vertical = new VBox (false, 0); - Image side_splash = new Image (SparkleHelpers.CombineMore (Defines.PREFIX, "share", "pixmaps", - "side-splash.png")); - - VBox wrapper = new VBox (false, 0); - - VBox layout_vertical = new VBox (false, 0) { - BorderWidth = 30 - }; - Label header = new Label ("" + _("Folder synced successfully!") + "") { @@ -568,56 +512,30 @@ namespace SparkleShare { UseMarkup = true }; - - HButtonBox controls = new HButtonBox () { - BorderWidth = 12, - Layout = ButtonBoxStyle.End - }; - Button finish_button = new Button (_("Finish")); finish_button.Clicked += delegate (object o, EventArgs args) { - - if(SparkleShare.SparkleUI != null) - SparkleShare.SparkleUI.UpdateRepositories (); - Destroy (); - }; - controls.Add (finish_button); + AddButton (finish_button); layout_vertical.PackStart (header, false, false, 0); layout_vertical.PackStart (information, false, false, 0); - wrapper.PackStart (layout_vertical, true, true, 0); - wrapper.PackStart (controls, false, true, 0); - - layout_horizontal.PackStart (side_splash, false, false, 0); - layout_horizontal.PackStart (wrapper, true, true, 0); - - Add (layout_horizontal); + Add (layout_vertical); ShowAll (); } - private void ShowStepTwoAndAHalf () + private void ShowSyncingPage () { - Remove (Child); - - HBox layout_horizontal = new HBox (false, 6); - - Image side_splash = new Image (SparkleHelpers.CombineMore (Defines.PREFIX, "share", "pixmaps", - "side-splash.png")); - - VBox wrapper = new VBox (false, 0); + Reset (); - VBox layout_vertical = new VBox (false, 0) { - BorderWidth = 30 - }; + VBox layout_vertical = new VBox (false, 0); Label header = new Label ("" + String.Format (_("Syncing folder ‘{0}’…"), FolderEntry.Text) + @@ -635,17 +553,12 @@ namespace SparkleShare { Xalign = 0 }; - HButtonBox controls = new HButtonBox () { - BorderWidth = 12, - Layout = ButtonBoxStyle.End, - Spacing = 6 - }; Button button = new Button () { Sensitive = false }; - if (StepTwoOnly) { + if (ServerFormOnly) { button.Label = _("Finish"); button.Clicked += delegate { @@ -656,12 +569,12 @@ namespace SparkleShare { button.Label = _("Next"); button.Clicked += delegate { - ShowStepThree (); + ShowCompletedPage (); }; } - controls.Add (button); + AddButton (button); SparkleSpinner spinner = new SparkleSpinner (22); @@ -680,36 +593,19 @@ namespace SparkleShare { layout_vertical.PackStart (box, false, false, 0); - wrapper.PackStart (layout_vertical, true, true, 0); - wrapper.PackStart (controls, false, true, 0); - - layout_horizontal.PackStart (side_splash, false, false, 0); - layout_horizontal.PackStart (wrapper, true, true, 0); - - Add (layout_horizontal); - - CheckStepTwoFields (); + Add (layout_vertical); ShowAll (); } - private void ShowStepThree () + private void ShowCompletedPage () { - Remove (Child); + Reset (); - HBox layout_horizontal = new HBox (false, 6); - - Image side_splash = new Image (SparkleHelpers.CombineMore (Defines.PREFIX, "share", "pixmaps", - "side-splash.png")); - - VBox wrapper = new VBox (false, 0); - - VBox layout_vertical = new VBox (false, 0) { - BorderWidth = 30 - }; + VBox layout_vertical = new VBox (false, 0); Label header = new Label ("" + _("SparkleShare is ready to go!") + @@ -737,11 +633,6 @@ namespace SparkleShare { layout_vertical.PackStart (information, false, false, 21); layout_vertical.PackStart (link_wrapper, false, false, 0); - HButtonBox controls = new HButtonBox () { - Layout = ButtonBoxStyle.End, - BorderWidth = 12 - }; - Button finish_button = new Button (_("Finish")); finish_button.Clicked += delegate (object o, EventArgs args) { @@ -753,15 +644,9 @@ namespace SparkleShare { }; - controls.Add (finish_button); + AddButton (finish_button); - wrapper.PackStart (layout_vertical, true, true, 0); - wrapper.PackStart (controls, false, false, 0); - - layout_horizontal.PackStart (side_splash, false, false, 0); - layout_horizontal.PackStart (wrapper, true, true, 0); - - Add (layout_horizontal); + Add (layout_vertical); ShowAll (); @@ -770,7 +655,7 @@ namespace SparkleShare { // Enables or disables the 'Next' button depending on the // entries filled in by the user - private void CheckStepOneFields () + private void CheckAccountForm () { if (NameEntry.Text.Length > 0 && @@ -789,30 +674,30 @@ namespace SparkleShare { // Enables the Add button when the fields are // filled in correctly - public void CheckStepTwoFields (object o, EventArgs args) + public void CheckServerForm (object o, EventArgs args) { - CheckStepTwoFields (); + CheckServerForm (); } // Enables the Add button when the fields are // filled in correctly - public void CheckStepTwoFields () + public void CheckServerForm () { - AddButton.Sensitive = false; + SyncButton.Sensitive = false; bool IsFolder = !FolderEntry.Text.Trim ().Equals (""); if (ServerEntry.Sensitive == true) { if (IsGitUrl (ServerEntry.Text) && IsFolder) - AddButton.Sensitive = true; + SyncButton.Sensitive = true; } else if (IsFolder) { - AddButton.Sensitive = true; + SyncButton.Sensitive = true; } diff --git a/SparkleShare/SparkleInvitation.cs b/SparkleShare/SparkleInvitation.cs new file mode 100644 index 00000000..5b135107 --- /dev/null +++ b/SparkleShare/SparkleInvitation.cs @@ -0,0 +1,43 @@ +// 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 System; +using System.IO; +using System.Xml; + +namespace SparkleShare { + + class SparkleInvitation { + + public SparkleInvitation (string file_path) + { + + XmlDocument xml_doc = new XmlDocument (); + xml_doc.Load (file_path); + + XmlNodeList server_xml = xml_doc.GetElementsByTagName ("server"); + XmlNodeList repository_xml = xml_doc.GetElementsByTagName ("repository"); + XmlNodeList key_xml = xml_doc.GetElementsByTagName ("key"); + + string server = server_xml [0].InnerText; + string repository = repository_xml [0].InnerText; + string key = key_xml [0].InnerText; + + } + + } + +} diff --git a/SparkleShare/SparkleLog.cs b/SparkleShare/SparkleLog.cs new file mode 100644 index 00000000..903f489b --- /dev/null +++ b/SparkleShare/SparkleLog.cs @@ -0,0 +1,318 @@ +// 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 Gtk; +using Mono.Unix; +using SparkleLib; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text.RegularExpressions; + +namespace SparkleShare { + + public class SparkleLog : Window { + + private SparkleRepo SparkleRepo; + private VBox LayoutVertical; + private ScrolledWindow ScrolledWindow; + + + // Short alias for the translations + public static string _ (string s) + { + return Catalog.GetString (s); + } + + + public SparkleLog (SparkleRepo sparkle_repo) : base ("") + { + + SparkleRepo = sparkle_repo; + SetSizeRequest (540, 640); + SetPosition (WindowPosition.Center); + BorderWidth = 12; + + // TRANSLATORS: {0} is a folder name, and {1} is a server address + Title = String.Format(_("Recent Events in ‘{0}’"), SparkleRepo.Name); + IconName = "folder"; + + LayoutVertical = new VBox (false, 12); + + LayoutVertical.PackStart (CreateEventLog (), true, true, 0); + + HButtonBox dialog_buttons = new HButtonBox { + Layout = ButtonBoxStyle.Edge, + BorderWidth = 0 + }; + + Button open_folder_button = new Button (_("Open Folder")); + + open_folder_button.Clicked += delegate (object o, EventArgs args) { + + string path = SparkleHelpers.CombineMore (SparklePaths.SparklePath, SparkleRepo.Name); + + Process process = new Process (); + process.StartInfo.FileName = "xdg-open"; + process.StartInfo.Arguments = path.Replace(" ", "\\ "); // Escape space-characters + process.Start (); + + Destroy (); + + }; + + Button close_button = new Button (Stock.Close); + + close_button.Clicked += delegate (object o, EventArgs args) { + Destroy (); + }; + + dialog_buttons.Add (open_folder_button); + dialog_buttons.Add (close_button); + + LayoutVertical.PackStart (dialog_buttons, false, false, 0); + + Add (LayoutVertical); + + } + + + public void UpdateEventLog () + { + + LayoutVertical.Remove (ScrolledWindow); + ScrolledWindow = CreateEventLog (); + LayoutVertical.PackStart (ScrolledWindow, true, true, 0); + LayoutVertical.ReorderChild (ScrolledWindow, 0); + ShowAll (); + + } + + + private ScrolledWindow CreateEventLog () + { + + int number_of_events = 50; + + Process process = new Process () { + EnableRaisingEvents = true + }; + + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.UseShellExecute = false; + process.StartInfo.WorkingDirectory = SparkleRepo.LocalPath; + process.StartInfo.FileName = "git"; + process.StartInfo.Arguments = "log --format=\"%at☃%an☃%ae☃%s\" -" + number_of_events; + + process.Start (); + + string output = process.StandardOutput.ReadToEnd ().Trim (); + + output = output.TrimStart ("\n".ToCharArray ()); + string [] lines = Regex.Split (output, "\n"); + int linesLength = lines.Length; + if (output == "") + linesLength = 0; + + // Sort by time and get the last 25 + Array.Sort (lines); + Array.Reverse (lines); + + List activity_days = new List (); + + for (int i = 0; i < number_of_events && i < linesLength; i++) { + + string line = lines [i]; + + // Look for the snowman! + string [] parts = Regex.Split (line, "☃"); + + int unix_timestamp = int.Parse (parts [0]); + string user_name = parts [1]; + string user_email = parts [2]; + string message = parts [3]; + + DateTime date_time = UnixTimestampToDateTime (unix_timestamp); + + message = message.Replace ("\n", " "); + + ChangeSet change_set = new ChangeSet (user_name, user_email, message, date_time); + + bool change_set_inserted = false; + foreach (ActivityDay stored_activity_day in activity_days) { + + if (stored_activity_day.DateTime.Year == change_set.DateTime.Year && + stored_activity_day.DateTime.Month == change_set.DateTime.Month && + stored_activity_day.DateTime.Day == change_set.DateTime.Day) { + + stored_activity_day.Add (change_set); + change_set_inserted = true; + break; + + } + + } + + if (!change_set_inserted) { + + ActivityDay activity_day = new ActivityDay (change_set.DateTime); + activity_day.Add (change_set); + activity_days.Add (activity_day); + + } + + } + + + VBox layout_vertical = new VBox (false, 0); + + foreach (ActivityDay activity_day in activity_days) { + + TreeIter iter = new TreeIter (); + ListStore list_store = new ListStore (typeof (Gdk.Pixbuf), + typeof (string), + typeof (string)); + + Gdk.Color color = Style.Foreground (StateType.Insensitive); + string secondary_text_color = GdkColorToHex (color); + + foreach (ChangeSet change_set in activity_day) { + + iter = list_store.Append (); + + list_store.SetValue (iter, 0, SparkleHelpers.GetAvatar (change_set.UserEmail , 32)); + + list_store.SetValue (iter, 1, "" + change_set.UserName + "\n" + + "" + + change_set.Message + "\n" + + "" + change_set.DateTime.ToString ("HH:mm") + "" + + ""); + + list_store.SetValue (iter, 2, change_set.UserEmail); + + } + + Label date_label = new Label ("") { + UseMarkup = true, + Xalign = 0, + Xpad = 9, + Ypad = 9 + }; + + DateTime today = DateTime.Now; + DateTime yesterday = DateTime.Now.AddDays (-1); + + if (today.Day == activity_day.DateTime.Day && + today.Month == activity_day.DateTime.Month && + today.Year == activity_day.DateTime.Year) { + + date_label.Markup = "Today"; + + } else if (yesterday.Day == activity_day.DateTime.Day && + yesterday.Month == activity_day.DateTime.Month && + yesterday.Year == activity_day.DateTime.Year) { + + date_label.Markup = "Yesterday"; + + } else { + + date_label.Markup = "" + activity_day.DateTime.ToString ("ddd MMM d, yyyy") + ""; + + } + + layout_vertical.PackStart (date_label, false, false, 0); + + IconView icon_view = new IconView (list_store) { + ItemWidth = 470, + MarkupColumn = 1, + Orientation = Orientation.Horizontal, + PixbufColumn = 0, + Spacing = 9 + }; + + icon_view.SelectionChanged += delegate { + icon_view.UnselectAll (); + }; + + layout_vertical.PackStart (icon_view, false, false, 0); + + } + + ScrolledWindow = new ScrolledWindow (); + ScrolledWindow.ShadowType = ShadowType.None; + ScrolledWindow.AddWithViewport (layout_vertical); + + return ScrolledWindow; + + } + + + // Converts a UNIX timestamp to a more usable time object + public DateTime UnixTimestampToDateTime (int timestamp) + { + DateTime unix_epoch = new DateTime (1970, 1, 1, 0, 0, 0, 0); + return unix_epoch.AddSeconds (timestamp); + } + + + // Converts a Gdk RGB color to a hex value. + // Example: from "rgb:0,0,0" to "#000000" + public string GdkColorToHex (Gdk.Color color) + { + + return String.Format ("#{0:X2}{1:X2}{2:X2}", + (int) Math.Truncate (color.Red / 256.00), + (int) Math.Truncate (color.Green / 256.00), + (int) Math.Truncate (color.Blue / 256.00)); + + } + + } + + + public class ActivityDay : List + { + + public DateTime DateTime; + + public ActivityDay (DateTime date_time) + { + DateTime = date_time; + DateTime = new DateTime (DateTime.Year, DateTime.Month, DateTime.Day); + } + + } + + + public class ChangeSet + { + + public string UserName; + public string UserEmail; + public string Message; + public DateTime DateTime; + + public ChangeSet (string user_name, string user_email, string message, DateTime date_time) + { + UserName = user_name; + UserEmail = user_email; + Message = message; + DateTime = date_time; + } + + } + +} diff --git a/SparkleShare/SparkleShare.cs b/SparkleShare/SparkleShare.cs index 68cd5620..1bb77ad1 100644 --- a/SparkleShare/SparkleShare.cs +++ b/SparkleShare/SparkleShare.cs @@ -25,13 +25,15 @@ namespace SparkleShare { // This is SparkleShare! public class SparkleShare { + public static SparkleUI SparkleUI; + + // Short alias for the translations public static string _ (string s) { return Catalog.GetString (s); } - public static SparkleUI SparkleUI; public static void Main (string [] args) { @@ -60,41 +62,74 @@ namespace SparkleShare { Environment.Exit (0); } - // Parse the command line arguments bool HideUI = false; + + // Parse the command line arguments if (args.Length > 0) { + foreach (string Argument in args) { + if (Argument.Equals ("--disable-gui") || Argument.Equals ("-d")) HideUI = true; + + if (Argument.Equals ("--version") || Argument.Equals ("-v")) { + + PrintVersion (); + Environment.Exit (0); + + } + if (Argument.Equals ("--help") || Argument.Equals ("-h")) { + ShowHelp (); Environment.Exit (0); + } + } + } SparkleUI = new SparkleUI (HideUI); SparkleUI.Run(); + } + // Prints the help output public static void ShowHelp () { - Console.WriteLine (_("SparkleShare Copyright (C) 2010 Hylke Bons")); + + Console.WriteLine (" "); + Console.WriteLine (_("SparkleShare, an instant update workflow to Git.")); + Console.WriteLine (_("Copyright (C) 2010 Hylke Bons")); Console.WriteLine (" "); Console.WriteLine (_("This program comes with ABSOLUTELY NO WARRANTY.")); + Console.WriteLine (" "); Console.WriteLine (_("This is free software, and you are welcome to redistribute it ")); Console.WriteLine (_("under certain conditions. Please read the GNU GPLv3 for details.")); Console.WriteLine (" "); - Console.WriteLine (_("SparkleShare syncs the ~/SparkleShare folder with remote repositories.")); + Console.WriteLine (_("SparkleShare automatically syncs Git repositories in ")); + Console.WriteLine (_("the ~/SparkleShare folder with their remote origins.")); Console.WriteLine (" "); Console.WriteLine (_("Usage: sparkleshare [start|stop|restart] [OPTION]...")); Console.WriteLine (_("Sync SparkleShare folder with remote repositories.")); Console.WriteLine (" "); Console.WriteLine (_("Arguments:")); Console.WriteLine (_("\t -d, --disable-gui\tDon't show the notification icon.")); - Console.WriteLine (_("\t -h, --help\t\tDisplay this help text.")); + Console.WriteLine (_("\t -h, --help\t\tShow this help text.")); + Console.WriteLine (_("\t -v, --version\t\tPrint version information.")); Console.WriteLine (" "); + + } + + + // Prints the version information + public static void PrintVersion () + { + + Console.WriteLine (_("SparkleShare " + Defines.VERSION)); + } } diff --git a/SparkleShare/SparkleStatusIcon.cs b/SparkleShare/SparkleStatusIcon.cs index 26bc4791..032a97ee 100644 --- a/SparkleShare/SparkleStatusIcon.cs +++ b/SparkleShare/SparkleStatusIcon.cs @@ -29,12 +29,14 @@ namespace SparkleShare { public int SyncingReposCount; - private Timer Timer; private Menu Menu; private MenuItem StatusMenuItem; private string StateText; + + private Timer Timer; private Gdk.Pixbuf [] AnimationFrames; private int FrameNumber; + private Gtk.Action FolderAction; private double FolderSize; @@ -50,8 +52,9 @@ namespace SparkleShare { FolderSize = GetFolderSize (new DirectoryInfo (SparklePaths.SparklePath)); - CreateAnimationFrames (); - CreateTimer (); + FrameNumber = 0; + AnimationFrames = CreateAnimationFrames (); + Timer = CreateTimer (); SyncingReposCount = 0; @@ -59,37 +62,42 @@ namespace SparkleShare { StatusMenuItem = new MenuItem (); CreateMenu (); + + // Primary mouse button Activate += ShowMenu; + // Secondary mouse button + PopupMenu += ShowMenu; + SetIdleState (); ShowState (); } - private void CreateAnimationFrames () + private Gdk.Pixbuf [] CreateAnimationFrames () { - FrameNumber = 0; - - AnimationFrames = new Gdk.Pixbuf [5]; + Gdk.Pixbuf [] animation_frames = new Gdk.Pixbuf [5]; Gdk.Pixbuf frames_pixbuf = SparkleHelpers.GetIcon ("process-syncing-sparkleshare", 24); - for (int i = 0; i < AnimationFrames.Length; i++) - AnimationFrames [i] = new Gdk.Pixbuf (frames_pixbuf, (i * 24), 0, 24, 24); + for (int i = 0; i < animation_frames.Length; i++) + animation_frames [i] = new Gdk.Pixbuf (frames_pixbuf, (i * 24), 0, 24, 24); + + return animation_frames; } // Creates the timer that handles the syncing animation - private void CreateTimer () + private Timer CreateTimer () { - Timer = new Timer () { + Timer timer = new Timer () { Interval = 35 }; - Timer.Elapsed += delegate { + timer.Elapsed += delegate { if (FrameNumber < AnimationFrames.Length - 1) FrameNumber++; @@ -100,6 +108,8 @@ namespace SparkleShare { }; + return timer; + } @@ -108,8 +118,8 @@ namespace SparkleShare { return delegate { - SparkleWindow SparkleWindow = new SparkleWindow (repo); - SparkleWindow.ShowAll (); + SparkleLog log = new SparkleLog (repo); + log.ShowAll (); }; @@ -121,11 +131,18 @@ namespace SparkleShare { double size = 0; - FileInfo [] files = parent.GetFiles(); + if (parent.Name.Equals ("rebase-apply")) + return 0; + + foreach (FileInfo file in parent.GetFiles()) { + + if (!file.Exists) + return 0; - foreach (FileInfo file in files) size += file.Length; + } + foreach (DirectoryInfo directory in parent.GetDirectories()) size += GetFolderSize (directory); @@ -134,19 +151,29 @@ namespace SparkleShare { } - private string GetSizeFormat (double byte_count) + private void UpdateFolderSize () + { + + FolderSize = GetFolderSize (new DirectoryInfo (SparklePaths.SparklePath)); + + } + + + // Format a file size nicely. + // Example: 1048576 becomes "1 ᴍʙ" + private string FormatFileSize (double byte_count) { string size = ""; if (byte_count >= 1099511627776) - size = String.Format ("{0:##.##}", Math.Round (byte_count / 1099511627776, 1)) + " ᴛʙ"; + size = String.Format (_("{0:##.##} ᴛʙ"), Math.Round (byte_count / 1099511627776, 1)); else if (byte_count >= 1073741824) - size = String.Format ("{0:##.##}", Math.Round (byte_count / 1073741824, 1)) + " ɢʙ"; + size = String.Format (_("{0:##.##} ɢʙ"), Math.Round (byte_count / 1073741824, 1)); else if (byte_count >= 1048576) - size = String.Format ("{0:##.##}", Math.Round (byte_count / 1048576, 1)) + " ᴍʙ"; + size = String.Format (_("{0:##.##} ᴍʙ"), Math.Round (byte_count / 1048576, 1)); else if (byte_count >= 1024) - size = String.Format ("{0:##.##}", Math.Round (byte_count / 1024, 1)) + " ᴋʙ"; + size = String.Format (_("{0:##.##} ᴋʙ"), Math.Round (byte_count / 1024, 1)); else size = byte_count.ToString () + " bytes"; @@ -216,8 +243,7 @@ namespace SparkleShare { add_item.Activated += delegate { SparkleIntro intro = new SparkleIntro (); - intro.ShowStepTwo (true); - intro.ShowAll (); + intro.ShowServerForm (true); }; @@ -246,7 +272,7 @@ namespace SparkleShare { Menu.Add (new SeparatorMenuItem ()); - MenuItem about_item = new MenuItem (_("About")); + MenuItem about_item = new MenuItem (_("Visit Website")); about_item.Activated += delegate { @@ -295,6 +321,14 @@ namespace SparkleShare { public void ShowState () { + UpdateFolderSize (); + + if (SyncingReposCount < 0) + SyncingReposCount = 0; + + if (SyncingReposCount > SparkleUI.Repositories.Count) + SyncingReposCount = SparkleUI.Repositories.Count; + if (SyncingReposCount > 0) SetSyncingState (); else @@ -302,7 +336,7 @@ namespace SparkleShare { UpdateStatusMenuItem (); - Console.WriteLine ("Number of repos syncing: " + SyncingReposCount); + SparkleHelpers.DebugInfo ("Status", "Number of repos syncing: " + SyncingReposCount); } @@ -313,8 +347,8 @@ namespace SparkleShare { Timer.Stop (); - Pixbuf = SparkleHelpers.GetIcon ("folder-sparkleshare", 24); - StateText = _("Up to date") + " (" + GetSizeFormat (FolderSize) + ")"; + Application.Invoke (delegate { SetPixbuf (AnimationFrames [0]); }); + StateText = _("Up to date") + " (" + FormatFileSize (FolderSize) + ")"; } diff --git a/SparkleShare/SparkleUI.cs b/SparkleShare/SparkleUI.cs index 920a219a..7d10a66a 100644 --- a/SparkleShare/SparkleUI.cs +++ b/SparkleShare/SparkleUI.cs @@ -23,6 +23,8 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Runtime.InteropServices; +using System.Text; namespace SparkleShare { @@ -47,6 +49,10 @@ namespace SparkleShare { BusG.Init (); Gtk.Application.Init (); +// SparkleInvitation i = new SparkleInvitation ("/home/hbons/SparkleShare/sparkleshare.invitation"); + + SetProcessName ("sparkleshare"); + Repositories = new List (); Process = new Process () { @@ -75,24 +81,21 @@ namespace SparkleShare { Filter = "*" }; - watcher.Deleted += delegate { + watcher.Deleted += delegate (object o, FileSystemEventArgs args) { - foreach (SparkleRepo repo in Repositories) - repo.Stop (); - - Application.Invoke (delegate { UpdateRepositories (); } ); + RemoveRepository (args.FullPath); }; - watcher.Created += delegate { + watcher.Created += delegate (object o, FileSystemEventArgs args) { - Application.Invoke (delegate {UpdateRepositories (); } ); + AddRepository (args.FullPath); }; CreateConfigurationFolders (); - UpdateRepositories (); + PopulateRepositories (); // Don't create the window and status // icon when --disable-gui was given @@ -109,6 +112,7 @@ namespace SparkleShare { NotificationIcon = new SparkleStatusIcon (); } + } @@ -323,57 +327,81 @@ namespace SparkleShare { } + public 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); }); + }; + + repo.Commited += delegate (object o, SparkleEventArgs args) { + Application.Invoke (delegate { CheckForUnicorns (args.Message); }); + }; + + repo.FetchingStarted += delegate { + Application.Invoke (UpdateStatusIconToSyncing); + }; + + repo.FetchingFinished += delegate { + Application.Invoke (UpdateStatusIconToIdle); + }; + + repo.PushingStarted += delegate { + Application.Invoke (UpdateStatusIconToSyncing); + }; + + repo.PushingFinished += delegate { + Application.Invoke (UpdateStatusIconToIdle); + }; + + repo.ConflictDetected += delegate { + Application.Invoke (ShowConflictBubble); + }; + + Repositories.Add (repo); + + if (NotificationIcon != null) + Application.Invoke (delegate { NotificationIcon.CreateMenu (); }); + + } + + + public void RemoveRepository (string folder_path) { + + string repo_name = Path.GetFileName (folder_path); + + foreach (SparkleRepo repo in Repositories) { + + if (repo.Name.Equals (repo_name)) { + + repo.Stop (); + Repositories.Remove (repo); + break; + + } + + } + + if (NotificationIcon != null) + Application.Invoke (delegate { NotificationIcon.CreateMenu (); }); + + } + + // Updates the list of repositories with all the // folders in the SparkleShare folder - public void UpdateRepositories () + public void PopulateRepositories () { Repositories = new List (); - foreach (string folder in Directory.GetDirectories (SparklePaths.SparklePath)) { - - // Check if the folder is a git repo - if (Directory.Exists (SparkleHelpers.CombineMore (folder, ".git"))) { - - SparkleRepo repo = new SparkleRepo (folder); - - repo.NewCommit += delegate (object o, NewCommitArgs args) { - Application.Invoke (delegate { ShowNewCommitBubble (args.Author, args.Email, args.Message); }); - }; - - repo.Commited += delegate (object o, SparkleEventArgs args) { - Application.Invoke (delegate { CheckForUnicorns (args.Message); }); - }; - - repo.FetchingStarted += delegate { - Application.Invoke (UpdateStatusIconToSyncing); - }; - - repo.FetchingFinished += delegate { - Application.Invoke (UpdateStatusIconToIdle); - }; - - repo.PushingStarted += delegate { - Application.Invoke (UpdateStatusIconToSyncing); - }; - - repo.PushingFinished += delegate { - Application.Invoke (UpdateStatusIconToIdle); - }; - - repo.ConflictDetected += delegate { - Application.Invoke (ShowConflictBubble); - }; - - Repositories.Add (repo); - - } - - // Update the list in the statusicon - if (NotificationIcon != null) - NotificationIcon.CreateMenu (); - - } + foreach (string folder_path in Directory.GetDirectories (SparklePaths.SparklePath)) + AddRepository (folder_path); } @@ -397,6 +425,27 @@ namespace SparkleShare { } + + [DllImport ("libc")] + private static extern int prctl (int option, byte [] arg2, IntPtr arg3, IntPtr arg4, IntPtr arg5); + + + 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) {} + + } + } } diff --git a/SparkleShare/SparkleWindow.cs b/SparkleShare/SparkleWindow.cs index f3de3478..2aefd828 100644 --- a/SparkleShare/SparkleWindow.cs +++ b/SparkleShare/SparkleWindow.cs @@ -28,264 +28,89 @@ namespace SparkleShare { public class SparkleWindow : Window { - // Short alias for the translations - public static string _ (string s) - { - return Catalog.GetString (s); - } + private HBox HBox; + private VBox VBox; + private VBox Wrapper; + private HButtonBox Buttons; - private SparkleRepo SparkleRepo; - private VBox LayoutVertical; - private ScrolledWindow ScrolledWindow; - public SparkleWindow (SparkleRepo sparkle_repo) : base ("") + public SparkleWindow () : base ("") { - SparkleRepo = sparkle_repo; - SetSizeRequest (540, 640); - SetPosition (WindowPosition.Center); - BorderWidth = 12; - - // TRANSLATORS: {0} is a folder name, and {1} is a server address - Title = String.Format(_("Recent Events in ‘{0}’"), SparkleRepo.Name); - IconName = "folder"; + BorderWidth = 0; + IconName = "folder-sparkleshare"; + Resizable = true; + WindowPosition = WindowPosition.Center; - LayoutVertical = new VBox (false, 12); + SetDefaultSize (640, 480); - LayoutVertical.PackStart (CreateEventLog (), true, true, 0); + Buttons = CreateButtonBox (); - HButtonBox dialog_buttons = new HButtonBox { - Layout = ButtonBoxStyle.Edge, - BorderWidth = 0 - }; + HBox = new HBox (false, 6); - Button open_folder_button = new Button (_("Open Folder")); - open_folder_button.Clicked += delegate (object o, EventArgs args) { - Process process = new Process (); - process.StartInfo.FileName = "xdg-open"; - string path = SparkleHelpers.CombineMore (SparklePaths.SparklePath, - SparkleRepo.Name); - process.StartInfo.Arguments = path.Replace(" ", "\\ "); - process.Start (); - Destroy (); + string image_path = SparkleHelpers.CombineMore (Defines.PREFIX, "share", "pixmaps", "side-splash.png"); + Image side_splash = new Image (image_path); + + VBox = new VBox (false, 0); + + Wrapper = new VBox (false, 0) { + BorderWidth = 30 }; - Button close_button = new Button (Stock.Close); - close_button.Clicked += delegate (object o, EventArgs args) { - Destroy (); - }; + VBox.PackStart (Wrapper, true, true, 0); + VBox.PackStart (Buttons, false, false, 0); - dialog_buttons.Add (open_folder_button); - dialog_buttons.Add (close_button); + HBox.PackStart (side_splash, false, false, 0); + HBox.PackStart (VBox, true, true, 0); - LayoutVertical.PackStart (dialog_buttons, false, false, 0); - - Add (LayoutVertical); + base.Add (HBox); } - public void UpdateEventLog () + private HButtonBox CreateButtonBox () { - LayoutVertical.Remove (ScrolledWindow); - ScrolledWindow = CreateEventLog (); - LayoutVertical.PackStart (ScrolledWindow, true, true, 0); - LayoutVertical.ReorderChild (ScrolledWindow, 0); + return new HButtonBox () { + BorderWidth = 12, + Layout = ButtonBoxStyle.End, + Spacing = 6 + }; + + } + + + public void AddButton (Button button) + { + + Buttons.Add (button); ShowAll (); } - private ScrolledWindow CreateEventLog () + new public void Add (Widget widget) { - int number_of_events = 50; - - Process process = new Process (); - process.EnableRaisingEvents = true; - process.StartInfo.RedirectStandardOutput = true; - process.StartInfo.UseShellExecute = false; - process.StartInfo.WorkingDirectory = SparkleRepo.LocalPath; - process.StartInfo.FileName = "git"; - process.StartInfo.Arguments = "log --format=\"%at☃%an☃%ae☃%s\" -" + number_of_events; - - process.Start (); - - string output = process.StandardOutput.ReadToEnd ().Trim (); - - output = output.TrimStart ("\n".ToCharArray ()); - string [] lines = Regex.Split (output, "\n"); - int linesLength = lines.Length; - if (output == "") - linesLength = 0; - - // Sort by time and get the last 25 - Array.Sort (lines); - Array.Reverse (lines); - - List activity_days = new List (); - - for (int i = 0; i < number_of_events && i < linesLength; i++) { - - string line = lines [i]; - - // Look for the snowman! - string [] parts = Regex.Split (line, "☃"); - - int unix_timestamp = int.Parse (parts [0]); - string user_name = parts [1]; - string user_email = parts [2]; - string message = parts [3]; - - DateTime date_time = UnixTimestampToDateTime (unix_timestamp); - - message = message.Replace ("/", " ‣ "); - message = message.Replace ("\n", " "); - - ChangeSet change_set = new ChangeSet (user_name, user_email, message, date_time); - - bool change_set_inserted = false; - foreach (ActivityDay stored_activity_day in activity_days) { - - if (stored_activity_day.DateTime.Year == change_set.DateTime.Year && - stored_activity_day.DateTime.Month == change_set.DateTime.Month && - stored_activity_day.DateTime.Day == change_set.DateTime.Day) { - - stored_activity_day.Add (change_set); - change_set_inserted = true; - break; - - } - - } - - if (!change_set_inserted) { - - ActivityDay activity_day = new ActivityDay (change_set.DateTime); - activity_day.Add (change_set); - activity_days.Add (activity_day); - - } - - } - - - VBox layout_vertical = new VBox (false, 0); - - foreach (ActivityDay activity_day in activity_days) { - - TreeIter iter = new TreeIter (); - ListStore list_store = new ListStore (typeof (Gdk.Pixbuf), - typeof (string), - typeof (string)); - - foreach (ChangeSet change_set in activity_day) { - - iter = list_store.Append (); - list_store.SetValue (iter, 0, SparkleHelpers.GetAvatar (change_set.UserEmail , 32)); - list_store.SetValue (iter, 1, "" + change_set.UserName + "\n" + - "" + change_set.Message + ""); - list_store.SetValue (iter, 2, change_set.UserEmail); - - } - - Label date_label = new Label ("") { - UseMarkup = true, - Xalign = 0, - Xpad = 9, - Ypad = 9 - }; - - DateTime today = DateTime.Now; - DateTime yesterday = DateTime.Now.AddDays (-1); - - if (today.Day == activity_day.DateTime.Day && - today.Month == activity_day.DateTime.Month && - today.Year == activity_day.DateTime.Year) { - - date_label.Markup = "Today"; - - } else if (yesterday.Day == activity_day.DateTime.Day && - yesterday.Month == activity_day.DateTime.Month && - yesterday.Year == activity_day.DateTime.Year) { - - date_label.Markup = "Yesterday"; - - } else { - - date_label.Markup = "" + activity_day.DateTime.ToString ("ddd MMM d, yyyy") + ""; - - } - - layout_vertical.PackStart (date_label, false, false, 0); - - IconView icon_view = new IconView (list_store) { - ItemWidth = 470, - MarkupColumn = 1, - Orientation = Orientation.Horizontal, - PixbufColumn = 0, - Spacing = 9 - }; - - icon_view.SelectionChanged += delegate { - icon_view.UnselectAll (); - }; - - layout_vertical.PackStart (icon_view, false, false, 0); - - } - - ScrolledWindow = new ScrolledWindow (); - ScrolledWindow.ShadowType = ShadowType.None; - ScrolledWindow.AddWithViewport (layout_vertical); - - return ScrolledWindow; + Wrapper.PackStart (widget, true, true, 0); + ShowAll (); } - // Converts a UNIX timestamp to a more usable time object - public DateTime UnixTimestampToDateTime (int timestamp) + public void Reset () { - DateTime unix_epoch = new DateTime (1970, 1, 1, 0, 0, 0, 0); - return unix_epoch.AddSeconds (timestamp); + + if (Wrapper.Children.Length > 0) + Wrapper.Remove (Wrapper.Children [0]); + + foreach (Button button in Buttons) + Buttons.Remove (button); + + ShowAll (); + } - - } - - - public class ActivityDay : List - { - - public DateTime DateTime; - - public ActivityDay (DateTime date_time) - { - DateTime = date_time; - DateTime = new DateTime (DateTime.Year, DateTime.Month, DateTime.Day); - } - - } - - - public class ChangeSet - { - - public string UserName; - public string UserEmail; - public string Message; - public DateTime DateTime; - - public ChangeSet (string user_name, string user_email, string message, DateTime date_time) - { - UserName = user_name; - UserEmail = user_email; - Message = message; - DateTime = date_time; - } - } } diff --git a/SparkleShare/sparkleshare.in b/SparkleShare/sparkleshare.in index 6a5e559d..251b65ee 100644 --- a/SparkleShare/sparkleshare.in +++ b/SparkleShare/sparkleshare.in @@ -2,69 +2,59 @@ pidfile=/tmp/sparkleshare/sparkleshare.pid -# Create a directory to save the pid to +start() { + if [ -e "${pidfile}" ]; then + sparklepid=`cat ${pidfile}` + if [ -n "`ps -p ${sparklepid} | grep ${sparklepid}`" ]; then + echo "SparkleShare is already running." + exit 0 + else + echo "SparkleShare stale pid file found, starting a new instance." + rm -f $pidfile + fi + fi + + echo -n "Starting SparkleShare... " + mkdir -p /tmp/sparkleshare/ + # Start SparkleShare in the background and save the pid + mono "@expanded_libdir@/@PACKAGE@/SparkleShare.exe" $2 & + echo $! > ${pidfile} + echo "Done." +} + +stop() { + if [ -e "${pidfile}" ]; then + sparklepid=`cat ${pidfile}` + if [ -n "`ps -p ${sparklepid} | grep ${sparklepid}`" ]; then + echo -n "Stopping SparkleShare... " + kill ${sparklepid} + rm -f ${pidfile} + echo "Done." + else + echo "SparkleShare is not running, removing stale pid file." + rm -f ${pidfile} + fi + else + echo "SparkleShare is not running." + fi +} + case $1 in - start) - if [ -e "${pidfile}" ]; then - sparklepid=`cat ${pidfile}` - if [ -n "`ps -p ${sparklepid} | grep ${sparklepid}`" ] - then - echo "SparkleShare is already running" - exit 0 - else - echo "SparkleShare stale pid file found, starting a new instance" - rm -f $pidfile - fi - fi - - echo -n "Starting SparkleShare..." - mkdir -p /tmp/sparkleshare/ - # Start SparkleShare in the background and save the pid - mono "@expanded_libdir@/@PACKAGE@/SparkleShare.exe" $2 & - PID=$! - echo $PID > /tmp/sparkleshare/sparkleshare.pid - echo " Done." - ;; - - stop) - if [ -e "/tmp/sparkleshare/sparkleshare.pid" ]; then - echo -n "Stopping SparkleShare..." - kill `cat /tmp/sparkleshare/sparkleshare.pid` - rm -f /tmp/sparkleshare/sparkleshare.pid - echo " Done." - else - echo "SparkleShare isn't running." - fi - ;; - - restart) - if [ -e "/tmp/sparkleshare/sparkleshare.pid" ]; then - echo -n "Stopping SparkleShare..." - kill `cat /tmp/sparkleshare/sparkleshare.pid` - rm -f /tmp/sparkleshare/sparkleshare.pid - echo " Done." - else - echo "SparkleShare isn't running." - fi - - if [ -e "/tmp/sparkleshare/sparkleshare.pid" ]; then - echo "SparkleShare is already running." - else - echo -n "Starting SparkleShare..." - - # Start SparkleShare in the background and save the pid - mono "@expanded_libdir@/@PACKAGE@/SparkleShare.exe" $2 & - PID=$! - echo $PID > /tmp/sparkleshare/sparkleshare.pid - echo " Done." - fi - ;; - - --help | help) - mono "@expanded_libdir@/@PACKAGE@/SparkleShare.exe" --help - ;; - + start|--start) + start + ;; + stop|--stop) + stop + ;; + restart|--restart) + stop + start + ;; + help|--help) + mono "@expanded_libdir@/@PACKAGE@/SparkleShare.exe" --help + ;; *) - echo "Usage: sparkleshare {start|stop|restart|help}" - ;; + echo "Usage: sparkleshare {start|stop|restart|help}" + ;; esac + diff --git a/data/gnome-design.sparkleshare-invitation b/data/gnome-design.sparkleshare-invitation new file mode 100644 index 00000000..0f237b93 --- /dev/null +++ b/data/gnome-design.sparkleshare-invitation @@ -0,0 +1,7 @@ + + + + + + + diff --git a/data/sparkleshare.invitation b/data/sparkleshare.invitation new file mode 100644 index 00000000..33b48b43 --- /dev/null +++ b/data/sparkleshare.invitation @@ -0,0 +1,6 @@ + + + git.gnome.org + gnome-design + a22bc6f4b9ffe8e5acd4be0838d41aa10a1187dd +