Merge branch 'osx'

This commit is contained in:
Hylke Bons 2011-03-02 00:24:47 +00:00
commit 83178e5fa0
49 changed files with 5489 additions and 2493 deletions

6
.gitmodules vendored
View file

@ -4,9 +4,3 @@
[submodule "GitSharp"]
path = GitSharp
url = http://github.com/henon/GitSharp.git
[submodule "MonoMac"]
path = MonoMac
url = https://github.com/mono/monomac.git
[submodule "MacCore"]
path = MacCore
url = https://github.com/mono/maccore.git

@ -1 +0,0 @@
Subproject commit da3e017ccda1ce1c21777246151a5d7f21a3ffa5

@ -1 +0,0 @@
Subproject commit 433483a484b8637b379265c38ebab643a8cfcc6a

8
NEWS
View file

@ -1,3 +1,11 @@
0.2-beta2 for Mac (Sat Feb, 2011):
Hylke: Mac version! Massive restructure of the code to an MVC-like model
to make building different front-ends easier. Ported the event logs to
Webkit, so users can style it to their liking. It also reduces the amount
of UI-porting that needs to be done between toolkits.
0.2-beta1 (Sun Sep 5, 2010):
Hylke: Aside from the usual bug fixes and behind the scenes work I mainly

50
README
View file

@ -1,4 +1,4 @@
SparkleShare 0.2 Beta 1
SparkleShare 0.2 Beta 2
=======================
SparkleShare is a file sharing and collaboration tool inspired by Dropbox.
@ -25,8 +25,8 @@ to change and redistribute it under certain conditions. For more information
see the LICENSE file or visit http://www.gnu.org/licenses/gpl-3.0.html
Run
===
Run on Linux:
=============
SparkleShare currently requires:
@ -43,7 +43,7 @@ SparkleShare currently requires:
- webkitgtk
- webkit-sharp
Run the service:
Run the service, either click the SparkleShare launcher or:
$ sparkleshare start
@ -62,8 +62,8 @@ Note:
by hand.
Build
=====
Build on Linux:
===============
To build SparkleShare you need:
@ -97,13 +97,40 @@ Note:
Use './configure --prefix=/usr' if you want the Nautilus extension to work.
Build on OSX:
Run on Mac:
===========
You will need to have the Mac version of git installed.
SparkleShare will look for git in /usr/bin, so you may need to create a symbolic
link to git, depending on where it was installed:
$ sudo ln -s /path/to/your/git /usr/bin/git
Now just double-click the SparkleShare.app.
Build on Mac:
=============
Get the Mono Framework, Monodevelop, and MacPorts.
Install the Mono Framework, Monodevelop (plus the MonoMac plugin), and MacPorts.
Install git-core, automake and intltool using 'port install'.
Make sure that git or a symbolic link to git is in /usr/bin.
Note:
You may need to adjust some environment variables to find mono:
$ export PATH=/Library/Frameworks/Mono.framework/Versions/Current/bin:$PATH
$ export PKG_CONFIG=/Library/Frameworks/Mono.framework/Versions/Current/bin/pkg-config
$ export PKG_CONFIG_PATH=/Library/Frameworks/Mono.framework/Versions/Current/lib/pkgconfig
$ ./autogen.sh
The last step will give you some errors, but you only need the libraries to be compiled.
Open 'SparkleShare/Mac/SparkleShare.sln' in MonoDevelop and start the build.
Frequently Asked Question
=========================
@ -118,18 +145,19 @@ Official website:
http://www.sparkleshare.org/
Project page:
http://github.com/SparkleShare
http://github.com/SparkleShare/
IRC Channel:
#sparkleshare on irc.gnome.org
Wiki:
http://github.com/hbons/SparkleShare/wiki
http://github.com/hbons/SparkleShare/wiki/
Issue tracker:
http://github.com/hbons/SparkleShare/issues
http://github.com/hbons/SparkleShare/issues/
Translation project:
http://www.transifex.net/projects/p/sparkleshare/
Now have fun and create cool things together! :)

View file

@ -8,6 +8,7 @@ SOURCES = \
SparkleCommit.cs \
SparkleEvents.cs \
SparkleFetcher.cs \
SparkleGit.cs \
SparkleHelpers.cs \
SparkleListener.cs \
SparkleOptions.cs \

View file

