Merge branch 'master' into translations

This commit is contained in:
Hylke Bons 2010-08-14 16:06:53 +01:00
commit 9c0539d935
14 changed files with 1093 additions and 870 deletions

View file

@ -13,6 +13,7 @@ Contributors:
Jakub Steiner <jimmac@novell.com>
Lapo Calamandrei <calamandrei@gmail.com>
Łukasz Jernaś <deejay1@srem.org>
Michael Monreal <michael.monreal@gmail.com>
Oleg Khlystov <pktfag@gmail.com>
Philipp Gildein <rmbl@openspeak-project.org>
Ruben Vermeersch <rubenv@gnome.org>

View file

@ -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)) {

View file

@ -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 ()
{

View file

@ -11,6 +11,8 @@ SOURCES = \
SparkleBubble.cs \
SparkleEntry.cs \
SparkleIntro.cs \
SparkleInvitation.cs \
SparkleLog.cs \
SparkleShare.cs \
SparkleSpinner.cs \
SparkleStatusIcon.cs \

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,43 @@
// SparkleShare, an instant update workflow to Git.
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.IO;
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;
}
}
}

318
SparkleShare/SparkleLog.cs Normal file
View file

@ -0,0 +1,318 @@
// SparkleShare, an instant update workflow to Git.
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using 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 <ActivityDay> activity_days = new List <ActivityDay> ();
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, "<b>" + change_set.UserName + "</b>\n" +
"<span fgcolor='" + secondary_text_color +"'>" +
change_set.Message + "\n" +
"<small>" + change_set.DateTime.ToString ("HH:mm") + "</small>" +
"</span>");
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 = "<b>Today</b>";
} else if (yesterday.Day == activity_day.DateTime.Day &&
yesterday.Month == activity_day.DateTime.Month &&
yesterday.Year == activity_day.DateTime.Year) {
date_label.Markup = "<b>Yesterday</b>";
} else {
date_label.Markup = "<b>" + activity_day.DateTime.ToString ("ddd MMM d, yyyy") + "</b>";
}
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 <ChangeSet>
{
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;
}
}
}

View file

@ -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));
}
}

View file

@ -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) + ")";
}

View file

@ -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 <SparkleRepo> ();
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 <SparkleRepo> ();
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) {}
}
}
}

View file

@ -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 <ActivityDay> activity_days = new List <ActivityDay> ();
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, "<b>" + change_set.UserName + "</b>\n" +
"<span fgcolor='#777'>" + change_set.Message + "</span>");
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 = "<b>Today</b>";
} else if (yesterday.Day == activity_day.DateTime.Day &&
yesterday.Month == activity_day.DateTime.Month &&
yesterday.Year == activity_day.DateTime.Year) {
date_label.Markup = "<b>Yesterday</b>";
} else {
date_label.Markup = "<b>" + activity_day.DateTime.ToString ("ddd MMM d, yyyy") + "</b>";
}
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 <ChangeSet>
{
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;
}
}
}

View file

@ -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

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<sparkleshare_invitation>
<server="git.gnome.org" />
<repository="gnome-design" />
<key="a22bc6f4b9ffe8e5acd4be0838d41aa10a1187dd" />
<email="hylkebons@gmail.com" />
</sparkleshare_invitation>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<sparkleshare_invitation>
<server>git.gnome.org</server>
<repository>gnome-design</repository>
<key>a22bc6f4b9ffe8e5acd4be0838d41aa10a1187dd</key>
</sparkleshare_invitation>