@ -130,21 +130,42 @@ namespace SparkleLib {
private void InstallExcludeRules ()
{
string exlude_rules_file_path = SparkleHelpers.CombineMore (TargetFolder, ".git", "info", "exclude");
string exlude_rules_file_path = SparkleHelpers.CombineMore
(TargetFolder, ".git", "info", "exclude");
TextWriter writer = new StreamWriter (exlude_rules_file_path);
// Ignore gedit swap files
// gedit and emacs
writer.WriteLine ("*~");
// Ignore vi swap files
writer.WriteLine (".*.sw?");
// Ignore OSX's invisible directories
writer.WriteLine (".DS_Store");
// vi(m)
writer.WriteLine (".*.sw[a-z]");
writer.WriteLine ("*.un~");
writer.WriteLine ("*.swp");
writer.WriteLine ("*.swo");
// Ignore Windows cache files
// KDE
writer.WriteLine (".directory");
// Mac OSX
writer.WriteLine (".DS_Store");
writer.WriteLine ("Icon?");
writer.WriteLine ("._*");
writer.WriteLine (".Spotlight-V100");
writer.WriteLine (".Trashes");
// Windows
writer.WriteLine ("Thumbs.db");
writer.WriteLine ("Desktop.ini");
// CVS
writer.WriteLine ("*/CVS/*");
writer.WriteLine (".cvsignore");
writer.WriteLine ("*/.cvsignore");
// Subversion
writer.WriteLine ("/.svn/*");
writer.WriteLine ("*/.svn/*");
writer.Close ();

View file

@ -14,52 +14,27 @@
// 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.Collections.Generic;
using System.Drawing;
using System.Timers;
using MonoMac.Foundation;
using MonoMac.AppKit;
using MonoMac.ObjCRuntime;
using MonoMac.WebKit;
using System.Diagnostics;
namespace SparkleShare {
namespace SparkleLib {
public partial class AppDelegate : NSApplicationDelegate {
// Workaround to be able to work with SparkleUI as the main class
}
public class SparkleGit : Process {
public class SparkleUI : AppDelegate
{
public static SparkleStatusIcon StatusIcon;
public static List <SparkleLog> OpenLogs;
public SparkleUI ()
{
NSApplication.Init ();
NSApplication.SharedApplication.ApplicationIconImage
= NSImage.ImageNamed ("sparkleshare.icns");
OpenLogs = new List <SparkleLog> ();
StatusIcon = new SparkleStatusIcon ();
}
public void Run ()
public SparkleGit (string path, string args) : base ()
{
NSApplication.Main (new string [0]);
EnableRaisingEvents = true;
StartInfo.FileName = SparklePaths.GitPath;
StartInfo.Arguments = args;
StartInfo.RedirectStandardOutput = true;
StartInfo.UseShellExecute = false;
StartInfo.WorkingDirectory = path;
}
}
}
}

View file

@ -76,6 +76,7 @@
<Compile Include="SparkleOptions.cs" />
<Compile Include="SparkleCommit.cs" />
<Compile Include="SparkleListener.cs" />
<Compile Include="SparkleGit.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>

View file

@ -14,62 +14,60 @@
// 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 Meebey.SmartIrc4net;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Security.Cryptography;
namespace SparkleLib {
// A persistent connection to the server that
// listens for change notifications
public class SparkleListener
{
public class SparkleListener {
// FIXME: The IrcClient is a public property because
// extending it causes crashes
public IrcClient Client;
private Thread Thread;
public readonly string Server;
public readonly string FallbackServer;
public readonly string Channel;
public readonly string Nick;
public SparkleListener (string server, string channel, string nick)
public SparkleListener (string server, string folder_name, string user_email)
{
Server = server;
Channel = channel;
Nick = nick;
if (!Nick.Equals (""))
Nick = nick.Replace ("@", "_at_").Replace (".", "_dot_");
// This is SparkleShare's centralized notification service.
// Don't worry, we only use this server as a backup if you
// don't have your own. All data needed to connect is hashed and
// we don't store any personal information ever.
// Server = "204.62.14.135";
if (!user_email.Equals ("") && user_email != null)
Nick = GetSHA1 (folder_name + user_email + "sparkles");
else
Nick = "anonymous";
Nick = GetSHA1 (DateTime.Now.ToString () + "sparkles");
// Keep the nick short
if (Nick.Length > 9)
Nick = Nick.Substring (0, 9);
// TODO: Remove these hardcoded values
Nick = "s" + Nick.Substring (0, 7);
// Channel = "#" + GetSHA1 (server + folder_name);
Server = "irc.gnome.org";
Channel = "#sparkletest";
Server = "irc.gnome.org";
Client = new IrcClient () {
PingTimeout = 120,
SocketSendTimeout = 120,
SocketReceiveTimeout = 120,
AutoRetry = true,
AutoReconnect = true,
AutoRejoin = true
PingTimeout = 180,
PingInterval = 90
};
}
// Starts a new thread and listens to the channel
public void ListenForChanges ()
public void Listen ()
{
Thread = new Thread (
@ -102,6 +100,14 @@ namespace SparkleLib {
Thread.Start ();
}
public void Announce (string message)
{
Client.SendMessage (SendType.Message, Channel, message);
}
// Frees all resources for this Listener
@ -113,6 +119,16 @@ namespace SparkleLib {
}
// Creates an SHA-1 hash of input
private static string GetSHA1 (string s)
{
SHA1 sha1 = new SHA1CryptoServiceProvider ();
Byte[] bytes = ASCIIEncoding.Default.GetBytes (s);
Byte[] encoded_bytes = sha1.ComputeHash (bytes);
return BitConverter.ToString (encoded_bytes).ToLower ().Replace ("-", "");
}
}
}

View file

@ -24,7 +24,7 @@ namespace SparkleLib {
public static class SparklePaths
{
public static string GitPath = "/usr/bin/git"; // TODO: Don't hardcode this
public static string GitPath = SystemGitPath;
public static string HomePath = new UnixUserInfo (UnixEnvironment.UserName).HomeDirectory;
@ -44,24 +44,37 @@ namespace SparkleLib {
"icons");
private static string GetGitPath ()
private static string SystemGitPath
{
Process process = new Process ();
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = "which";
process.StartInfo.Arguments = "git";
process.Start ();
string git_path = process.StandardOutput.ReadToEnd ().Trim ();
get {
if (!string.IsNullOrEmpty (git_path))
return git_path;
else
return null;
Process process = new Process ();
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = "which";
process.StartInfo.Arguments = "git";
process.Start ();
string git_path = process.StandardOutput.ReadToEnd ();
git_path = git_path.Trim ();
if (!string.IsNullOrEmpty (git_path)) {
return git_path;
} else {
Console.WriteLine ("Sorry, SparkleShare needs Git to run, but it wasn't found.");
Environment.Exit (-1);
return null;
}
}
}
}

View file

@ -14,6 +14,7 @@
// 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 GitSharp;
using GitSharp.Commands;
using GitSharp.Core.Transport;
@ -30,15 +31,15 @@ namespace SparkleLib {
public class SparkleRepo : Repository {
private Process Process;
private Timer RemoteTimer;
private Timer LocalTimer;
private FileSystemWatcher Watcher;
private bool HasChanged;
private DateTime LastChange;
private System.Object ChangeLock;
private int FetchRequests;
private SparkleListener Listener;
private bool HasChanged;
private List <double> SizeBuffer;
/// <summary>
/// The folder name the repository resides in locally
@ -251,37 +252,32 @@ namespace SparkleLib {
public SparkleRepo (string path) : base (path)
{
LocalPath = path;
Name = Path.GetFileName (LocalPath);
LocalPath = path;
Name = Path.GetFileName (LocalPath);
Process = new Process () {
EnableRaisingEvents = true
};
Process.StartInfo.FileName = SparklePaths.GitPath;
Process.StartInfo.RedirectStandardOutput = true;
Process.StartInfo.UseShellExecute = false;
Process.StartInfo.WorkingDirectory = LocalPath;
RemoteName = Path.GetFileNameWithoutExtension (RemoteOriginUrl);
RemoteOriginUrl = Config ["remote.origin.url"];
Domain = GetDomain (RemoteOriginUrl);
Description = GetDescription ();
UserName = Config ["user.name"];
UserEmail = Config ["user.email"];
RemoteName = Path.GetFileNameWithoutExtension (RemoteOriginUrl);
RemoteOriginUrl = Config ["remote.origin.url"];
Domain = GetDomain (RemoteOriginUrl);
Description = GetDescription ();
UserName = Config ["user.name"];
UserEmail = Config ["user.email"];
if (Head.CurrentCommit == null)
_CurrentHash = null;
_CurrentHash = null;
else
_CurrentHash = Head.CurrentCommit.Hash;
_CurrentHash = Head.CurrentCommit.Hash;
_IsSyncing = false;
_IsBuffering = false;
_IsPolling = true;
_IsFetching = false;
_IsPushing = false;
_ServerOnline = true;
_IsSyncing = false;
_IsBuffering = false;
_IsPolling = true;
_IsFetching = false;
_IsPushing = false;
_ServerOnline = true;
HasChanged = false;
ChangeLock = new Object ();
FetchRequests = 0;
string unsynced_file_path = SparkleHelpers.CombineMore (LocalPath ,
".git", "has_unsynced_changes");
@ -295,10 +291,6 @@ namespace SparkleLib {
if (_CurrentHash == null)
CreateInitialCommit ();
HasChanged = false;
ChangeLock = new System.Object ();
FetchRequests = 0;
// Watch the repository's folder
Watcher = new FileSystemWatcher (LocalPath) {
@ -312,35 +304,41 @@ namespace SparkleLib {
Watcher.Deleted += new FileSystemEventHandler (OnFileActivity);
Watcher.Renamed += new RenamedEventHandler (OnFileActivity);
// Fetch remote changes every minute
// Listen to the irc channel on the server...
Listener = new SparkleListener (Domain, "#" + RemoteName, UserEmail);
// ...fetch remote changes every 60 seconds if that fails
RemoteTimer = new Timer () {
Interval = 60000
};
// Listen to the irc channel on the server
Listener = new SparkleListener (Domain, "#" + RemoteName, UserEmail);
RemoteTimer.Elapsed += delegate {
if (_IsPolling)
if (_IsPolling) {
CheckForRemoteChanges ();
if (!Listener.Client.IsConnected) {
SparkleHelpers.DebugInfo ("Irc", "[" + Name + "] Trying to reconnect...");
Listener.Listen ();
}
}
if (_HasUnsyncedChanges)
Push ();
if (!Listener.Client.IsConnected) {
SparkleHelpers.DebugInfo ("Irc", "[" + Name + "] Trying to reconnect...");
Listener.Client.Reconnect (true, true);
}
};
// Stop polling when the connection to the irc channel is succesful
Listener.Client.OnConnected += delegate {
_IsPolling = false;
// Check for changes manually one more time
CheckForRemoteChanges ();
@ -348,19 +346,22 @@ namespace SparkleLib {
if (_HasUnsyncedChanges)
Push ();
SparkleHelpers.DebugInfo ("Irc", "[" + Name + "] Connected. Now listening...");
_IsPolling = false;
SparkleHelpers.DebugInfo ("Irc", "[" + Name + "] Connected. Now listening... (" + Listener.Server + ")");
};
// Start polling when the connection to the irc channel is lost
Listener.Client.OnConnectionError += delegate {
SparkleHelpers.DebugInfo ("Irc", "[" + Name + "] Lost connection. Falling back to polling...");
_IsPolling = true;
};
// Start polling when the connection to the irc channel is lost
Listener.Client.OnDisconnected += delegate {
SparkleHelpers.DebugInfo ("Irc", "[" + Name + "] Lost connection. Falling back to polling...");
CheckForRemoteChanges ();
_IsPolling = true;
};
@ -369,8 +370,9 @@ namespace SparkleLib {
Listener.Client.OnChannelMessage += delegate (object o, IrcEventArgs args) {
SparkleHelpers.DebugInfo ("Irc", "[" + Name + "] Was notified of a remote change.");
if (!args.Data.Message.Equals (_CurrentHash)) {
string message = args.Data.Message.Trim ();
if (!message.Equals (_CurrentHash) && message.Length == 40) {
FetchRequests++;
@ -388,7 +390,8 @@ namespace SparkleLib {
}
} else {
// Not really needed as we won't be notified about our own messages
SparkleHelpers.DebugInfo ("Irc",
"[" + Name + "] False alarm, already up to date. (" + _CurrentHash + ")");
@ -397,13 +400,15 @@ namespace SparkleLib {
};
// Start listening
Listener.ListenForChanges ();
Listener.Listen ();
SizeBuffer = new List <double> ();
// Keep a timer that checks if there are changes and
// whether they have settled
LocalTimer = new Timer () {
Interval = 4000
Interval = 250
};
LocalTimer.Elapsed += delegate (object o, ElapsedEventArgs args) {
@ -411,9 +416,7 @@ namespace SparkleLib {
};
if (_IsPolling)
RemoteTimer.Start ();
RemoteTimer.Start ();
LocalTimer.Start ();
// Add everything that changed
@ -430,23 +433,14 @@ namespace SparkleLib {
{
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Checking for remote changes...");
Process process = new Process () {
EnableRaisingEvents = true
};
process.StartInfo.FileName = SparklePaths.GitPath;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.WorkingDirectory = LocalPath;
process.StartInfo.Arguments = "ls-remote origin master";
process.Exited += delegate {
SparkleGit git = new SparkleGit (LocalPath, "ls-remote origin master");
git.Exited += delegate {
if (process.ExitCode != 0)
if (git.ExitCode != 0)
return;
string remote_hash = process.StandardOutput.ReadToEnd ();
string remote_hash = git.StandardOutput.ReadToEnd ();
if (!remote_hash.StartsWith (_CurrentHash)) {
@ -457,33 +451,10 @@ namespace SparkleLib {
}
};
process.Start ();
/* FIXME: LsRemoteCommand is not yet implemented by GitSharp
LsRemoteCommand ls_remote = new LsRemoteCommand () {
Repository = this
};
ls_remote.Execute ();
using (StreamReader reader = new StreamReader (ls_remote.OutputStream.BaseStream))
{
string remote_hash = reader.ReadLine ());
if (!remote_hash.StartsWith (_CurrentHash)) {
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Remote changes found.");
Fetch ();
Rebase ();
}
}
*/
git.Start ();
git.WaitForExit ();
}
@ -494,15 +465,18 @@ namespace SparkleLib {
lock (ChangeLock) {
if (HasChanged) {
if (SizeBuffer.Count >= 4)
SizeBuffer.RemoveAt (0);
DirectoryInfo dir_info = new DirectoryInfo (LocalPath);
SizeBuffer.Add (CalculateFolderSize (dir_info));
SparkleHelpers.DebugInfo ("Local", "[" + Name + "] Changes found, checking if settled.");
if (SizeBuffer [0].Equals (SizeBuffer [1]) &&
SizeBuffer [1].Equals (SizeBuffer [2]) &&
SizeBuffer [2].Equals (SizeBuffer [3])) {
DateTime now = DateTime.UtcNow;
TimeSpan changed = new TimeSpan (now.Ticks - LastChange.Ticks);
if (changed.TotalMilliseconds > 5000) {
SparkleHelpers.DebugInfo ("Local", "[" + Name + "] Changes have settled, adding files...");
SparkleHelpers.DebugInfo ("Local", "[" + Name + "] Changes have settled.");
_IsBuffering = false;
@ -523,8 +497,12 @@ namespace SparkleLib {
{
WatcherChangeTypes wct = fse_args.ChangeType;
if (!ShouldIgnore (fse_args.FullPath)) {
int number_of_changes = Status.Untracked.Count +
Status.Missing.Count +
Status.Modified.Count;
if (number_of_changes > 0) {
_IsBuffering = true;
@ -540,12 +518,12 @@ namespace SparkleLib {
}
SparkleHelpers.DebugInfo ("Event", "[" + Name + "] " + wct.ToString () + " '" + fse_args.Name + "'");
SparkleHelpers.DebugInfo ("Local", "[" + Name + "] Changes found, checking if settled.");
RemoteTimer.Stop ();
lock (ChangeLock) {
LastChange = DateTime.UtcNow;
HasChanged = true;
}
@ -565,14 +543,13 @@ namespace SparkleLib {
LocalTimer.Stop ();
RemoteTimer.Stop ();
Add ();
string message = FormatCommitMessage ();
if (message != null) {
if (Status.AnyDifferences) {
Add ();
string message = FormatCommitMessage ();
Commit (message);
CheckForRemoteChanges ();
Push ();
} else {
@ -586,9 +563,7 @@ namespace SparkleLib {
} finally {
if (_IsPolling)
RemoteTimer.Start ();
RemoteTimer.Start ();
LocalTimer.Start ();
}
@ -604,9 +579,10 @@ namespace SparkleLib {
// FIXME: this GitSharp method seems to block...
// Index.AddAll ();
Process.StartInfo.Arguments = "add --all";
Process.Start ();
Process.WaitForExit ();
SparkleGit git = new SparkleGit (LocalPath, "add --all");
git.Start ();
git.WaitForExit ();
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Changes staged.");
@ -618,6 +594,21 @@ namespace SparkleLib {
}
// Removes unneeded objects
private void CollectGarbage ()
{
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Collecting garbage...");
SparkleGit git = new SparkleGit (LocalPath, "gc");
git.Start ();
git.WaitForExit ();
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Garbage collected..");
}
// Commits the made changes
new public void Commit (string message)
{
@ -626,14 +617,20 @@ namespace SparkleLib {
return;
base.Commit (message);
_CurrentHash = Head.CurrentCommit.Hash;
SparkleHelpers.DebugInfo ("Commit", "[" + Name + "] " + message + " (" + _CurrentHash);
SparkleHelpers.DebugInfo ("Commit", "[" + Name + "] " + message);
SparkleEventArgs args = new SparkleEventArgs ("Commited");
args.Message = message;
SparkleEventArgs args = new SparkleEventArgs ("Commited") {
Message = message
};
if (Commited != null)
Commited (this, args);
// Collect garbage pseudo-randomly
if (DateTime.Now.Second % 10 == 0)
CollectGarbage ();
}
@ -647,32 +644,9 @@ namespace SparkleLib {
RemoteTimer.Stop ();
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Fetching changes...");
/* FIXME: SSH transport doesn't work with GitSharp
try {
FetchCommand fetch_command = new FetchCommand () {
Remote = "origin",
Repository = this
};
fetch_command.Execute ();
} catch (GitSharp.Core.Exceptions.TransportException e) {
Console.WriteLine ("Nothing to fetch: " + e.Message);
}
*/
Process process = new Process () {
EnableRaisingEvents = true
};
process.StartInfo.FileName = SparklePaths.GitPath;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.WorkingDirectory = LocalPath;
SparkleGit git = new SparkleGit (LocalPath, "fetch -v origin master");
SparkleEventArgs args;
args = new SparkleEventArgs ("FetchingStarted");
@ -680,44 +654,43 @@ namespace SparkleLib {
if (FetchingStarted != null)
FetchingStarted (this, args);
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Fetching changes...");
process.StartInfo.Arguments = "fetch -v origin master";
process.Exited += delegate {
git.Exited += delegate {
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Changes fetched.");
args = new SparkleEventArgs ("FetchingFinished");
_IsSyncing = false;
_IsFetching = false;
if (_IsPolling)
RemoteTimer.Start ();
_CurrentHash = Head.CurrentCommit.Hash;
if (process.ExitCode != 0) {
if (git.ExitCode != 0) {
_ServerOnline = false;
args = new SparkleEventArgs ("FetchingFailed");
if (FetchingFailed != null)
FetchingFailed (this, args);
} else {
_ServerOnline = true;
args = new SparkleEventArgs ("FetchingFinished");
if (FetchingFinished != null)
FetchingFinished (this, args);
}
RemoteTimer.Start ();
};
process.Start ();
process.WaitForExit ();
git.Start ();
git.WaitForExit ();
}
@ -726,79 +699,75 @@ namespace SparkleLib {
public void Rebase ()
{
Add ();
Watcher.EnableRaisingEvents = false;
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Rebasing changes...");
Process.StartInfo.Arguments = "rebase -v FETCH_HEAD";
Process.WaitForExit ();
Process.Start ();
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Changes rebased.");
string output = Process.StandardOutput.ReadToEnd ().Trim ();
if (!output.Contains ("up to date")) {
if (output.Contains ("Failed to merge")) {
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Resolving conflict...");
Process.StartInfo.Arguments = "status";
Process.WaitForExit ();
Process.Start ();
output = Process.StandardOutput.ReadToEnd ().Trim ();
string [] lines = Regex.Split (output, "\n");
foreach (string line in lines) {
if (line.Contains ("needs merge")) {
string problem_file_name = line.Substring (line.IndexOf (": needs merge"));
Process.StartInfo.Arguments = "checkout --ours " + problem_file_name;
Process.WaitForExit ();
Process.Start ();
string timestamp = DateTime.Now.ToString ("H:mm d MMM yyyy");
File.Move (problem_file_name, problem_file_name + " (" + UserName + ", " + timestamp + ")");
Process.StartInfo.Arguments = "checkout --theirs " + problem_file_name;
Process.WaitForExit ();
Process.Start ();
SparkleEventArgs args = new SparkleEventArgs ("ConflictDetected");
if (ConflictDetected != null)
ConflictDetected (this, args);
}
}
Add ();
Process.StartInfo.Arguments = "rebase --continue";
Process.WaitForExit ();
Process.Start ();
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Conflict resolved.");
Push ();
}
if (Status.AnyDifferences) {
Add ();
string commit_message = FormatCommitMessage ();
Commit (commit_message);
List <SparkleCommit> commits = GetCommits (1);
if (NewCommit != null)
NewCommit (commits [0], LocalPath);
}
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Rebasing changes...");
SparkleGit git = new SparkleGit (LocalPath, "rebase -v FETCH_HEAD");
git.Exited += delegate {
if (Status.MergeConflict.Count > 0) {
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Conflict detected...");
foreach (string problem_file_name in Status.MergeConflict) {
SparkleGit git_ours = new SparkleGit (LocalPath,
"checkout --ours " + problem_file_name);
git_ours.Start ();
git_ours.WaitForExit ();
string timestamp = DateTime.Now.ToString ("H:mm d MMM");
string new_file_name = problem_file_name + " (" + UserName + ", " + timestamp + ")";
File.Move (problem_file_name, new_file_name);
SparkleGit git_theirs = new SparkleGit (LocalPath,
"checkout --theirs " + problem_file_name);
git_theirs.Start ();
git_theirs.WaitForExit ();
SparkleEventArgs args = new SparkleEventArgs ("ConflictDetected");
if (ConflictDetected != null)
ConflictDetected (this, args);
}
Add ();
SparkleGit git_continue = new SparkleGit (LocalPath, "rebase --continue");
git_continue.Start ();
git_continue.WaitForExit ();
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Conflict resolved.");
Push ();
}
};
git.Start ();
git.WaitForExit ();
_CurrentHash = Head.CurrentCommit.Hash;
if (NewCommit != null)
NewCommit (GetCommits (2) [0], LocalPath); // FIXME: GetCommits doesn't like 1
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Changes rebased.");
Watcher.EnableRaisingEvents = true;
}
@ -810,41 +779,23 @@ namespace SparkleLib {
_IsSyncing = true;
_IsPushing = true;
SparkleEventArgs args = new SparkleEventArgs ("PushingStarted");
if (PushingStarted != null)
PushingStarted (this, args);
SparkleGit git = new SparkleGit (LocalPath, "push origin master");
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Pushing changes...");
/* FIXME: SSH transport doesn't work with GitSharp
try {
PushCommand push_command = new PushCommand () {
Remote = "origin",
Repository = this
};
push_command.Execute ();
} catch (GitSharp.Core.Exceptions.TransportException e) {
Console.WriteLine (e.Message);
SparkleEventArgs args = new SparkleEventArgs ("PushingStarted");
}
*/
if (PushingStarted != null)
PushingStarted (this, args);
Process.StartInfo.Arguments = "push origin master";
Process.WaitForExit ();
Process.Exited += delegate {
git.Exited += delegate {
_IsSyncing = false;
_IsPushing = false;
if (Process.ExitCode != 0) {
if (git.ExitCode != 0) {
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Pushing failed.");
@ -859,7 +810,9 @@ namespace SparkleLib {
args = new SparkleEventArgs ("PushingFailed");
if (PushingFailed != null)
PushingFailed (this, args);
PushingFailed (this, args);
CheckForChanges ();
} else {
@ -877,33 +830,17 @@ namespace SparkleLib {
if (PushingFinished != null)
PushingFinished (this, args);
if (!_IsPolling)
Listener.Announce (_CurrentHash);
}
};
Process.Start ();
}
// Ignores repos, dotfiles, swap files and the like
private bool ShouldIgnore (string file_path)
{
if (file_path.EndsWith (".lock") ||
file_path.EndsWith ("~") ||
file_path.Contains (".git") ||
file_path.Contains ("/.") ||
file_path.EndsWith (".swp") ||
System.IO.Directory.Exists (Path.Combine (LocalPath, file_path))) {
return true; // Yes, ignore it
} else {
return false;
}
git.Start ();
git.WaitForExit ();
}
@ -946,6 +883,37 @@ namespace SparkleLib {
return description;
}
// Recursively gets a folder's size in bytes
private double CalculateFolderSize (DirectoryInfo parent)
{
if (!System.IO.Directory.Exists (parent.ToString ()))
return 0;
double size = 0;
// Ignore the temporary 'rebase-apply' directory. This prevents potential
// crashes when files are being queried whilst the files have already been deleted.
if (parent.Name.Equals ("rebase-apply"))
return 0;
foreach (FileInfo file in parent.GetFiles()) {
if (!file.Exists)
return 0;
size += file.Length;
}
foreach (DirectoryInfo directory in parent.GetDirectories())
size += CalculateFolderSize (directory);
return size;
}
// Create a first commit in case the user has cloned
@ -964,49 +932,91 @@ namespace SparkleLib {
public List <SparkleCommit> GetCommits (int count)
{
if (count <= 0)
return null;
if (count < 1)
count = 30;
List <SparkleCommit> commits = new List <SparkleCommit> ();
string commit_ref = "HEAD";
SparkleGit git_log = new SparkleGit (LocalPath, "log -" + count + " --raw --date=iso");
git_log.Start ();
git_log.WaitForExit ();
string output = git_log.StandardOutput.ReadToEnd ();
string [] lines = output.Split ("\n".ToCharArray ());
List <string> entries = new List <string> ();
try {
for (int i = 0; i < count; i++) {
Commit commit = new Commit (this, commit_ref);
SparkleCommit sparkle_commit = new SparkleCommit ();
sparkle_commit.UserName = commit.Author.Name;
sparkle_commit.UserEmail = commit.Author.EmailAddress;
sparkle_commit.DateTime = commit.CommitDate.DateTime;
sparkle_commit.Hash = commit.Hash;
int j = 0;
string entry = "";
foreach (string line in lines) {
if (line.StartsWith ("commit") && j > 0) {
foreach (Change change in commit.Changes) {
entries.Add (entry);
entry = "";
}
entry += line + "\n";
j++;
if (change.ChangeType.ToString ().Equals ("Added"))
sparkle_commit.Added.Add (change.Path);
}
if (change.ChangeType.ToString ().Equals ("Modified"))
sparkle_commit.Edited.Add (change.Path);
foreach (string log_entry in entries) {
if (change.ChangeType.ToString ().Equals ("Deleted"))
sparkle_commit.Deleted.Add (change.Path);
Regex regex = new Regex (@"commit ([a-z0-9]{40})\n" +
"Author: (.+) <(.+)>\n" +
"Date: ([0-9]{4})-([0-9]{2})-([0-9]{2}) " +
"([0-9]{2}):([0-9]{2}):([0-9]{2}) \\+([0-9]{4})\n" +
"*");
Match match = regex.Match (log_entry);
if (match.Success) {
SparkleCommit commit = new SparkleCommit ();
commit.Hash = match.Groups [1].Value;
commit.UserName = match.Groups [2].Value;
commit.UserEmail = match.Groups [3].Value;
commit.DateTime = new DateTime (int.Parse (match.Groups [4].Value),
int.Parse (match.Groups [5].Value), int.Parse (match.Groups [6].Value),
int.Parse (match.Groups [7].Value), int.Parse (match.Groups [8].Value),
int.Parse (match.Groups [9].Value));
string [] entry_lines = log_entry.Split ("\n".ToCharArray ());
foreach (string entry_line in entry_lines) {
if (entry_line.StartsWith (":")) {
string change_type = entry_line [37].ToString ();
string file_path = entry_line.Substring (39);
if (change_type.Equals ("A")) {
commit.Added.Add (file_path);
} else if (change_type.Equals ("M")) {
commit.Edited.Add (file_path);
} else if (change_type.Equals ("D")) {
commit.Deleted.Add (file_path);
}
}
}
commits.Add (sparkle_commit);
commit_ref += "^";
}
} catch (System.NullReferenceException) {
// FIXME: Doesn't show the first commit because it throws
// this exception before getting to it. Seems to be a bug in GitSharp
commits.Add (commit);
}
}
return commits;

View file

@ -0,0 +1,21 @@
using System;
using System.Drawing;
using MonoMac.Foundation;
using MonoMac.AppKit;
using MonoMac.ObjCRuntime;
namespace test2
{
public partial class AppDelegate : NSApplicationDelegate
{
public AppDelegate ()
{
}
public override void FinishedLaunching (NSObject notification)
{
}
}
}

View file

@ -2,26 +2,19 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string></string>
<key>CFBundleIconFile</key>
<string>sparkleshare.icns</string>
<key>LSEnvironment</key>
<dict>
<key>PATH</key>
<string>/opt/local/bin</string>
</dict>
<string>sparkleshare</string>
<key>CFBundleIdentifier</key>
<string>org.sparkleshare.sparkleshare</string>
<key>CFBundleName</key>
<string>SparkleShare</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>10.6</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>LSBackgroundOnly</key>
<false/>
</dict>
</plist>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,558 @@
// 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.Drawing;
using System.IO;
using System.Timers;
using MonoMac.Foundation;
using MonoMac.AppKit;
using MonoMac.ObjCRuntime;
using MonoMac.WebKit;
using Mono.Unix;
namespace SparkleShare {
public class SparkleIntro : SparkleWindow {
private NSButton ContinueButton;
private NSButton SyncButton;
private NSButton TryAgainButton;
private NSButton CancelButton;
private NSButton SkipButton;
private NSButton OpenFolderButton;
private NSButton FinishButton;
private NSForm UserInfoForm;
private NSProgressIndicator ProgressIndicator;
private NSTextField AddressTextField;
private NSTextField FolderNameTextField;
private NSTextField ServerTypeLabel;
private NSTextField AddressLabel;
private NSTextField FolderNameLabel;
private NSTextField FolderNameHelpLabel;
private NSButtonCell ButtonCellProto;
private NSMatrix Matrix;
private int ServerType;
private bool ServerFormOnly;
public SparkleIntro () : base ()
{
ServerFormOnly = false;
}
public void ShowAccountForm ()
{
Reset ();
Header = "Welcome to SparkleShare!";
Description = "Before we can create a SparkleShare folder on this " +
"computer, we need some information from you.";
UserInfoForm = new NSForm (new RectangleF (250, 115, 350, 64));
UserInfoForm.AddEntry ("Full Name:");
UserInfoForm.AddEntry ("Email Address:");
UserInfoForm.CellSize = new SizeF (280, 22);
UserInfoForm.IntercellSpacing = new SizeF (4, 4);
string full_name = new UnixUserInfo (UnixEnvironment.UserName).RealName;
UserInfoForm.Cells [0].StringValue = full_name;
UserInfoForm.Cells [1].StringValue = SparkleShare.Controller.UserEmail;
ContinueButton = new NSButton () {
Title = "Continue",
Enabled = false
};
ContinueButton.Activated += delegate {
SparkleShare.Controller.UserName = UserInfoForm.Cells [0].StringValue.Trim ();
SparkleShare.Controller.UserEmail = UserInfoForm.Cells [1].StringValue.Trim ();
SparkleShare.Controller.GenerateKeyPair ();
SparkleShare.Controller.FirstRun = false;
InvokeOnMainThread (delegate {
ShowServerForm ();
});
};
// TODO: Ugly hack, do properly with events
Timer timer = new Timer () {
Interval = 50
};
timer.Elapsed += delegate {
InvokeOnMainThread (delegate {
bool name_is_correct =
!UserInfoForm.Cells [0].StringValue.Trim ().Equals ("");
bool email_is_correct = SparkleShare.Controller.IsValidEmail
(UserInfoForm.Cells [1].StringValue.Trim ());
ContinueButton.Enabled = (name_is_correct && email_is_correct);
});
};
timer.Start ();
ContentView.AddSubview (UserInfoForm);
Buttons.Add (ContinueButton);
ShowAll ();
}
public void ShowServerForm (bool server_form_only)
{
ServerFormOnly = server_form_only;
ShowServerForm ();
}
public void ShowServerForm ()
{
Reset ();
Header = "Where is your remote folder?";
Description = "";
ServerTypeLabel = new NSTextField () {
Alignment = (uint) NSTextAlignment.Right,
BackgroundColor = NSColor.WindowBackground,
Bordered = false,
Editable = false,
Frame = new RectangleF (150, Frame.Height - 139 , 160, 17),
StringValue = "Server Type:",
Font = SparkleUI.Font
};
AddressLabel = new NSTextField () {
Alignment = (uint) NSTextAlignment.Right,
BackgroundColor = NSColor.WindowBackground,
Bordered = false,
Editable = false,
Frame = new RectangleF (150, Frame.Height - 237 , 160, 17),
StringValue = "Address:",
Font = SparkleUI.Font
};
FolderNameLabel = new NSTextField () {
Alignment = (uint) NSTextAlignment.Right,
BackgroundColor = NSColor.WindowBackground,
Bordered = false,
Editable = false,
Frame = new RectangleF (150, Frame.Height - 264 , 160, 17),
StringValue = "Folder Name:",
Font = SparkleUI.Font
};
AddressTextField = new NSTextField () {
Frame = new RectangleF (320, Frame.Height - 240 , 256, 22),
Font = SparkleUI.Font
};
FolderNameTextField = new NSTextField () {
Frame = new RectangleF (320, Frame.Height - (240 + 22 + 4) , 256, 22),
StringValue = ""
};
FolderNameHelpLabel = new NSTextField () {
BackgroundColor = NSColor.WindowBackground,
Bordered = false,
TextColor = NSColor.DisabledControlText,
Editable = false,
Frame = new RectangleF (320, Frame.Height - 285 , 200, 17),
StringValue = "e.g. rupert/website-design"
};
ServerType = 0;
ButtonCellProto = new NSButtonCell ();
ButtonCellProto.SetButtonType (NSButtonType.Radio) ;
Matrix = new NSMatrix (new RectangleF (315, 180, 256, 78),
NSMatrixMode.Radio, ButtonCellProto, 4, 1);
Matrix.CellSize = new SizeF (256, 18);
Matrix.Cells [0].Title = "My own server";
Matrix.Cells [1].Title = "Github";
Matrix.Cells [2].Title = "Gitorious";
Matrix.Cells [3].Title = "The GNOME Project";
foreach (NSCell cell in Matrix.Cells)
cell.Font = SparkleUI.Font;
// TODO: Ugly hack, do properly with events
Timer timer = new Timer () {
Interval = 50
};
timer.Elapsed += delegate {
InvokeOnMainThread (delegate {
if (Matrix.SelectedRow != ServerType) {
ServerType = Matrix.SelectedRow;
AddressTextField.Enabled = (ServerType == 0);
switch (ServerType) {
case 0:
AddressTextField.StringValue = "";
FolderNameHelpLabel.StringValue = "e.g. rupert/website-design";
break;
case 1:
AddressTextField.StringValue = "ssh://git@github.com/";
FolderNameHelpLabel.StringValue = "e.g. rupert/website-design";
break;
case 2:
AddressTextField.StringValue = "ssh://git@gitorious.org/";
FolderNameHelpLabel.StringValue = "e.g. project/website-design";
break;
case 3:
AddressTextField.StringValue = "ssh://git@gnome.org/git/";
FolderNameHelpLabel.StringValue = "e.g. gnome-icon-theme";
break;
}
}
if (ServerType == 0 && !AddressTextField.StringValue.Trim ().Equals ("")
&& !FolderNameTextField.StringValue.Trim ().Equals ("")) {
SyncButton.Enabled = true;
} else if (ServerType != 0 &&
!FolderNameTextField.StringValue.Trim ().Equals ("")) {
SyncButton.Enabled = true;
} else {
SyncButton.Enabled = false;
}
});
};
timer.Start ();
ContentView.AddSubview (ServerTypeLabel);
ContentView.AddSubview (Matrix);
ContentView.AddSubview (AddressLabel);
ContentView.AddSubview (AddressTextField);
ContentView.AddSubview (FolderNameLabel);
ContentView.AddSubview (FolderNameTextField);
ContentView.AddSubview (FolderNameHelpLabel);
SyncButton = new NSButton () {
Title = "Sync",
Enabled = false
};
SyncButton.Activated += delegate {
string name = FolderNameTextField.StringValue;
// Remove the starting slash if there is one
if (name.StartsWith ("/"))
name = name.Substring (1);
string server = AddressTextField.StringValue;
if (name.EndsWith ("/"))
name = name.TrimEnd ("/".ToCharArray ());
if (name.StartsWith ("/"))
name = name.TrimStart ("/".ToCharArray ());
if (server.StartsWith ("ssh://"))
server = server.Substring (6);
if (ServerType == 0) {
// Use the default user 'git' if no username is specified
if (!server.Contains ("@"))
server = "git@" + server;
// Prepend the Secure Shell protocol when it isn't specified
if (!server.StartsWith ("ssh://"))
server = "ssh://" + server;
// Remove the trailing slash if there is one
if (server.EndsWith ("/"))
server = server.TrimEnd ("/".ToCharArray ());
}
if (ServerType == 2) {
server = "ssh://git@gitorious.org";
if (!name.EndsWith (".git")) {
if (!name.Contains ("/"))
name = name + "/" + name;
name += ".git";
}
}
if (ServerType == 1)
server = "ssh://git@github.com";
if (ServerType == 3)
server = "ssh://git@gnome.org/git/";
string url = server + "/" + name;
string canonical_name = Path.GetFileNameWithoutExtension (name);
ShowSyncingPage (canonical_name);
SparkleShare.Controller.FolderFetched += delegate {
InvokeOnMainThread (delegate {
ShowSuccessPage (canonical_name);
});
};
SparkleShare.Controller.FolderFetchError += delegate {
InvokeOnMainThread (delegate {
ShowErrorPage ();
});
};
SparkleShare.Controller.FetchFolder (url, name);
};
Buttons.Add (SyncButton);
if (ServerFormOnly) {
CancelButton = new NSButton () {
Title = "Cancel"
};
CancelButton.Activated += delegate {
InvokeOnMainThread (delegate {
Close ();
});
};
Buttons.Add (CancelButton);
} else {
SkipButton = new NSButton () {
Title = "Skip"
};
SkipButton.Activated += delegate {
InvokeOnMainThread (delegate {
ShowCompletedPage ();
});
};
Buttons.Add (SkipButton);
}
ShowAll ();
}
public void ShowErrorPage ()
{
Reset ();
Header = "Something went wrong…";
Description = "";
TryAgainButton = new NSButton () {
Title = "Try again…"
};
TryAgainButton.Activated += delegate {
InvokeOnMainThread (delegate {
ShowServerForm ();
});
};
Buttons.Add (TryAgainButton);
ShowAll ();
}
private void ShowSyncingPage (string name)
{
Reset ();
Header = "Syncing folder " + name + "’…";
Description = "This may take a while.\n" +
"You sure its not coffee o-clock?";
ProgressIndicator = new NSProgressIndicator () {
Frame = new RectangleF (190, Frame.Height - 200, 640 - 150 - 80, 20),
Style = NSProgressIndicatorStyle.Bar
};
ProgressIndicator.StartAnimation (this);
ContentView.AddSubview (ProgressIndicator);
FinishButton = new NSButton () {
Title = "Finish",
Enabled = false
};
Buttons.Add (FinishButton);
ShowAll ();
}
public void ShowSuccessPage (string folder_name)
{
Reset ();
Header = "Folder synced succesfully!";
Description = "Now you can access the synced files from " + folder_name + " in " +
"your SparkleShare folder.";
FinishButton = new NSButton () {
Title = "Finish"
};
FinishButton.Activated += delegate {
InvokeOnMainThread (delegate {
SparkleUI.StatusIcon.CreateMenu ();
Close ();
});
};
OpenFolderButton = new NSButton () {
Title = "Open Folder"
};
OpenFolderButton.Activated += delegate {
SparkleShare.Controller.OpenSparkleShareFolder (folder_name);
};
Buttons.Add (FinishButton);
Buttons.Add (OpenFolderButton);
ShowAll ();
NSApplication.SharedApplication.RequestUserAttention
(NSRequestUserAttentionType.CriticalRequest);
}
private void ShowCompletedPage ()
{
Reset ();
Header = "SparkleShare is ready to go!";
Description = "Now you can start accepting invitations from others. " +
"Just click on invitations you get by email and " +
"we will take care of the rest.";
FinishButton = new NSButton () {
Title = "Finish"
};
FinishButton.Activated += delegate {
InvokeOnMainThread (delegate {
SparkleUI.StatusIcon.CreateMenu ();
Close ();
});
};
Buttons.Add (FinishButton);
ShowAll ();
}
}
}

View file

@ -0,0 +1,181 @@
// 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.Drawing;
using MonoMac.Foundation;
using MonoMac.AppKit;
using MonoMac.ObjCRuntime;
using MonoMac.WebKit;
using System.IO;
namespace SparkleShare {
public class SparkleLog : NSWindow {
public readonly string LocalPath;
private WebView WebView;
private NSButton CloseButton;
private NSButton OpenFolderButton;
private NSBox Separator;
public SparkleLog (IntPtr handle) : base (handle) { }
public SparkleLog (string path) : base ()
{
LocalPath = path;
Delegate = new SparkleLogDelegate ();
SetFrame (new RectangleF (0, 0, 480, 640), true);
Center ();
// Open slightly off center for each consecutive window
if (SparkleUI.OpenLogs.Count > 0) {
RectangleF offset = new RectangleF (Frame.X + (SparkleUI.OpenLogs.Count * 20),
Frame.Y - (SparkleUI.OpenLogs.Count * 20), Frame.Width, Frame.Height);
SetFrame (offset, true);
}
StyleMask = (NSWindowStyle.Closable |
NSWindowStyle.Miniaturizable |
NSWindowStyle.Titled);
MaxSize = new SizeF (480, 640);
MinSize = new SizeF (480, 640);
HasShadow = true;
BackingType = NSBackingStore.Buffered;
CreateEventLog ();
UpdateEventLog ();
ContentView.AddSubview (WebView);
OpenFolderButton = new NSButton (new RectangleF (16, 12, 120, 32)) {
Title = "Open Folder",
BezelStyle = NSBezelStyle.Rounded ,
Font = SparkleUI.Font
};
OpenFolderButton.Activated += delegate {
SparkleShare.Controller.OpenSparkleShareFolder (LocalPath);
};
ContentView.AddSubview (OpenFolderButton);
CloseButton = new NSButton (new RectangleF (480 - 120 - 16, 12, 120, 32)) {
Title = "Close",
BezelStyle = NSBezelStyle.Rounded,
Font = SparkleUI.Font
};
CloseButton.Activated += delegate {
InvokeOnMainThread (delegate {
PerformClose (this);
});
};
ContentView.AddSubview (CloseButton);
string name = Path.GetFileName (LocalPath);
Title = String.Format ("Events in {0}", name);
Separator = new NSBox (new RectangleF (0, 58, 480, 1)) {
BorderColor = NSColor.LightGray,
BoxType = NSBoxType.NSBoxCustom
};
ContentView.AddSubview (Separator);
OrderFrontRegardless ();
}
public void UpdateEventLog ()
{
string folder_name = Path.GetFileName (LocalPath);
string html = SparkleShare.Controller.GetHTMLLog (folder_name);
html = html.Replace ("<!-- $body-font-family -->", "Lucida Grande");
html = html.Replace ("<!-- $body-font-size -->", "13.4px");
html = html.Replace ("<!-- $secondary-font-color -->", "#bbb");
html = html.Replace ("<!-- $small-color -->", "#ddd");
html = html.Replace ("<!-- $day-entry-header-background-color -->", "#f5f5f5");
html = html.Replace ("<!-- $a-color -->", "#0085cf");
html = html.Replace ("<!-- $no-buddy-icon-background-image -->",
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "avatar-default.png"));
WebView.MainFrame.LoadHtmlString (html, new NSUrl (""));
Update ();
}
private WebView CreateEventLog ()
{
WebView = new WebView (new RectangleF (0, 59, 480, 559), "", ""){
PolicyDelegate = new SparkleWebPolicyDelegate ()
};
return WebView;
}
}
public class SparkleLogDelegate : NSWindowDelegate {
public override bool WindowShouldClose (NSObject sender)
{
(sender as SparkleLog).OrderOut (this);
return false;
}
}
public class SparkleWebPolicyDelegate : WebPolicyDelegate {
public override void DecidePolicyForNavigation (WebView web_view, NSDictionary action_info,
NSUrlRequest request, WebFrame frame, NSObject decision_token)
{
string file_path = request.Url.ToString ();
file_path = file_path.Replace ("%20", " ");
NSWorkspace.SharedWorkspace.OpenFile (file_path);
}
}
}

View file

@ -49,8 +49,8 @@ namespace SparkleShare {
// list of bookmarked places
public override void AddToBookmarks ()
{
// TODO
}
@ -61,11 +61,8 @@ namespace SparkleShare {
if (!Directory.Exists (SparklePaths.SparklePath)) {
Directory.CreateDirectory (SparklePaths.SparklePath);
NSWorkspace.SharedWorkspace.SetIconforFile (NSImage.ImageNamed ("sparkleshare.icns"),
SparklePaths.SparklePath, 0);
Directory.CreateDirectory (SparklePaths.SparklePath);
return true;
} else {
@ -82,14 +79,72 @@ namespace SparkleShare {
{
string folder = Path.Combine (SparklePaths.SparklePath, subfolder);
folder.Replace (" ", "\\ "); // Escape space-characters
NSWorkspace.SharedWorkspace.OpenFile (folder);
}
public override string EventLogHTML
{
get {
string resource_path = NSBundle.MainBundle.ResourcePath;
Process process = new Process ();
process.StartInfo.Arguments = folder.Replace (" ", "\\ "); // Escape space-characters
process.StartInfo.FileName = "open";
process.Start ();
string html_path = Path.Combine (resource_path, "HTML", "event-log.html");
StreamReader reader = new StreamReader (html_path);
string html = reader.ReadToEnd ();
reader.Close ();
return html;
}
}
public override string DayEntryHTML
{
get {
string resource_path = NSBundle.MainBundle.ResourcePath;
string html_path = Path.Combine (resource_path, "HTML", "day-entry.html");
StreamReader reader = new StreamReader (html_path);
string html = reader.ReadToEnd ();
reader.Close ();
return html;
}
}
public override string EventEntryHTML
{
get {
string resource_path = NSBundle.MainBundle.ResourcePath;
string html_path = Path.Combine (resource_path, "HTML", "event-entry.html");
StreamReader reader = new StreamReader (html_path);
string html = reader.ReadToEnd ();
reader.Close ();
return html;
}
}
}
}

View file

@ -0,0 +1,161 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>10.0.0</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{CF5BC8DB-A633-4FCC-8A3E-E3AC9B59FABC}</ProjectGuid>
<ProjectTypeGuids>{1C533B1C-72DD-4CB1-9F6B-BF11D93BCFBE};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Exe</OutputType>
<RootNamespace>SparkleShare</RootNamespace>
<AssemblyName>SparkleShare</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<ReleaseVersion>0.2</ReleaseVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<ItemGroup>
<Reference Include="System">
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="System.Xml">
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="System.Core">
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="System.Xml.Linq">
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="System.Drawing">
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="MonoMac">
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="SparkleLib, Version=0.2.0.0, Culture=neutral, PublicKeyToken=null">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\bin\SparkleLib.dll</HintPath>
</Reference>
<Reference Include="Mono.Posix">
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="DiffieHellman, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\bin\DiffieHellman.dll</HintPath>
</Reference>
<Reference Include="GitSharp.Core, Version=0.3.0.0, Culture=neutral, PublicKeyToken=null">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\bin\GitSharp.Core.dll</HintPath>
</Reference>
<Reference Include="GitSharp, Version=0.3.0.0, Culture=neutral, PublicKeyToken=null">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\bin\GitSharp.dll</HintPath>
</Reference>
<Reference Include="Meebey.SmartIrc4net, Version=0.4.5.0, Culture=neutral, PublicKeyToken=7868485fbf407e0f">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\bin\Meebey.SmartIrc4net.dll</HintPath>
</Reference>
<Reference Include="Org.Mentalis.Security, Version=1.0.13.715, Culture=neutral, PublicKeyToken=null">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\bin\Org.Mentalis.Security.dll</HintPath>
</Reference>
<Reference Include="Tamir.SharpSSH, Version=1.1.1.13, Culture=neutral, PublicKeyToken=null">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\bin\Tamir.SharpSSH.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="AppDelegate.cs">
<DependentUpon>MainMenu.xib</DependentUpon>
</Compile>
<Compile Include="MainMenu.xib.designer.cs">
<DependentUpon>MainMenu.xib</DependentUpon>
</Compile>
<Compile Include="..\SparkleController.cs">
<Link>SparkleController.cs</Link>
</Compile>
<Compile Include="SparkleWindow.cs" />
<Compile Include="SparkleIntro.cs" />
<Compile Include="SparkleLog.cs" />
<Compile Include="SparkleMacController.cs" />
<Compile Include="SparkleStatusIcon.cs" />
<Compile Include="SparkleUI.cs" />
<Compile Include="..\SparkleShare.cs">
<Link>SparkleShare.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<Page Include="MainMenu.xib" />
</ItemGroup>
<ItemGroup>
<None Include="Info.plist" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath)\Mono\MonoMac\v0.0\Mono.MonoMac.targets" />
<ItemGroup>
<Content Include="..\..\data\html\day-entry.html">
<Link>HTML\day-entry.html</Link>
</Content>
<Content Include="..\..\data\html\event-entry.html">
<Link>HTML\event-entry.html</Link>
</Content>
<Content Include="..\..\data\html\event-log.html">
<Link>HTML\event-log.html</Link>
</Content>
<Content Include="..\..\data\side-splash.png">
<Link>Pixmaps\side-splash.png</Link>
</Content>
<Content Include="..\..\data\avatar-default.png">
<Link>Pixmaps\avatar-default.png</Link>
</Content>
<Content Include="..\..\data\sparkleshare-mac.icns">
<Link>sparkleshare-mac.icns</Link>
</Content>
<Content Include="..\..\data\sparkleshare.icns">
<Link>sparkleshare.icns</Link>
</Content>
<Content Include="..\..\data\idle-active.png">
<Link>Pixmaps\idle-active.png</Link>
</Content>
<Content Include="..\..\data\idle.png">
<Link>Pixmaps\idle.png</Link>
</Content>
<Content Include="..\..\data\idle0.png">
<Link>Pixmaps\idle0.png</Link>
</Content>
<Content Include="..\..\data\idle1.png">
<Link>Pixmaps\idle1.png</Link>
</Content>
<Content Include="..\..\data\idle2.png">
<Link>Pixmaps\idle2.png</Link>
</Content>
<Content Include="..\..\data\idle3.png">
<Link>Pixmaps\idle3.png</Link>
</Content>
<Content Include="..\..\data\idle4.png">
<Link>Pixmaps\idle4.png</Link>
</Content>
</ItemGroup>
<ItemGroup>
<Folder Include="Pixmaps\" />
<Folder Include="HTML\" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,21 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SparkleShare", "SparkleShare.csproj", "{CF5BC8DB-A633-4FCC-8A3E-E3AC9B59FABC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CF5BC8DB-A633-4FCC-8A3E-E3AC9B59FABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CF5BC8DB-A633-4FCC-8A3E-E3AC9B59FABC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CF5BC8DB-A633-4FCC-8A3E-E3AC9B59FABC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CF5BC8DB-A633-4FCC-8A3E-E3AC9B59FABC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = SparkleShare.csproj
version = 0.2
EndGlobalSection
EndGlobal

View file

@ -1,298 +0,0 @@
//
// Layout.cs
//
// Author:
// Michael Hutchinson <mhutchinson@novell.com>
//
// Copyright (c) 2010 Novell, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Drawing;
using MonoMac.AppKit;
using System.Linq;
namespace MonoDevelop.Platform.Mac
{
interface ILayout
{
LayoutRequest BeginLayout ();
void EndLayout (LayoutRequest request, PointF origin, SizeF allocation);
}
class LayoutRequest
{
public SizeF Size { get; set; }
public bool Visible { get; set; }
public bool ExpandWidth { get; set; }
public bool ExpandHeight { get; set; }
}
abstract class LayoutBox : IEnumerable<ILayout>, ILayout
{
List<ILayout> children = new List<ILayout> ();
public float Spacing { get; set; }
public float PadLeft { get; set; }
public float PadRight { get; set; }
public float PadTop { get; set; }
public float PadBottom { get; set; }
public LayoutAlign Align { get; set; }
public LayoutDirection Direction { get; set; }
public LayoutBox (LayoutDirection direction, float spacing) : this (direction, spacing, 0)
{
}
public LayoutBox (LayoutDirection direction, float spacing, float padding)
{
PadLeft = PadRight = PadTop = PadBottom = padding;
this.Direction = direction;
this.Spacing = spacing;
this.Align = LayoutAlign.Center;
}
public int Count { get { return children.Count; } }
bool IsHorizontal { get { return Direction == LayoutDirection.Horizontal; } }
public IEnumerator<ILayout> GetEnumerator ()
{
return children.GetEnumerator ();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
{
return children.GetEnumerator ();
}
public void Add (ILayout child)
{
children.Add (child);
OnChildAdded (child);
}
ContainerLayoutRequest request = new ContainerLayoutRequest ();
public virtual LayoutRequest BeginLayout ()
{
float width = 0;
float height = 0;
request.ChildRequests.Clear ();
request.ChildRequests.AddRange (children.Select (c => c.BeginLayout ()));
foreach (var r in request.ChildRequests) {
if (!r.Visible)
continue;
request.Visible = true;
if (r.ExpandWidth)
request.ExpandWidth = true;
if (r.ExpandHeight)
request.ExpandHeight = true;
if (IsHorizontal) {
if (width != 0)
width += Spacing;
width += r.Size.Width;
height = Math.Max (height, r.Size.Height);
} else {
if (height != 0)
height += Spacing;
height += r.Size.Height;
width = Math.Max (width, r.Size.Width);
}
}
request.Size = new SizeF (width + PadLeft + PadRight, height + PadTop + PadBottom);
return request;
}
public virtual void EndLayout (LayoutRequest request, PointF origin, SizeF allocation)
{
var childRequests = ((ContainerLayoutRequest) request).ChildRequests;
allocation = new SizeF (allocation.Width - PadLeft - PadRight, allocation.Height - PadBottom - PadTop);
origin = new PointF (origin.X + PadLeft, origin.Y + PadBottom);
var size = request.Size;
size.Height -= (PadTop + PadBottom);
size.Width -= (PadLeft + PadRight);
int wExpandCount = 0;
int hExpandCount = 0;
int visibleCount = 0;
foreach (var childRequest in childRequests) {
if (childRequest.Visible)
visibleCount++;
else
continue;
if (childRequest.ExpandWidth)
wExpandCount++;
if (childRequest.ExpandHeight)
hExpandCount++;
}
float wExpand = 0;
if (allocation.Width > size.Width) {
wExpand = allocation.Width - size.Width;
if (wExpandCount > 0)
wExpand /= wExpandCount;
}
float hExpand = 0;
if (allocation.Height > size.Height) {
hExpand = allocation.Height - size.Height;
if (hExpandCount > 0)
hExpand /= hExpandCount;
}
if (Direction == LayoutDirection.Horizontal) {
float pos = PadLeft;
if (wExpandCount == 0) {
if (Align == LayoutAlign.End)
pos += wExpand;
else if (Align == LayoutAlign.Center)
pos += wExpand / 2;
}
for (int i = 0; i < childRequests.Count; i++) {
var child = children[i];
var childReq = childRequests[i];
if (!childReq.Visible)
continue;
var childSize = new SizeF (childReq.Size.Width, allocation.Height);
if (childReq.ExpandWidth) {
childSize.Width += wExpand;
} else if (hExpandCount == 0 && Align == LayoutAlign.Fill) {
childSize.Width += wExpand / visibleCount;
}
child.EndLayout (childReq, new PointF (pos, origin.Y), childSize);
pos += childSize.Width + Spacing;
}
} else {
float pos = PadBottom;
if (hExpandCount == 0) {
if (Align == LayoutAlign.End)
pos += hExpand;
else if (Align == LayoutAlign.Center)
pos += hExpand / 2;
}
for (int i = 0; i < childRequests.Count; i++) {
var child = children[i];
var childReq = childRequests[i];
if (!childReq.Visible)
continue;
var childSize = new SizeF (allocation.Width, childReq.Size.Height);
if (childReq.ExpandHeight) {
childSize.Height += hExpand;
} else if (hExpandCount == 0 && Align == LayoutAlign.Fill) {
childSize.Height += hExpand / visibleCount;
}
child.EndLayout (childReq, new PointF (origin.X, pos), childSize);
pos += childSize.Height + Spacing;
}
}
}
protected abstract void OnChildAdded (ILayout child);
class ContainerLayoutRequest : LayoutRequest
{
public List<LayoutRequest> ChildRequests = new List<LayoutRequest> ();
}
}
public enum LayoutAlign
{
Begin, Center, End, Fill
}
public enum LayoutDirection
{
Horizontal, Vertical
}
abstract class LayoutAlignment : ILayout
{
public LayoutAlignment ()
{
XAlign = YAlign = LayoutAlign.Center;
}
public LayoutAlign XAlign { get; set; }
public LayoutAlign YAlign { get; set; }
public bool ExpandHeight { get; set; }
public bool ExpandWidth { get; set; }
public float MinHeight { get; set; }
public float MinWidth { get; set; }
public float PadLeft { get; set; }
public float PadRight { get; set; }
public float PadTop { get; set; }
public float PadBottom { get; set; }
public bool Visible { get; set; }
LayoutRequest request = new LayoutRequest ();
public virtual LayoutRequest BeginLayout ()
{
request.Size = new SizeF (MinWidth + PadLeft + PadRight, MinHeight + PadTop + PadBottom);
request.ExpandHeight = this.ExpandHeight;
request.ExpandWidth = this.ExpandWidth;
request.Visible = this.Visible;
return request;
}
public virtual void EndLayout (LayoutRequest request, PointF origin, SizeF allocation)
{
var frame = new RectangleF (origin.X + PadLeft, origin.Y + PadBottom,
allocation.Width - PadLeft - PadRight, allocation.Height - PadTop - PadBottom);
if (allocation.Height > request.Size.Height) {
if (YAlign != LayoutAlign.Fill) {
frame.Height = request.Size.Height - PadTop - PadBottom;
if (YAlign == LayoutAlign.Center) {
frame.Y += (allocation.Height - request.Size.Height) / 2;
} else if (YAlign == LayoutAlign.End) {
frame.Y += (allocation.Height - request.Size.Height);
}
}
}
if (allocation.Width > request.Size.Width) {
if (XAlign != LayoutAlign.Fill) {
frame.Width = request.Size.Width - PadLeft - PadRight;
if (XAlign == LayoutAlign.Center) {
frame.X += (allocation.Width - request.Size.Width) / 2;
} else if (XAlign == LayoutAlign.End) {
frame.X += (allocation.Width - request.Size.Width);
}
}
}
OnLayoutEnded (frame);
}
protected abstract void OnLayoutEnded (RectangleF frame);
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,190 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
<data>
<int key="IBDocument.SystemTarget">1060</int>
<string key="IBDocument.SystemVersion">10D573</string>
<string key="IBDocument.InterfaceBuilderVersion">762</string>
<string key="IBDocument.AppKitVersion">1038.29</string>
<string key="IBDocument.HIToolboxVersion">460.00</string>
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="NS.object.0">762</string>
</object>
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
<bool key="EncodedWithXMLCoder">YES</bool>
<integer value="2"/>
</object>
<object class="NSArray" key="IBDocument.PluginDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
</object>
<object class="NSMutableDictionary" key="IBDocument.Metadata">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys" id="0">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSCustomObject" id="1001">
<string key="NSClassName">MainWindowController</string>
</object>
<object class="NSCustomObject" id="1003">
<string key="NSClassName">FirstResponder</string>
</object>
<object class="NSCustomObject" id="1004">
<string key="NSClassName">NSApplication</string>
</object>
<object class="NSWindowTemplate" id="748157544">
<int key="NSWindowStyleMask">15</int>
<int key="NSWindowBacking">2</int>
<string key="NSWindowRect">{{131, 74}, {606, 354}}</string>
<int key="NSWTFlags">611844096</int>
<string key="NSWindowTitle">Window</string>
<string key="NSWindowClass">MainWindow</string>
<nil key="NSViewClass"/>
<string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string>
<object class="NSView" key="NSWindowView" id="312036702">
<reference key="NSNextResponder"/>
<int key="NSvFlags">256</int>
<string key="NSFrameSize">{606, 354}</string>
<reference key="NSSuperview"/>
</object>
<string key="NSScreenRect">{{0, 0}, {1280, 778}}</string>
<string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string>
</object>
</object>
<object class="IBObjectContainer" key="IBDocument.Objects">
<object class="NSMutableArray" key="connectionRecords">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">window</string>
<reference key="source" ref="1001"/>
<reference key="destination" ref="748157544"/>
</object>
<int key="connectionID">6</int>
</object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBObjectRecord">
<int key="objectID">0</int>
<reference key="object" ref="0"/>
<reference key="children" ref="1000"/>
<nil key="parent"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">-2</int>
<reference key="object" ref="1001"/>
<reference key="parent" ref="0"/>
<string key="objectName">File's Owner</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">-1</int>
<reference key="object" ref="1003"/>
<reference key="parent" ref="0"/>
<string key="objectName">First Responder</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">-3</int>
<reference key="object" ref="1004"/>
<reference key="parent" ref="0"/>
<string key="objectName">Application</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">2</int>
<reference key="object" ref="748157544"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="312036702"/>
</object>
<reference key="parent" ref="0"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">3</int>
<reference key="object" ref="312036702"/>
<reference key="parent" ref="748157544"/>
</object>
</object>
</object>
<object class="NSMutableDictionary" key="flattenedProperties">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>-1.IBPluginDependency</string>
<string>-2.IBPluginDependency</string>
<string>-3.IBPluginDependency</string>
<string>2.IBEditorWindowLastContentRect</string>
<string>2.IBPluginDependency</string>
<string>2.IBWindowTemplateEditedContentRect</string>
<string>2.NSWindowTemplate.visibleAtLaunch</string>
<string>3.IBPluginDependency</string>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>{{319, 371}, {606, 354}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>{{319, 371}, {606, 354}}</string>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
</object>
</object>
<object class="NSMutableDictionary" key="unlocalizedProperties">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference key="dict.sortedKeys" ref="0"/>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<nil key="activeLocalization"/>
<object class="NSMutableDictionary" key="localizations">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference key="dict.sortedKeys" ref="0"/>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<nil key="sourceID"/>
<int key="maxID">6</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBPartialClassDescription">
<string key="className">MainWindow</string>
<string key="superclassName">NSWindow</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBUserSource</string>
<string key="minorKey"/>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">MainWindowController</string>
<string key="superclassName">NSWindowController</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBUserSource</string>
<string key="minorKey"/>
</object>
</object>
</object>
</object>
<int key="IBDocument.localizationMode">0</int>
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
<integer value="3000" key="NS.object.0"/>
</object>
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
<nil key="IBDocument.LastKnownRelativeProjectPath"/>
<int key="IBDocument.defaultPropertyAccessControl">3</int>
</data>
</archive>

View file

@ -1,128 +0,0 @@
// 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.Drawing;
using MonoMac.Foundation;
using MonoMac.AppKit;
using MonoMac.ObjCRuntime;
using MonoMac.WebKit;
namespace SparkleShare {
public class SparkleLog : NSWindow {
public readonly string LocalPath;
private WebView WebView;
private NSButton CloseButton;
private NSButton OpenFolderButton;
public SparkleLog (IntPtr handle) : base (handle) { }
public SparkleLog (string path) : base ()
{
LocalPath = path;
Delegate = new LogDelegate ();
SetFrame (new RectangleF (0, 0, 480, 640), true);
Center ();
StyleMask = (NSWindowStyle.Closable |
NSWindowStyle.Miniaturizable |
NSWindowStyle.Titled);
MaxSize = new SizeF (480, 640);
MinSize = new SizeF (480, 640);
HasShadow = true;
BackingType = NSBackingStore.Buffered;
ContentView.AddSubview (CreateEventLog ());
OpenFolderButton = new NSButton (new RectangleF (16, 12, 120, 31)) {
Title = "Open Folder",
BezelStyle = NSBezelStyle.Rounded
};
OpenFolderButton.Activated += delegate {
SparkleShare.Controller.OpenSparkleShareFolder (LocalPath);
};
ContentView.AddSubview (OpenFolderButton);
CloseButton = new NSButton (new RectangleF (480 - 120 - 16, 12, 120, 31)) {
Title = "Close",
BezelStyle = NSBezelStyle.Rounded
};
CloseButton.Activated += delegate {
InvokeOnMainThread (delegate {
PerformClose (this);
});
};
ContentView.AddSubview (CloseButton);
string name = System.IO.Path.GetFileName (LocalPath);
Title = String.Format ("Recent Events in {0}", name);
OrderFrontRegardless ();
}
public void UpdateEventLog ()
{
}
private WebView CreateEventLog ()
{
RectangleF frame = new RectangleF (0, 12 + 31 + 16, 480, 640 - (12 + 31 + 16));
WebView = new WebView (frame, "", "");
WebView.MainFrameUrl = "http://www.google.nl/";
return WebView;
}
}
public class LogDelegate : NSWindowDelegate {
public override void WillClose (NSNotification notification)
{
InvokeOnMainThread (delegate {
SparkleUI.OpenLogs.Remove ((SparkleLog) notification.Object);
});
}
}
}

View file

@ -1,98 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.21022</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{709CB8F4-F82F-4C94-B4E2-DC502087525B}</ProjectGuid>
<ProjectTypeGuids>{1C533B1C-72DD-4CB1-9F6B-BF11D93BCFBE};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Exe</OutputType>
<RootNamespace>SparkleShare</RootNamespace>
<AssemblyName>SparkleShare</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<EnvironmentVariables>
<EnvironmentVariables>
<Variable name="PATH" value="/opt/local/bin" />
</EnvironmentVariables>
</EnvironmentVariables>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Drawing" />
<Reference Include="MonoMac">
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="Mono.Posix" />
</ItemGroup>
<ItemGroup>
<Compile Include="MainMenu.xib.designer.cs">
<DependentUpon>MainMenu.xib</DependentUpon>
</Compile>
<Compile Include="Layout.cs" />
<Compile Include="SparkleLog.cs" />
<Compile Include="SparkleStatusIcon.cs" />
<Compile Include="..\..\SparkleShare.cs">
<Link>SparkleShare.cs</Link>
</Compile>
<Compile Include="..\..\SparkleController.cs">
<Link>SparkleController.cs</Link>
</Compile>
<Compile Include="SparkleMacController.cs" />
<Compile Include="SparkleUI.cs" />
<Compile Include="SparkleWindow.cs" />
</ItemGroup>
<ItemGroup>
<Page Include="MainMenu.xib" />
</ItemGroup>
<ItemGroup>
<None Include="Info.plist" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath)\Mono\MonoMac\v0.0\Mono.MonoMac.targets" />
<ItemGroup>
<Content Include="Pixmaps\idle.png" />
<Content Include="Pixmaps\idle0.png" />
<Content Include="Pixmaps\idle2.png" />
<Content Include="Pixmaps\idle-active.png" />
<Content Include="Pixmaps\idle1.png" />
<Content Include="Pixmaps\idle4.png" />
<Content Include="Pixmaps\idle3.png" />
<Content Include="Pixmaps\sparkleshare-idle.png" />
<Content Include="Pixmaps\sparkleshare-idle-focus.png" />
<Content Include="..\..\..\data\side-splash.png">
<Link>Pixmaps\side-splash.png</Link>
</Content>
<Content Include="sparkleshare.icns" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\SparkleLib\SparkleLib.csproj">
<Project>{2C914413-B31C-4362-93C7-1AE34F09112A}</Project>
<Name>SparkleLib</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Pixmaps\" />
</ItemGroup>
</Project>

View file

@ -1,26 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SparkleShare", "SparkleShare.csproj", "{709CB8F4-F82F-4C94-B4E2-DC502087525B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SparkleLib", "..\..\..\SparkleLib\SparkleLib.csproj", "{2C914413-B31C-4362-93C7-1AE34F09112A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2C914413-B31C-4362-93C7-1AE34F09112A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2C914413-B31C-4362-93C7-1AE34F09112A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2C914413-B31C-4362-93C7-1AE34F09112A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2C914413-B31C-4362-93C7-1AE34F09112A}.Release|Any CPU.Build.0 = Release|Any CPU
{709CB8F4-F82F-4C94-B4E2-DC502087525B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{709CB8F4-F82F-4C94-B4E2-DC502087525B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{709CB8F4-F82F-4C94-B4E2-DC502087525B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{709CB8F4-F82F-4C94-B4E2-DC502087525B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = SparkleShare.csproj
EndGlobalSection
EndGlobal

View file

@ -1,70 +0,0 @@
// 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.Drawing;
using MonoMac.Foundation;
using MonoMac.AppKit;
using MonoMac.ObjCRuntime;
using MonoMac.WebKit;
namespace SparkleShare {
public class SparkleWindow : NSWindow {
public readonly string LocalPath;
private NSImage SideSplash;
public SparkleWindow () : base ()
{
SetFrame (new RectangleF (0, 0, 640, 480), true);
Center ();
StyleMask = (NSWindowStyle.Closable |
NSWindowStyle.Miniaturizable |
NSWindowStyle.Titled);
MaxSize = new SizeF (640, 480);
MinSize = new SizeF (640, 480);
HasShadow = true;
BackingType = NSBackingStore.Buffered;
SideSplash = new NSImage (NSBundle.MainBundle.ResourcePath + "/Pixmaps/side-splash.png");
SideSplash.Size = new SizeF (150, 480);
NSText tv = new NSText (new RectangleF (200, 200, 200, 200)) {
Value = "TEST"
};
ContentView.AddSubview (new NSImageView (new RectangleF (0, 0, 150, 480)) { Image = SideSplash});
ContentView.AddSubview (new NSTextField (new RectangleF (200, 100, 128, 31)) { BezelStyle = NSTextFieldBezelStyle.Rounded});
ContentView.AddSubview (tv);
NSApplication.SharedApplication.ActivateIgnoringOtherApps (true);
MakeKeyAndOrderFront (this);
}
}
}

View file

@ -16,6 +16,7 @@
using System;
using System.Drawing;
using System.IO;
using System.Timers;
using MonoMac.Foundation;
using MonoMac.AppKit;
@ -39,7 +40,6 @@ namespace SparkleShare {
private NSMenuItem [] FolderMenuItems;
private NSMenuItem SyncMenuItem;
private NSMenuItem NotificationsMenuItem;
private NSMenuItem AboutMenuItem;
private delegate void Task ();
private EventHandler [] Tasks;
@ -53,7 +53,7 @@ namespace SparkleShare {
public SparkleStatusIcon () : base ()
{
{
Animation = CreateAnimation ();
@ -69,7 +69,12 @@ namespace SparkleShare {
SparkleShare.Controller.FolderSizeChanged += delegate {
InvokeOnMainThread (delegate {
if (!Animation.Enabled)
SetNormalState ();
UpdateMenu ();
});
};
@ -123,11 +128,20 @@ namespace SparkleShare {
InvokeOnMainThread (delegate {
StatusItem.AlternateImage = new NSImage (NSBundle.MainBundle.ResourcePath + "/Pixmaps/idle" + FrameNumber + ".png");
StatusItem.AlternateImage.Size = new SizeF (16, 16);
string image_path =
Path.Combine (NSBundle.MainBundle.ResourcePath,
"Pixmaps", "idle" + FrameNumber + ".png");
StatusItem.Image = new NSImage (NSBundle.MainBundle.ResourcePath + "/Pixmaps/idle" + FrameNumber + ".png");
StatusItem.Image = new NSImage (image_path);
StatusItem.Image.Size = new SizeF (16, 16);
string alternate_image_path =
Path.Combine (NSBundle.MainBundle.ResourcePath,
"Pixmaps", "idle" + FrameNumber + ".png");
StatusItem.AlternateImage = new NSImage (alternate_image_path);
StatusItem.AlternateImage.Size = new SizeF (16, 16);
});
@ -160,23 +174,27 @@ namespace SparkleShare {
FolderMenuItem.Activated += delegate {
SparkleShare.Controller.OpenSparkleShareFolder ();
};
//FolderMenuItem.Image = new NSImage (NSBundle.MainBundle.ResourcePath + "/Pixmaps/sparkleshare.icns");
FolderMenuItem.Image = NSImage.ImageNamed ("NSFolder");
string folder_icon_path = Path.Combine (NSBundle.MainBundle.ResourcePath,
"sparkleshare-mac.icns");
FolderMenuItem.Image = new NSImage (folder_icon_path);
FolderMenuItem.Image.Size = new SizeF (16, 16);
Menu.AddItem (FolderMenuItem);
if (SparkleShare.Controller.Folders.Count > 0) {
FolderMenuItems = new NSMenuItem [SparkleShare.Controller.Folders.Count];
Tasks = new EventHandler [SparkleShare.Controller.Folders.Count];
int i = 0;
foreach (string path in SparkleShare.Controller.Folders) {
// TODO
// if (repo.HasUnsyncedChanges)
// folder_action.IconName = "dialog-error";
@ -198,67 +216,82 @@ namespace SparkleShare {
} else {
// TODO: No Remote Folders Yet
FolderMenuItems = new NSMenuItem [1];
FolderMenuItems [0] = new NSMenuItem () {
Title = "No Remote Folders Yet"
};
Menu.AddItem (FolderMenuItems [0]);
}
Menu.AddItem (NSMenuItem.SeparatorItem);
SyncMenuItem = new NSMenuItem () {
Title = "Add Remote Folder..."
Title = "Add Remote Folder"
};
if (SparkleShare.Controller.FirstRun)
SyncMenuItem.Enabled = false;
if (!SparkleShare.Controller.FirstRun) {
SyncMenuItem.Activated += delegate {
new SparkleWindow ();
};
SyncMenuItem.Activated += delegate {
InvokeOnMainThread (delegate {
NSApplication.SharedApplication.ActivateIgnoringOtherApps (true);
if (SparkleUI.Intro == null) {
SparkleUI.Intro = new SparkleIntro ();
SparkleUI.Intro.ShowServerForm (true);
}
if (!SparkleUI.Intro.IsVisible)
SparkleUI.Intro.ShowServerForm (true);
SparkleUI.Intro.OrderFrontRegardless ();
SparkleUI.Intro.MakeKeyAndOrderFront (this);
});
};
}
Menu.AddItem (SyncMenuItem);
Menu.AddItem (NSMenuItem.SeparatorItem);
NotificationsMenuItem = new NSMenuItem () {
Title = "Show Notifications"
};
NotificationsMenuItem = new NSMenuItem ();
if (SparkleShare.Controller.NotificationsEnabled)
NotificationsMenuItem.State = NSCellStateValue.On;
NotificationsMenuItem.Title = "Turn Notifications Off";
else
NotificationsMenuItem.Title = "Turn Notifications On";
NotificationsMenuItem.Activated += delegate {
SparkleShare.Controller.ToggleNotifications ();
InvokeOnMainThread (delegate {
if (SparkleShare.Controller.NotificationsEnabled)
NotificationsMenuItem.State = NSCellStateValue.On;
else
NotificationsMenuItem.State = NSCellStateValue.Off;
if (SparkleShare.Controller.NotificationsEnabled)
NotificationsMenuItem.Title = "Turn Notifications Off";
else
NotificationsMenuItem.Title = "Turn Notifications On";
});
};
Menu.AddItem (NotificationsMenuItem);
Menu.AddItem (NSMenuItem.SeparatorItem);
AboutMenuItem = new NSMenuItem () {
Title = "About"
};
AboutMenuItem.Activated += delegate {
// TODO
};
Menu.AddItem (AboutMenuItem);
StatusItem.Menu = Menu;
StatusItem.Menu.Update ();
Console.WriteLine ("MENU UPDATED");
}
@ -269,27 +302,31 @@ namespace SparkleShare {
{
return delegate {
SparkleLog log = SparkleUI.OpenLogs.Find (delegate (SparkleLog l) {
return l.LocalPath.Equals (path);
});
InvokeOnMainThread (delegate {
// Check whether the log is already open, create a new one if
// that's not the case or present it to the user if it is
if (log == null) {
NSApplication.SharedApplication.ActivateIgnoringOtherApps (true);
InvokeOnMainThread (delegate {
SparkleLog log = SparkleUI.OpenLogs.Find (delegate (SparkleLog l) {
return l.LocalPath.Equals (path);
});
// Check whether the log is already open, create a new one if
// that's not the case or present it to the user if it is
if (log == null) {
SparkleUI.OpenLogs.Add (new SparkleLog (path));
});
} else {
InvokeOnMainThread (delegate {
log.OrderFrontRegardless ();
});
SparkleUI.OpenLogs [SparkleUI.OpenLogs.Count - 1].MakeKeyAndOrderFront (this);
} else {
log.OrderFrontRegardless ();
log.MakeKeyAndOrderFront (this);
}
});
}
};
}
@ -380,13 +417,11 @@ namespace SparkleShare {
public override void MenuWillOpen (NSMenu menu)
{
Console.WriteLine ("OPENED");
InvokeOnMainThread (delegate {
foreach (SparkleLog log in SparkleUI.OpenLogs)
log.OrderFrontRegardless ();
InvokeOnMainThread (delegate {
SparkleUI.NewEvents = 0;
NSApplication.SharedApplication.DockTile.BadgeLabel = null;
});

View file

@ -0,0 +1,148 @@
// 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.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Timers;
using MonoMac.Foundation;
using MonoMac.AppKit;
using MonoMac.ObjCRuntime;
using MonoMac.WebKit;
namespace SparkleShare {
public partial class AppDelegate : NSApplicationDelegate {
public override void WillBecomeActive (NSNotification notification)
{
SparkleUI.NewEvents = 0;
NSApplication.SharedApplication.DockTile.BadgeLabel = null;
}
}
public class SparkleUI : AppDelegate
{
public static SparkleStatusIcon StatusIcon;
public static List <SparkleLog> OpenLogs;
public static int NewEvents;
public static SparkleIntro Intro;
public static NSFont Font;
public SparkleUI ()
{
NSApplication.Init ();
SetSparkleIcon ();
// TODO: Getting crashes when I remove this
NSApplication.SharedApplication.ApplicationIconImage
= NSImage.ImageNamed ("sparkleshare.icns");
Font = NSFontManager.SharedFontManager.FontWithFamily
("Lucida Grande", NSFontTraitMask.Condensed, 0, 13);
OpenLogs = new List <SparkleLog> ();
StatusIcon = new SparkleStatusIcon ();
NewEvents = 0;
SparkleShare.Controller.NotificationRaised += delegate {
InvokeOnMainThread (delegate {
NewEvents++;
NSApplication.SharedApplication.DockTile.BadgeLabel = NewEvents.ToString ();
foreach (SparkleLog log in SparkleUI.OpenLogs)
log.UpdateEventLog ();
NSApplication.SharedApplication.RequestUserAttention
(NSRequestUserAttentionType.InformationalRequest);
});
};
SparkleShare.Controller.AvatarFetched += delegate {
InvokeOnMainThread (delegate {
foreach (SparkleLog log in SparkleUI.OpenLogs)
log.UpdateEventLog ();
});
};
SparkleShare.Controller.OnIdle += delegate {
InvokeOnMainThread (delegate {
foreach (SparkleLog log in SparkleUI.OpenLogs)
log.UpdateEventLog ();
});
};
if (SparkleShare.Controller.FirstRun) {
Intro = new SparkleIntro ();
Intro.ShowAccountForm ();
}
}
public void SetSparkleIcon ()
{
string folder_icon_path = Path.Combine (NSBundle.MainBundle.ResourcePath,
"sparkleshare-mac.icns");
NSImage folder_icon = new NSImage (folder_icon_path);
NSWorkspace.SharedWorkspace.SetIconforFile (folder_icon,
SparkleShare.Controller.SparklePath, 0);
}
public void Run ()
{
NSApplication.Main (new string [0]);
}
}
}

View file

@ -0,0 +1,168 @@
// 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.Collections.Generic;
using System.Drawing;
using System.IO;
using MonoMac.Foundation;
using MonoMac.AppKit;
using MonoMac.ObjCRuntime;
using MonoMac.WebKit;
using Mono.Unix;
namespace SparkleShare {
public class SparkleWindow : NSWindow {
private NSImage SideSplash;
private NSImageView SideSplashView;
public List <NSButton> Buttons;
public string Header;
public string Description;
private NSTextField HeaderTextField;
private NSTextField DescriptionTextField;
public SparkleWindow () : base ()
{
SetFrame (new RectangleF (0, 0, 640, 380), true);
StyleMask = NSWindowStyle.Titled;
MaxSize = new SizeF (640, 380);
MinSize = new SizeF (640, 380);
HasShadow = true;
BackingType = NSBackingStore.Buffered;
Center ();
string side_splash_path = Path.Combine (NSBundle.MainBundle.ResourcePath,
"Pixmaps", "side-splash.png");
SideSplash = new NSImage (side_splash_path) {
Size = new SizeF (150, 480)
};
SideSplashView = new NSImageView () {
Image = SideSplash,
Frame = new RectangleF (0, 0, 150, 480)
};
Buttons = new List <NSButton> ();
HeaderTextField = new NSTextField () {
Frame = new RectangleF (190, Frame.Height - 100, 318, 48),
BackgroundColor = NSColor.WindowBackground,
Bordered = false,
Editable = false,
Font = NSFontManager.SharedFontManager.FontWithFamily
("Lucida Grande", NSFontTraitMask.Bold, 0, 15)
};
DescriptionTextField = new NSTextField () {
Frame = new RectangleF (190, Frame.Height - 155 , 640 - 240, 64),
BackgroundColor = NSColor.WindowBackground,
Bordered = false,
Editable = false,
Font = SparkleUI.Font
};
NSApplication.SharedApplication.ActivateIgnoringOtherApps (true);
MakeKeyAndOrderFront (this);
OrderFrontRegardless ();
}
public void Reset () {
ContentView.Subviews = new NSView [0];
Buttons = new List <NSButton> ();
Header = "";
Description = "";
}
public void ShowAll () {
HeaderTextField.StringValue = Header;
DescriptionTextField.StringValue = Description;
ContentView.AddSubview (HeaderTextField);
if (!Description.Equals (""))
ContentView.AddSubview (DescriptionTextField);
ContentView.AddSubview (SideSplashView);
int i = 1;
if (Buttons.Count > 0) {
DefaultButtonCell = Buttons [0].Cell;
foreach (NSButton button in Buttons) {
button.BezelStyle = NSBezelStyle.Rounded;
button.Frame = new RectangleF (Frame.Width - 15 - (105 * i) , 12, 105, 32);
if (button.Title.Contains (" "))
button.Frame = new RectangleF (Frame.Width - 30 - (105 * i) , 12, 120, 32);
button.Font = SparkleUI.Font;
ContentView.AddSubview (button);
i++;
}
}
}
public override void OrderFrontRegardless ()
{
NSApplication.SharedApplication.AddWindowsItem (this, "SparkleShare Setup", false);
base.OrderFrontRegardless ();
}
public override void Close ()
{
OrderOut (this);
NSApplication.SharedApplication.RemoveWindowsItem (this);
return;
}
}
}

View file

@ -25,7 +25,6 @@ using System.Net;
using System.Threading;
using System.Text.RegularExpressions;
using System.Xml;
using System.Security.Cryptography;
using System.Text;
@ -36,6 +35,8 @@ namespace SparkleShare {
public List <SparkleRepo> Repositories;
public string FolderSize;
public bool FirstRun;
public readonly string SparklePath;
public event OnQuitWhileSyncingEventHandler OnQuitWhileSyncing;
@ -52,6 +53,9 @@ namespace SparkleShare {
public event FolderSizeChangedEventHandler FolderSizeChanged;
public delegate void FolderSizeChangedEventHandler (string folder_size);
public event AvatarFetchedEventHandler AvatarFetched;
public delegate void AvatarFetchedEventHandler ();
public event OnIdleEventHandler OnIdle;
public delegate void OnIdleEventHandler ();
@ -83,7 +87,9 @@ namespace SparkleShare {
AddToBookmarks ();
FolderSize = GetFolderSize ();
SparklePath = SparklePaths.SparklePath;
string global_config_file_path = SparkleHelpers.CombineMore (SparklePaths.SparkleConfigPath, "config");
@ -151,14 +157,14 @@ namespace SparkleShare {
}
// Uploads the user's public key to the server
public bool AcceptInvitation (string server, string folder, string token)
{
// The location of the user's public key for SparkleShare
string public_key_file_path = SparkleHelpers.CombineMore (SparklePaths.HomePath, ".ssh",
"sparkleshare." + SparkleShare.Controller.UserEmail + ".key.pub");
"sparkleshare." + UserEmail + ".key.pub");
if (!File.Exists (public_key_file_path))
return false;
@ -233,16 +239,20 @@ namespace SparkleShare {
}
public abstract string EventLogHTML { get; }
public abstract string DayEntryHTML { get; }
public abstract string EventEntryHTML { get; }
public string GetHTMLLog (string name)
{
List <SparkleCommit> commits = GetLog (name);
List <ActivityDay> activity_days = new List <ActivityDay> ();
List <SparkleCommit> commits = GetLog (name);
List <ActivityDay> activity_days = new List <ActivityDay> ();
foreach (SparkleCommit commit in commits) {
GetAvatar (commit.UserEmail, 32);
GetAvatar (commit.UserEmail, 36);
bool commit_inserted = false;
foreach (ActivityDay stored_activity_day in activity_days) {
@ -261,34 +271,20 @@ namespace SparkleShare {
if (!commit_inserted) {
ActivityDay activity_day = new ActivityDay (commit.DateTime);
activity_day.Add (commit);
activity_days.Add (activity_day);
ActivityDay activity_day = new ActivityDay (commit.DateTime);
activity_day.Add (commit);
activity_days.Add (activity_day);
}
}
StreamReader reader;
reader = new StreamReader (Defines.PREFIX + "/share/sparkleshare/html/event-log.html");
string event_log_html = reader.ReadToEnd ();
reader.Close ();
reader = new StreamReader (Defines.PREFIX + "/share/sparkleshare/html/day-entry.html");
string day_entry_html = reader.ReadToEnd ();
reader.Close ();
reader = new StreamReader (Defines.PREFIX + "/share/sparkleshare/html/event-entry.html");
string event_entry_html = reader.ReadToEnd ();
reader.Close ();
string event_log_html = EventLogHTML;
string day_entry_html = DayEntryHTML;
string event_entry_html = EventEntryHTML;
string event_log = "";
foreach (ActivityDay activity_day in activity_days) {
@ -304,14 +300,17 @@ namespace SparkleShare {
event_entry += "<dt>Edited</dt>";
foreach (string file_path in change_set.Edited) {
string absolute_file_path = SparkleHelpers.CombineMore (SparklePaths.SparklePath,
name, file_path);
if (File.Exists (absolute_file_path)) {
if (File.Exists (SparkleHelpers.CombineMore (SparklePaths.SparklePath ,name , file_path))) {
event_entry += "<dd><a href='#'>" + file_path + "</a></dd>";
event_entry += "<dd><a href='" + absolute_file_path + "'>" + file_path + "</a></dd>";
} else {
event_entry += "<dd>" + SparkleHelpers.CombineMore (SparklePaths.SparklePath, name, file_path) + "</dd>";
event_entry += "<dd>" + file_path + "</dd>";
}
@ -325,14 +324,16 @@ namespace SparkleShare {
event_entry += "<dt>Added</dt>";
foreach (string file_path in change_set.Added) {
string absolute_file_path = SparkleHelpers.CombineMore (SparklePaths.SparklePath,
name, file_path);
if (File.Exists (absolute_file_path)) {
if (File.Exists (SparkleHelpers.CombineMore (SparklePaths.SparklePath ,name , file_path))) {
event_entry += "<dd><a href='#'>" + file_path + "</a></dd>";
event_entry += "<dd><a href='" + absolute_file_path + "'>" + file_path + "</a></dd>";
} else {
event_entry += "<dd>" + SparkleHelpers.CombineMore (SparklePaths.SparklePath ,name , file_path) + "</dd>";
event_entry += "<dd>" + file_path + "</dd>";
}
@ -346,33 +347,36 @@ namespace SparkleShare {
foreach (string file_path in change_set.Deleted) {
if (File.Exists (SparkleHelpers.CombineMore (SparklePaths.SparklePath ,name , file_path))) {
event_entry += "<dd><a href='#'>" + file_path + "</a></dd>";
string absolute_file_path = SparkleHelpers.CombineMore (SparklePaths.SparklePath,
name, file_path);
if (File.Exists (absolute_file_path)) {
event_entry += "<dd><a href='" + absolute_file_path + "'>" + file_path + "</a></dd>";
} else {
event_entry += "<dd>" + SparkleHelpers.CombineMore (SparklePaths.SparklePath ,name , file_path) + "</dd>";
event_entry += "<dd>" + file_path + "</dd>";
}
}
}
Console.WriteLine(GetAvatar (change_set.UserEmail, 32));
event_entry += "</dl>";
event_entries += event_entry_html.Replace ("<!-- $event-entry-content -->", event_entry)
.Replace ("<!-- $event-user-name -->", change_set.UserName)
.Replace ("<!-- $event-avatar-url -->", "file://" +GetAvatar (change_set.UserEmail, 32) )
.Replace ("<!-- $event-avatar-url -->", "file://" + GetAvatar (change_set.UserEmail, 36) )
.Replace ("<!-- $event-time -->", change_set.DateTime.ToString ("H:mm"));
}
string day_entry = "";
DateTime today = DateTime.Now;
DateTime today = DateTime.Now;
DateTime yesterday = DateTime.Now.AddDays (-1);
if (today.Day == activity_day.DateTime.Day &&
@ -398,7 +402,8 @@ Console.WriteLine(GetAvatar (change_set.UserEmail, 32));
}
string html = event_log_html.Replace ("<!-- $event-log-content -->", event_log);
return html;
@ -553,6 +558,12 @@ Console.WriteLine(GetAvatar (change_set.UserEmail, 32));
if (FolderListChanged != null)
FolderListChanged ();
FolderSize = GetFolderSize ();
if (FolderSizeChanged != null)
FolderSizeChanged (FolderSize);
}
@ -582,6 +593,12 @@ Console.WriteLine(GetAvatar (change_set.UserEmail, 32));
if (FolderListChanged != null)
FolderListChanged ();
FolderSize = GetFolderSize ();
if (FolderSizeChanged != null)
FolderSizeChanged (FolderSize);
}
@ -822,7 +839,7 @@ Console.WriteLine(GetAvatar (change_set.UserEmail, 32));
private void WriteUserInfo (string user_name, string user_email)
{
string global_config_file_path = SparkleHelpers.CombineMore (SparklePaths.SparkleConfigPath, "config");
string global_config_file_path = Path.Combine (SparklePaths.SparkleConfigPath, "config");
// Write the user's information to a text file
TextWriter writer = new StreamWriter (global_config_file_path);
@ -831,7 +848,7 @@ Console.WriteLine(GetAvatar (change_set.UserEmail, 32));
"\temail = " + user_email);
writer.Close ();
SparkleHelpers.DebugInfo ("Config", "Created '" + global_config_file_path + "'");
SparkleHelpers.DebugInfo ("Config", "Updated '" + global_config_file_path + "'");
}
@ -840,18 +857,29 @@ Console.WriteLine(GetAvatar (change_set.UserEmail, 32));
public void GenerateKeyPair ()
{
string keys_path = SparklePaths.SparkleKeysPath;
string keys_path = SparklePaths.SparkleKeysPath;
string key_file_name = "sparkleshare." + UserEmail + ".key";
string key_file_path = Path.Combine (keys_path, key_file_name);
if (File.Exists (key_file_path)) {
SparkleHelpers.DebugInfo ("Config", "Key already exists ('" + key_file_name + "'), " +
"leaving it untouched");
return;
}
Process process = new Process () {
EnableRaisingEvents = true
};
if (!Directory.Exists (keys_path))
Directory.CreateDirectory (keys_path);
if (!File.Exists (key_file_name)) {
Process process = new Process () {
EnableRaisingEvents = true
};
process.StartInfo.WorkingDirectory = keys_path;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
@ -866,8 +894,11 @@ Console.WriteLine(GetAvatar (change_set.UserEmail, 32));
process.Exited += delegate {
SparkleHelpers.DebugInfo ("Config", "Created key '" + key_file_name + "'");
SparkleHelpers.DebugInfo ("Config", "Created key '" + key_file_name + ".pub'");
SparkleHelpers.DebugInfo ("Config", "Created private key '" + key_file_name + "'");
SparkleHelpers.DebugInfo ("Config", "Created public key '" + key_file_name + ".pub'");
File.Copy (key_file_path + ".pub",
Path.Combine (SparklePath, "Your key.txt"));
};
@ -890,10 +921,10 @@ Console.WriteLine(GetAvatar (change_set.UserEmail, 32));
} else {
TextWriter writer = new StreamWriter (ssh_config_file_path);
TextWriter writer = new StreamWriter (ssh_config_file_path);
writer.WriteLine (ssh_config);
writer.Close ();
}
}
@ -902,30 +933,94 @@ Console.WriteLine(GetAvatar (change_set.UserEmail, 32));
private void EnableHostKeyCheckingForHost (string host)
{
string ssh_config_file_path = SparkleHelpers.CombineMore (SparklePaths.HomePath, ".ssh", "config");
string ssh_config = "Host " + host + "\n\tStrictHostKeyChecking no";
string ssh_config_file_path = SparkleHelpers.CombineMore
(SparklePaths.HomePath, ".ssh", "config");
string ssh_config = "Host " + host + "\n" +
"\tStrictHostKeyChecking no";
if (File.Exists (ssh_config_file_path)) {
StreamReader reader = new StreamReader (ssh_config_file_path);
string current_ssh_config = reader.ReadToEnd ();
reader.Close ();
if (current_ssh_config.Equals (ssh_config)) {
File.Delete (ssh_config_file_path);
current_ssh_config = current_ssh_config.Remove (current_ssh_config.IndexOf (ssh_config),
ssh_config.Length);
if (current_ssh_config.Trim ().Equals ("")) {
File.Delete (ssh_config_file_path);
} else {
current_ssh_config = current_ssh_config.Remove (current_ssh_config.IndexOf (ssh_config),
ssh_config.Length);
TextWriter writer = new StreamWriter (ssh_config_file_path);
writer.WriteLine (current_ssh_config);
writer.Close ();
}
}
}
// Gets the avatar for a specific email address and size
public string GetAvatar (string email, int size)
{
string avatar_path = SparkleHelpers.CombineMore (SparklePaths.SparkleLocalIconPath,
size + "x" + size, "status");
if (!Directory.Exists (avatar_path)) {
Directory.CreateDirectory (avatar_path);
SparkleHelpers.DebugInfo ("Config", "Created '" + avatar_path + "'");
}
string avatar_file_path = SparkleHelpers.CombineMore (avatar_path, "avatar-" + email);
if (File.Exists (avatar_file_path)) {
return avatar_file_path;
} else {
// Let's try to get the person's gravatar for next time
WebClient web_client = new WebClient ();
Uri uri = new Uri ("http://www.gravatar.com/avatar/" + GetMD5 (email) +
".jpg?s=" + size + "&d=404");
string tmp_file_path = SparkleHelpers.CombineMore (SparklePaths.SparkleTmpPath, email + size);
if (!File.Exists (tmp_file_path)) {
web_client.DownloadFileAsync (uri, tmp_file_path);
web_client.DownloadFileCompleted += delegate {
if (File.Exists (avatar_file_path))
File.Delete (avatar_file_path);
FileInfo tmp_file_info = new FileInfo (tmp_file_path);
if (tmp_file_info.Length > 255)
File.Move (tmp_file_path, avatar_file_path);
if (AvatarFetched != null)
AvatarFetched ();
};
}
// Fall back to a generic icon if there is no gravatar
if (File.Exists (avatar_file_path))
return avatar_file_path;
else
return null;
}
}
@ -991,7 +1086,7 @@ Console.WriteLine(GetAvatar (change_set.UserEmail, 32));
} catch (Exception e) {
SparkleHelpers.DebugInfo ("Controller", "Error moving folder: " + e.Message);
}
@ -1013,11 +1108,12 @@ Console.WriteLine(GetAvatar (change_set.UserEmail, 32));
SparkleHelpers.ClearAttributes (tmp_folder);
Directory.Delete (tmp_folder, true);
SparkleHelpers.DebugInfo ("Config", "Deleted temporary directory: " + tmp_folder);
SparkleHelpers.DebugInfo ("Config",
"Deleted temporary directory: " + tmp_folder);
}
if (FolderFetchError != null)
FolderFetchError ();
@ -1029,71 +1125,13 @@ Console.WriteLine(GetAvatar (change_set.UserEmail, 32));
}
// Gets the avatar for a specific email address and size
public static string GetAvatar (string email, int size)
{
string avatar_path = SparkleHelpers.CombineMore (SparklePaths.SparkleLocalIconPath,
size + "x" + size, "status");
if (!Directory.Exists (avatar_path)) {
Directory.CreateDirectory (avatar_path);
SparkleHelpers.DebugInfo ("Config", "Created '" + avatar_path + "'");
}
string avatar_file_path = SparkleHelpers.CombineMore (avatar_path, "avatar-" + email);
if (File.Exists (avatar_file_path)) {
return avatar_file_path;
} else {
// Let's try to get the person's gravatar for next time
WebClient web_client = new WebClient ();
Uri uri = new Uri ("http://www.gravatar.com/avatar/" + GetMD5 (email) +
".jpg?s=" + size + "&d=404");
string tmp_file_path = SparkleHelpers.CombineMore (SparklePaths.SparkleTmpPath, email + size);
if (!File.Exists (tmp_file_path)) {
web_client.DownloadFileAsync (uri, tmp_file_path);
web_client.DownloadFileCompleted += delegate {
if (File.Exists (avatar_file_path))
File.Delete (avatar_file_path);
FileInfo tmp_file_info = new FileInfo (tmp_file_path);
if (tmp_file_info.Length > 255)
File.Move (tmp_file_path, avatar_file_path);
};
}
// Fall back to a generic icon if there is no gravatar
if (File.Exists (avatar_file_path))
return avatar_file_path;
else
return null;
}
}
// Creates an MD5 hash of input
public static string GetMD5 (string s)
{
MD5 md5 = new MD5CryptoServiceProvider ();
Byte[] bytes = ASCIIEncoding.Default.GetBytes (s);
Byte[] encodedBytes = md5.ComputeHash (bytes);
return BitConverter.ToString (encodedBytes).ToLower ().Replace ("-", "");
Byte[] encoded_bytes = md5.ComputeHash (bytes);
return BitConverter.ToString (encoded_bytes).ToLower ().Replace ("-", "");
}
@ -1118,7 +1156,7 @@ Console.WriteLine(GetAvatar (change_set.UserEmail, 32));
Quit ();
}
public void Quit ()
{
@ -1134,7 +1172,17 @@ Console.WriteLine(GetAvatar (change_set.UserEmail, 32));
Environment.Exit (0);
}
}
// Checks to see if an email address is valid
public bool IsValidEmail (string email)
{
Regex regex = new Regex (@"^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$", RegexOptions.IgnoreCase);
return regex.IsMatch (email);
}
}
@ -1142,7 +1190,7 @@ Console.WriteLine(GetAvatar (change_set.UserEmail, 32));
public class ChangeSet : SparkleCommit {
}
// All commits that happened on a day
public class ActivityDay : List <SparkleCommit>
@ -1158,6 +1206,6 @@ Console.WriteLine(GetAvatar (change_set.UserEmail, 32));
}
}
}
}

View file

@ -89,11 +89,11 @@ namespace SparkleShare {
case PlatformID.Unix:
SetProcessName ("sparkleshare");
Controller = new SparkleLinController ();
//Controller = new SparkleLinController ();
break;
case PlatformID.MacOSX:
//Controller = new SparkleMacController ();
Controller = new SparkleMacController ();
break;
case PlatformID.Win32NT:

BIN
data/avatar-default.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -4,7 +4,11 @@
<table>
<tr>
<td><img src='<!-- $event-avatar-url -->'></td>
<td>
<div class='no-buddy-icon'>
<div class='buddy-icon' style='background-image: url("<!-- $event-avatar-url -->")'></div>
</div>
</td>
<td width='100%'>
<b><!-- $event-user-name --></b><br>
<!-- $event-entry-content -->

View file

@ -8,12 +8,13 @@
<style>
body {
background-color: <!-- $body-background-color -->;
background-color: #f1f1f1;
color: <!-- $body-color -->;
font-size: <!-- $body-font-size -->;
font-family: <!-- $body-font-family -->;
margin: 0;
padding: 0;
margin-top: 20px;
}
small {
@ -22,18 +23,39 @@
}
.day-entry-header {
background-color: <!-- $day-entry-header-background-color -->;
padding: 9px;
background-color: #ccc;
color: #fff;
padding: 3px;
text-align: center;
margin-left: auto;
margin-right: auto;
-webkit-border-radius: 25px;
width: 128px;
font-weight: lighter;
-webkit-box-shadow: 0px 1px 0px #aaa;
}
.day-entry-content {
padding: 12px;
padding: 9px;
}
.dd {
dl {
padding: 0;
margin: 0;
padding-bottom: 15px;
}
dt {
padding-bottom: 9px;
padding-top: 9px;
}
dd {
padding-left: 0;
margin-left: 12px;
text-overflow: ellipsis;
}
a {
color: <!-- $a-color -->;
text-decoration: none;
@ -52,6 +74,28 @@
color: <!-- $secondary-font-color -->;
}
.no-buddy-icon {
margin-right: 12px;
width: 36px;
height: 36px;
background-image: url('<!-- $no-buddy-icon-background-image -->');
background-repeat: no-repeat;
background-position: center;
}
.buddy-icon {
width: 36px;
height: 36px;
}
.event-entry-content {
background-color: #fff;
margin: 12px;
padding: 12px;
-webkit-border-radius: 6px;
border: <!-- $small-color --> 1px solid;
}
</style>
</head>

View file

Before

Width:  |  Height:  |  Size: 732 B

After

Width:  |  Height:  |  Size: 732 B

View file

Before

Width:  |  Height:  |  Size: 797 B

After

Width:  |  Height:  |  Size: 797 B

View file

Before

Width:  |  Height:  |  Size: 803 B

After

Width:  |  Height:  |  Size: 803 B

View file

Before

Width:  |  Height:  |  Size: 822 B

After

Width:  |  Height:  |  Size: 822 B

View file

Before

Width:  |  Height:  |  Size: 818 B

After

Width:  |  Height:  |  Size: 818 B

View file

Before

Width:  |  Height:  |  Size: 831 B

After

Width:  |  Height:  |  Size: 831 B

View file

Before

Width:  |  Height:  |  Size: 826 B

After

Width:  |  Height:  |  Size: 826 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View file

Before

Width:  |  Height:  |  Size: 283 B

After

Width:  |  Height:  |  Size: 283 B

View file

Before

Width:  |  Height:  |  Size: 216 B

After

Width:  |  Height:  |  Size: 216 B

BIN
data/sparkleshare-mac.icns Normal file

Binary file not shown.

1087
data/sparkleshare-mac.svg Normal file

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 53 KiB