Merge with upstream (11a932b73e)

This commit is contained in:
wimh 2011-10-02 00:52:21 +02:00
parent 04b3b43f88
commit 9f729e5e3e
40 changed files with 2546 additions and 1993 deletions

1
.gitignore vendored
View file

@ -47,3 +47,4 @@ SparkleShare/Nautilus/sparkleshare-nautilus-extension.py
gnome-doc-utils.make
/sparkleshare-*
desktop.ini
_ReSharper.*

View file

@ -18,6 +18,7 @@
using System;
using System.IO;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Xml;
namespace SparkleLib {
@ -25,12 +26,15 @@ namespace SparkleLib {
// Sets up a fetcher that can get remote folders
public class SparkleFetcherGit : SparkleFetcherBase {
private SparkleGit git;
public SparkleFetcherGit (string server, string remote_folder, string target_folder) :
base (server, remote_folder, target_folder)
{
remote_folder = remote_folder.Trim ("/".ToCharArray ());
if (server.StartsWith("http")) {
if (server.StartsWith ("http")) {
base.target_folder = target_folder;
base.remote_url = server;
return;
@ -57,13 +61,20 @@ namespace SparkleLib {
} else {
server = server.TrimEnd ("/".ToCharArray ());
string protocol = "ssh://";
if (server.StartsWith ("ssh://"))
server = server.Substring (6);
if (server.StartsWith ("git://")) {
server = server.Substring (6);
protocol = "git://";
}
if (!server.Contains ("@"))
server = "git@" + server;
server = "ssh://" + server;
server = protocol + server;
}
base.target_folder = target_folder;
@ -73,15 +84,51 @@ namespace SparkleLib {
public override bool Fetch ()
{
SparkleGit git = new SparkleGit (SparklePaths.SparkleTmpPath,
"clone \"" + base.remote_url + "\" " + "\"" + base.target_folder + "\"");
this.git = new SparkleGit (SparkleConfig.DefaultConfig.TmpPath,
"clone " +
"--progress " + // Redirects progress stats to standarderror
"\"" + base.remote_url + "\" " + "\"" + base.target_folder + "\"");
this.git.StartInfo.RedirectStandardError = true;
this.git.Start ();
double percentage = 1.0;
Regex progress_regex = new Regex (@"([0-9]+)%", RegexOptions.Compiled);
while (!this.git.StandardError.EndOfStream) {
string line = this.git.StandardError.ReadLine ();
Match match = progress_regex.Match (line);
double number = 0.0;
if (match.Success) {
number = double.Parse (match.Groups [1].Value);
// The cloning progress consists of two stages: the "Compressing
// objects" stage which we count as 20% of the total progress, and
// the "Receiving objects" stage which we count as the last 80%
if (line.Contains ("|"))
// "Receiving objects" stage
number = (number / 100 * 75 + 20);
else
// "Compressing objects" stage
number = (number / 100 * 20);
}
if (number >= percentage) {
percentage = number;
// FIXME: for some reason it doesn't go above 95%
base.OnProgressChanged (percentage);
}
System.Threading.Thread.Sleep (100);
}
this.git.WaitForExit ();
git.Start ();
git.WaitForExit ();
SparkleHelpers.DebugInfo ("Git", "Exit code " + this.git.ExitCode.ToString ());
SparkleHelpers.DebugInfo ("Git", "Exit code " + git.ExitCode.ToString ());
if (git.ExitCode != 0) {
if (this.git.ExitCode != 0) {
return false;
} else {
InstallConfiguration ();
@ -91,11 +138,22 @@ namespace SparkleLib {
}
public override void Stop ()
{
if (this.git != null) {
this.git.Kill ();
this.git.Dispose ();
}
base.Stop ();
}
// Install the user's name and email and some config into
// the newly cloned repository
private void InstallConfiguration ()
{
string global_config_file_path = Path.Combine (SparklePaths.SparkleConfigPath, "config.xml");
string global_config_file_path = Path.Combine (SparkleConfig.DefaultConfig.TmpPath, "config.xml");
if (!File.Exists (global_config_file_path))
return;
@ -103,17 +161,20 @@ namespace SparkleLib {
string repo_config_file_path = SparkleHelpers.CombineMore (base.target_folder, ".git", "config");
string config = String.Join (Environment.NewLine, File.ReadAllLines (repo_config_file_path));
string n = Environment.NewLine;
// Show special characters in the logs
config = config.Replace ("[core]" + n,
"[core]" + n + "quotepath = false" + n);
// Be case sensitive explicitly to work on Mac
config = config.Replace ("ignorecase = true", "ignorecase = false");
// Ignore permission changes
config = config.Replace ("filemode = true", "filemode = false");
config = config.Replace ("fetch = +refs/heads/*:refs/remotes/origin/*",
"fetch = +refs/heads/*:refs/remotes/origin/*" + Environment.NewLine +
"\tfetch = +refs/notes/*:refs/notes/*");
// Add user info
string n = Environment.NewLine;
XmlDocument xml = new XmlDocument();
xml.Load (global_config_file_path);
@ -146,6 +207,10 @@ namespace SparkleLib {
// gedit and emacs
writer.WriteLine ("*~");
// Firefox and Chromium temporary download files
writer.WriteLine ("*.part");
writer.WriteLine ("*.crdownload");
// vi(m)
writer.WriteLine (".*.sw[a-z]");
writer.WriteLine ("*.un~");
@ -168,7 +233,6 @@ namespace SparkleLib {
// Windows
writer.WriteLine ("Thumbs.db");
writer.WriteLine ("Desktop.ini");
writer.WriteLine ("~*");
// CVS
writer.WriteLine ("*/CVS/*");

View file

@ -131,7 +131,9 @@ namespace SparkleLib {
public override bool SyncUp ()
{
Add ();
Commit ("Changes made by SparkleShare");
string message = FormatCommitMessage ();
Commit (message);
SparkleGit git = new SparkleGit (LocalPath, "push origin master");
git.Start ();
@ -163,6 +165,8 @@ namespace SparkleLib {
public override bool AnyDifferences {
get {
FillEmptyDirectories (LocalPath);
SparkleGit git = new SparkleGit (LocalPath, "status --porcelain");
git.Start ();
@ -197,7 +201,7 @@ namespace SparkleLib {
if (value) {
if (!File.Exists (unsynced_file_path))
File.Create (unsynced_file_path);
File.Create (unsynced_file_path).Close ();
} else {
File.Delete (unsynced_file_path);
}
@ -330,7 +334,7 @@ namespace SparkleLib {
// Windows doesn't allow colons in the file name, so
// we use "h" between the hours and minutes instead.
string timestamp = DateTime.Now.ToString ("HH\\hmm MMM d");
string their_path = conflicting_path + " (" + SparkleConfig.DefaultConfig.UserName + ", " + timestamp + ")";
string their_path = conflicting_path + " (" + SparkleConfig.DefaultConfig.User.Name + ", " + timestamp + ")";
string abs_conflicting_path = Path.Combine (LocalPath, conflicting_path);
string abs_their_path = Path.Combine (LocalPath, their_path);
@ -452,9 +456,9 @@ namespace SparkleLib {
change_set.Folder = Name;
change_set.Revision = match.Groups [1].Value;
change_set.UserName = match.Groups [2].Value;
change_set.UserEmail = match.Groups [3].Value;
change_set.IsMerge = is_merge_commit;
change_set.User.Name = match.Groups [2].Value;
change_set.User.Email = match.Groups [3].Value;
change_set.IsMagical = is_merge_commit;
change_set.Timestamp = new DateTime (int.Parse (match.Groups [4].Value),
int.Parse (match.Groups [5].Value), int.Parse (match.Groups [6].Value),
@ -477,6 +481,9 @@ namespace SparkleLib {
string file_path = entry_line.Substring (39);
string to_file_path;
if (file_path.EndsWith (".empty"))
file_path = file_path.Substring (0, file_path.Length - ".empty".Length);
if (change_type.Equals ("A") && !file_path.Contains (".notes")) {
change_set.Added.Add (file_path);
@ -512,6 +519,22 @@ namespace SparkleLib {
}
// Git doesn't track empty directories, so this method
// fills them all with a hidden empty file
private void FillEmptyDirectories (string path)
{
foreach (string child_path in Directory.GetDirectories (path)) {
if (child_path.EndsWith (".git") || child_path.EndsWith (".notes"))
continue;
FillEmptyDirectories (child_path);
}
if (Directory.GetFiles (path).Length == 0)
File.Create (Path.Combine (path, ".empty")).Close ();
}
// Creates a pretty commit message based on what has changed
private string FormatCommitMessage ()
{

View file

@ -130,7 +130,7 @@ namespace SparkleLib {
if (value) {
if (!File.Exists (unsynced_file_path))
File.Create (unsynced_file_path);
File.Create (unsynced_file_path).Close ();
} else {
File.Delete (unsynced_file_path);
}
@ -234,11 +234,13 @@ namespace SparkleLib {
SparkleChangeSet change_set = new SparkleChangeSet () {
Revision = match.Groups [9].Value,
UserName = match.Groups [7].Value.Trim (),
UserEmail = match.Groups [8].Value,
IsMerge = is_merge_commit
IsMagical = is_merge_commit
};
change_set.User.Name = match.Groups [7].Value.Trim ();
change_set.User.Email = match.Groups [8].Value;
change_set.Timestamp = new DateTime (int.Parse (match.Groups [1].Value),
int.Parse (match.Groups [2].Value), int.Parse (match.Groups [3].Value),
int.Parse (match.Groups [4].Value), int.Parse (match.Groups [5].Value), 0);

View file

@ -11,10 +11,6 @@ SOURCES = \
Defines.cs \
Git/SparkleFetcherGit.cs \
Git/SparkleRepoGit.cs \
Hg/SparkleFetcherHg.cs \
Hg/SparkleRepoHg.cs \
Scp/SparkleFetcherScp.cs \
Scp/SparkleRepoScp.cs \
SparkleBackend.cs \
SparkleChangeSet.cs \
SparkleConfig.cs \
@ -24,7 +20,6 @@ SOURCES = \
SparkleListenerIrc.cs \
SparkleListenerTcp.cs \
SparkleOptions.cs \
SparklePaths.cs \
SparkleRepoBase.cs \
SparkleWatcher.cs

View file

@ -1,139 +0,0 @@
// SparkleShare, a collaboration and sharing tool.
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.IO;
using System.Diagnostics;
using System.Xml;
namespace SparkleLib {
// Sets up a fetcher that can get remote folders
public class SparkleFetcherScp : SparkleFetcherBase {
public SparkleFetcherScp (string server, string remote_folder, string target_folder) :
base (server, remote_folder, target_folder) { }
public override bool Fetch ()
{
SparkleScp scp = new SparkleScp (SparklePaths.SparkleTmpPath,
"-r \"" + base.remote_url + "\" " + "\"" + base.target_folder + "\"");
scp.Start ();
scp.WaitForExit ();
SparkleHelpers.DebugInfo ("Scp", "Exit code " + scp.ExitCode.ToString ());
if (scp.ExitCode != 0) {
return false;
} else {
InstallConfiguration ();
InstallExcludeRules ();
return true;
}
}
// Install the user's name and email and some config into
// the newly cloned repository
private void InstallConfiguration ()
{
string log_file_path = SparkleHelpers.CombineMore (base.target_folder, ".sparkleshare", "log");
File.Create (log_file_path);
string config_file_path = SparkleHelpers.CombineMore (base.target_folder, ".sparkleshare", "config");
File.Create (config_file_path);
string config = "";
// Write the config to the file
TextWriter writer = new StreamWriter (config_file_path);
writer.WriteLine (config);
writer.Close ();
SparkleHelpers.DebugInfo ("Config", "Added configuration to '" + config_file_path + "'");
}
// Add a .gitignore file to the repo
private void InstallExcludeRules ()
{
string exlude_rules_file_path = SparkleHelpers.CombineMore (base.target_folder, ".sparkleshare", "exclude");
File.Create (exlude_rules_file_path);
TextWriter writer = new StreamWriter (exlude_rules_file_path);
// gedit and emacs
writer.WriteLine ("*~");
// vi(m)
writer.WriteLine (".*.sw[a-z]");
writer.WriteLine ("*.un~");
writer.WriteLine ("*.swp");
writer.WriteLine ("*.swo");
// KDE
writer.WriteLine (".directory");
// Mac OSX
writer.WriteLine (".DS_Store");
writer.WriteLine ("Icon?");
writer.WriteLine ("._*");
writer.WriteLine (".Spotlight-V100");
writer.WriteLine (".Trashes");
// Mac OSX
writer.WriteLine ("*(Autosaved).graffle");
// 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 ();
}
}
public class SparkleScp : Process {
public SparkleScp (string path, string args) : base ()
{
EnableRaisingEvents = true;
StartInfo.FileName = SparkleBackend.DefaultBackend.Path;
StartInfo.Arguments = args;
StartInfo.RedirectStandardOutput = true;
StartInfo.UseShellExecute = false;
StartInfo.WorkingDirectory = path;
}
new public void Start ()
{
SparkleHelpers.DebugInfo ("Cmd", StartInfo.FileName + " " + StartInfo.Arguments);
base.Start ();
}
}
}

View file

@ -1,115 +0,0 @@
// SparkleShare, a collaboration and sharing tool.
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
namespace SparkleLib {
public class SparkleRepoScp : SparkleRepoBase {
public SparkleRepoScp (string path, SparkleBackend backend) :
base (path, backend) { }
public override string Identifier {
get {
return "sparkles";
}
}
public override string CurrentRevision {
get {
return "";
}
}
public override bool CheckForRemoteChanges ()
{
return true;
}
public override bool SyncUp ()
{
return true;
}
public override bool SyncDown ()
{
return true;
}
public override bool AnyDifferences {
get {
return false;
}
}
public override bool HasUnsyncedChanges {
get {
string unsynced_file_path = SparkleHelpers.CombineMore (LocalPath,
".sparkleshare", "has_unsynced_changes");
return File.Exists (unsynced_file_path);
}
set {
string unsynced_file_path = SparkleHelpers.CombineMore (LocalPath,
".sparkleshare", "has_unsynced_changes");
if (value) {
if (!File.Exists (unsynced_file_path))
File.Create (unsynced_file_path);
} else {
File.Delete (unsynced_file_path);
}
}
}
public override List <SparkleChangeSet> GetChangeSets (int count)
{
var l = new List<SparkleChangeSet> ();
l.Add (new SparkleChangeSet () { UserName = "test", UserEmail = "test", Revision = "test", Timestamp = DateTime.Now });
return l;
}
public override void CreateInitialChangeSet ()
{
base.CreateInitialChangeSet ();
}
public override bool UsesNotificationCenter
{
get {
string file_path = SparkleHelpers.CombineMore (LocalPath, ".sparkleshare", "disable_notification_center");
return !File.Exists (file_path);
}
}
}
}

View file

@ -32,7 +32,7 @@ namespace SparkleLib {
public SparkleBackend (string name, string [] paths)
{
Name = name;
Path = "git"; // default
Path = "git";
foreach (string path in paths) {
if (File.Exists (path)) {

View file

@ -16,20 +16,20 @@
using System;
using System.IO;
using System.Collections.Generic;
namespace SparkleLib {
public class SparkleChangeSet {
public string UserName;
public string UserEmail;
public SparkleUser User = new SparkleUser ("Unknown", "Unknown");
public string Folder;
public string Revision;
public DateTime Timestamp;
public DateTime FirstTimestamp;
public bool IsMerge = false;
public bool IsMagical = false;
public List<string> Added = new List<string> ();
public List<string> Deleted = new List<string> ();
@ -76,10 +76,44 @@ namespace SparkleLib {
public class SparkleNote {
public string UserName;
public string UserEmail;
public SparkleUser User;
public DateTime Timestamp;
public string Body;
}
public class SparkleUser {
public string Name;
public string Email;
public string PublicKey;
public SparkleUser (string name, string email)
{
Name = name;
Email = email;
}
}
public class SparkleFolder {
public string Name;
// TODO: Uri
public string FullPath {
get {
return Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, Name);
}
}
public SparkleFolder (string name)
{
Name = name;
}
}
}

View file

@ -23,19 +23,37 @@ using System.Xml;
#if __MonoCS__
using Mono.Unix;
#endif
namespace SparkleLib {
public class SparkleConfig : XmlDocument {
public static SparkleConfig DefaultConfig = new SparkleConfig (
SparklePaths.SparkleConfigPath, "config.xml");
public static string ConfigPath = Path.Combine (
Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData),
"sparkleshare");
public string Path;
public static SparkleConfig DefaultConfig = new SparkleConfig (ConfigPath, "config.xml");
public string FullPath;
public string HomePath = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
public string TmpPath;
public string FoldersPath {
get {
if (GetConfigOption ("folders_path") != null)
return GetConfigOption ("folders_path");
else
return Path.Combine (HomePath, "SparkleShare");
}
}
public SparkleConfig (string config_path, string config_file_name)
{
Path = System.IO.Path.Combine (config_path, config_file_name);
FullPath = System.IO.Path.Combine (config_path, config_file_name);
TmpPath = Path.Combine (FoldersPath, ".tmp");
if (!Directory.Exists (config_path)) {
Directory.CreateDirectory (config_path);
@ -48,10 +66,30 @@ namespace SparkleLib {
SparkleHelpers.DebugInfo ("Config", "Created \"" + icons_path + "\"");
}
if (!File.Exists (Path))
try {
Load (FullPath);
} catch (TypeInitializationException) {
CreateInitialConfig ();
Load (Path);
} catch (IOException) {
CreateInitialConfig ();
} catch (XmlException) {
FileInfo file = new FileInfo (FullPath);
if (file.Length == 0) {
File.Delete (FullPath);
CreateInitialConfig ();
} else {
throw new XmlException (FullPath + " does not contain a valid config XML structure.");
}
} finally {
Load (FullPath);
}
}
@ -59,20 +97,23 @@ namespace SparkleLib {
{
string user_name = "Unknown";
if (SparkleBackend.Platform == PlatformID.Unix ||
SparkleBackend.Platform == PlatformID.MacOSX) {
#if __MonoCS__
user_name = new UnixUserInfo (UnixEnvironment.UserName).RealName;
if (string.IsNullOrEmpty (user_name))
user_name = UnixEnvironment.UserName;
else
user_name = user_name.TrimEnd (",".ToCharArray());
#else
user_name = Environment.UserName;
#endif
} else {
user_name = Environment.UserName;
}
if (string.IsNullOrEmpty (user_name))
user_name = "Unknown";
TextWriter writer = new StreamWriter (Path);
TextWriter writer = new StreamWriter (FullPath);
string n = Environment.NewLine;
writer.Write ("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" + n +
@ -84,36 +125,31 @@ namespace SparkleLib {
"</sparkleshare>");
writer.Close ();
SparkleHelpers.DebugInfo ("Config", "Created \"" + Path + "\"");
SparkleHelpers.DebugInfo ("Config", "Created \"" + FullPath + "\"");
}
public string UserName {
public SparkleUser User {
get {
XmlNode node = SelectSingleNode ("/sparkleshare/user/name/text()");
return node.Value;
XmlNode name_node = SelectSingleNode ("/sparkleshare/user/name/text()");
string name = name_node.Value;
XmlNode email_node = SelectSingleNode ("/sparkleshare/user/email/text()");
string email = email_node.Value;
return new SparkleUser (name, email);
}
set {
XmlNode node = SelectSingleNode ("/sparkleshare/user/name/text()");
node.InnerText = value;
SparkleUser user = (SparkleUser) value;
Save ();
}
}
XmlNode name_node = SelectSingleNode ("/sparkleshare/user/name/text()");
name_node.InnerText = user.Name;
XmlNode email_node = SelectSingleNode ("/sparkleshare/user/email/text()");
email_node.InnerText = user.Email;
public string UserEmail {
get {
XmlNode node = SelectSingleNode ("/sparkleshare/user/email/text()");
return node.Value;
}
set {
XmlNode node = SelectSingleNode ("/sparkleshare/user/email/text()");
node.InnerText = value;
Save ();
this.Save ();
}
}
@ -149,22 +185,7 @@ namespace SparkleLib {
XmlNode node_root = SelectSingleNode ("/sparkleshare");
node_root.AppendChild (node_folder);
Save ();
}
public bool SetFolderOptionalAttribute (string name, string key, string value)
{
XmlNode folder = this.GetFolder(name);
if (folder == null) return false;
if (folder[key] != null) {
folder[key].InnerText = value;
} else {
XmlNode new_node = CreateElement(key);
new_node.InnerText = value;
folder.AppendChild(new_node);
}
return true;
this.Save ();
}
@ -175,28 +196,64 @@ namespace SparkleLib {
SelectSingleNode ("/sparkleshare").RemoveChild (node_folder);
}
Save ();
this.Save ();
}
public bool FolderExists (string name)
{
XmlNode folder = this.GetFolder(name);
return folder != null;
XmlNode folder = this.GetFolder (name);
return (folder != null);
}
public string GetBackendForFolder (string name)
{
return this.GetFolderValue(name, "backend");
return this.GetFolderValue (name, "backend");
}
public string GetUrlForFolder (string name)
{
return this.GetFolderValue(name, "url");
return this.GetFolderValue (name, "url");
}
public bool SetFolderOptionalAttribute (string folder_name, string key, string value)
{
XmlNode folder = this.GetFolder (folder_name);
if (folder == null)
return false;
if (folder [key] != null) {
folder [key].InnerText = value;
} else {
XmlNode new_node = CreateElement (key);
new_node.InnerText = value;
folder.AppendChild (new_node);
}
return true;
}
public string GetFolderOptionalAttribute (string folder_name, string key)
{
XmlNode folder = this.GetFolder (folder_name);
if (folder != null) {
if (folder [key] != null)
return folder [key].InnerText;
else
return null;
} else {
return null;
}
}
public List<string> Hosts {
get {
@ -204,6 +261,7 @@ namespace SparkleLib {
foreach (XmlNode node_folder in SelectNodes ("/sparkleshare/folder")) {
Uri uri = new Uri (node_folder ["url"].InnerText);
if (!hosts.Contains (uri.Host))
hosts.Add (uri.Host);
}
@ -213,21 +271,40 @@ namespace SparkleLib {
}
public string GetAnnouncementsForFolder (string name)
{
return this.GetFolderValue(name, "announcements");
public List<string> HostsWithUsername {
get {
List<string> hosts = new List<string> ();
foreach (XmlNode node_folder in SelectNodes ("/sparkleshare/folder")) {
Uri uri = new Uri (node_folder ["url"].InnerText);
if ("git" != uri.UserInfo && !hosts.Contains (uri.UserInfo + "@" + uri.Host))
hosts.Add (uri.UserInfo + "@" + uri.Host);
}
return hosts;
}
}
public string GetAnnouncementUrlForFolder (string name)
private XmlNode GetFolder (string name)
{
// examples?
// tcp://localhost:9999/
// xmpp:someuser@somexmppserver?canhavefunnybits
// irc://hbons/#somechatroom
return this.GetFolderValue(name, "announcements_url");
return SelectSingleNode (String.Format("/sparkleshare/folder[name='{0}']", name));
}
private string GetFolderValue (string name, string key)
{
XmlNode folder = this.GetFolder(name);
if ((folder != null) && (folder [key] != null)) {
return folder [key].InnerText;
}
return null;
}
public string GetConfigOption (string name)
{
XmlNode node = SelectSingleNode ("/sparkleshare/" + name);
@ -255,34 +332,17 @@ namespace SparkleLib {
}
SparkleHelpers.DebugInfo ("Config", "Updated " + name + ":" + content);
Save ();
this.Save ();
}
public void Save ()
private void Save ()
{
if (!File.Exists (Path))
throw new ConfigFileNotFoundException (Path + " does not exist");
if (!File.Exists (FullPath))
throw new ConfigFileNotFoundException (FullPath + " does not exist");
Save (Path);
SparkleHelpers.DebugInfo ("Config", "Updated \"" + Path + "\"");
}
private XmlNode GetFolder (string name)
{
return SelectSingleNode(String.Format("/sparkleshare/folder[name='{0}']", name));
}
private string GetFolderValue (string name, string key)
{
XmlNode folder = this.GetFolder(name);
if ((folder != null) && (folder[key] != null)) {
return folder[key].InnerText;
}
return null;
this.Save (FullPath);
SparkleHelpers.DebugInfo ("Config", "Updated \"" + FullPath + "\"");
}
}
@ -293,3 +353,4 @@ namespace SparkleLib {
base (message) { }
}
}

View file

@ -33,18 +33,19 @@ namespace SparkleLib {
public delegate void StartedEventHandler ();
public delegate void FinishedEventHandler ();
public delegate void FailedEventHandler ();
public delegate void ProgressChangedEventHandler (double percentage);
public event StartedEventHandler Started;
public event FinishedEventHandler Finished;
public event FailedEventHandler Failed;
public event ProgressChangedEventHandler ProgressChanged;
protected string target_folder;
protected string remote_url;
private Thread thread;
public abstract bool Fetch ();
public SparkleFetcherBase (string server, string remote_folder, string target_folder)
{
this.target_folder = target_folder;
@ -52,6 +53,9 @@ namespace SparkleLib {
}
public abstract bool Fetch ();
// Clones the remote repository
public void Start ()
{
@ -97,6 +101,13 @@ namespace SparkleLib {
}
public virtual void Stop ()
{
this.thread.Abort ();
this.thread.Join ();
}
public string RemoteUrl {
get {
return this.remote_url;
@ -112,10 +123,16 @@ namespace SparkleLib {
}
}
protected void OnProgressChanged (double percentage) {
if (ProgressChanged != null)
ProgressChanged (percentage);
}
private void DisableHostKeyCheckingForHost (string host)
{
string path = SparklePaths.HomePath;
string path = SparkleConfig.DefaultConfig.HomePath;
if (!(SparkleBackend.Platform == PlatformID.Unix ||
SparkleBackend.Platform == PlatformID.MacOSX)) {
@ -154,7 +171,7 @@ namespace SparkleLib {
private void EnableHostKeyCheckingForHost (string host)
{
string path = SparklePaths.HomePath;
string path = SparkleConfig.DefaultConfig.HomePath;
if (!(SparkleBackend.Platform == PlatformID.Unix ||
SparkleBackend.Platform == PlatformID.MacOSX)) {

View file

@ -41,35 +41,44 @@ namespace SparkleLib {
public static SparkleListenerBase CreateListener (string folder_name, string folder_identifier)
{
string announce_uri = SparkleConfig.DefaultConfig.GetAnnouncementUrlForFolder (folder_name);
string uri = SparkleConfig.DefaultConfig.GetFolderOptionalAttribute (
folder_name, "announcements_url");
if (announce_uri == null) {
if (uri == null) {
// 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
announce_uri = "irc://204.62.14.135/";
uri = "tcp://204.62.14.135:1986"; // TODO: announcements.sparkleshare.org
}
Uri announce_uri = new Uri (uri);
// We use only one listener per server to keep
// the number of connections as low as possible
foreach (SparkleListenerBase listener in listeners) {
if (listener.Server.Equals (announce_uri)) {
SparkleHelpers.DebugInfo ("ListenerFactory", "Refered to existing listener for " + announce_uri);
SparkleHelpers.DebugInfo ("ListenerFactory",
"Refered to existing listener for " + announce_uri);
listener.AlsoListenTo (folder_identifier);
return (SparkleListenerBase) listener;
}
}
Uri listen_on = new Uri (announce_uri);
switch (listen_on.Scheme) {
case "tcp":
listeners.Add (new SparkleListenerTcp (listen_on, folder_identifier));
break;
case "irc":
default:
listeners.Add (new SparkleListenerIrc (listen_on, folder_identifier));
break;
// Create a new listener with the appropriate
// type if one doesn't exist yet for that server
switch (announce_uri.Scheme) {
case "tcp":
listeners.Add (new SparkleListenerTcp (announce_uri, folder_identifier));
break;
case "irc":
listeners.Add (new SparkleListenerIrc (announce_uri, folder_identifier));
break;
default:
listeners.Add (new SparkleListenerTcp (announce_uri, folder_identifier));
break;
}
SparkleHelpers.DebugInfo ("ListenerFactory", "Issued new listener for " + announce_uri);
@ -109,20 +118,25 @@ namespace SparkleLib {
protected Uri server;
protected Timer reconnect_timer = new Timer { Interval = 60 * 1000, Enabled = true };
public SparkleListenerBase (Uri server, string folder_identifier) {
public SparkleListenerBase (Uri server, string folder_identifier)
{
this.server = server;
this.reconnect_timer.Elapsed += delegate {
if (!IsConnected && !this.is_connecting)
Reconnect ();
};
this.server = server;
this.reconnect_timer.Start ();
}
public void AnnounceBase (SparkleAnnouncement announcement) {
public void AnnounceBase (SparkleAnnouncement announcement)
{
if (IsConnected) {
SparkleHelpers.DebugInfo ("Listener", "Announcing to " + announcement.FolderIdentifier + " on " + this.server);
SparkleHelpers.DebugInfo ("Listener",
"Announcing to " + announcement.FolderIdentifier + " on " + this.server);
Announce (announcement);
} else {
@ -161,6 +175,7 @@ namespace SparkleLib {
if (this.queue_up.Count > 0) {
SparkleHelpers.DebugInfo ("Listener", "Delivering queued messages...");
foreach (SparkleAnnouncement announcement in this.queue_up) {
AnnounceBase (announcement);
this.queue_up.Remove (announcement);
@ -171,7 +186,7 @@ namespace SparkleLib {
public void OnDisconnected ()
{
SparkleHelpers.DebugInfo ("Listener", "Disonnected");
SparkleHelpers.DebugInfo ("Listener", "Disonnected from " + Server);
if (Disconnected != null)
Disconnected ();

View file

@ -48,6 +48,20 @@ namespace SparkleLib {
PingInterval = 60
};
string proxy = Environment.GetEnvironmentVariable ("http_proxy");
Uri proxy_uri = null;
if (!String.IsNullOrEmpty (proxy) &&
Uri.TryCreate (proxy, UriKind.Absolute, out proxy_uri)) {
#if __MonoCS__
if (proxy_uri.Scheme == "http") {
this.client.ProxyType = ProxyType.Http;
this.client.ProxyHost = proxy_uri.Host;
this.client.ProxyPort = proxy_uri.Port;
}
#endif
}
this.client.OnConnected += delegate {
base.is_connecting = false;
OnConnected ();
@ -92,11 +106,12 @@ namespace SparkleLib {
int port = base.server.Port;
if (port < 0) port = 6667;
this.client.Connect (base.server.Host, port);
this.client.Login (this.nick, this.nick);
this.client.Login (this.nick, this.nick, 8, this.nick);
foreach (string channel in base.channels) {
SparkleHelpers.DebugInfo ("ListenerIrc", "Joining channel " + channel);
this.client.RfcJoin (channel);
this.client.RfcMode (channel, "+s");
}
// List to the channel, this blocks the thread
@ -124,6 +139,7 @@ namespace SparkleLib {
if (IsConnected) {
SparkleHelpers.DebugInfo ("ListenerIrc", "Joining channel " + channel);
this.client.RfcJoin (channel);
this.client.RfcMode (channel, "+s");
}
}
}

View file

@ -46,11 +46,12 @@ namespace SparkleLib {
public override bool IsConnected {
get {
//return this.client.IsConnected;
bool result = false;
lock (this.mutex) {
result = this.connected;
}
return result;
}
}
@ -70,40 +71,46 @@ namespace SparkleLib {
int port = Server.Port;
if (port < 0) port = 9999;
this.socket.Connect (Server.Host, port);
lock (this.mutex) {
base.is_connecting = false;
this.connected = true;
OnConnected ();
foreach (string channel in base.channels) {
SparkleHelpers.DebugInfo ("ListenerTcp", "Subscribing to channel " + channel);
this.socket.Send (Encoding.UTF8.GetBytes ("subscribe " + channel + "\n"));
}
}
byte [] bytes = new byte [4096];
// List to the channels, this blocks the thread
while (this.socket.Connected) {
int bytes_read = this.socket.Receive (bytes);
if (bytes_read > 0) {
string received = Encoding.UTF8.GetString (bytes);
string folder_identifier = received.Substring (0, received.IndexOf ("!"));
string message = received.Substring (received.IndexOf ("!") + 1);
OnAnnouncement (new SparkleAnnouncement (folder_identifier, message));
} else {
SparkleHelpers.DebugInfo ("ListenerTcp", "Error on socket");
lock (this.mutex) {
this.socket.Close();
this.socket.Close ();
this.connected = false;
OnDisconnected ();
}
}
}
SparkleHelpers.DebugInfo ("ListenerTcp", "Disconnected from " + Server.Host);
// TODO: attempt to reconnect..?
} catch (SocketException e) {
SparkleHelpers.DebugInfo ("ListenerTcp", "Could not connect to " + Server + ": " + e.Message);
}

View file

@ -67,9 +67,12 @@ namespace SparkleLib {
public delegate void SyncStatusChangedEventHandler (SyncStatus new_status);
public event SyncStatusChangedEventHandler SyncStatusChanged;
public delegate void NewChangeSetEventHandler (SparkleChangeSet change_set, string source_path);
public delegate void NewChangeSetEventHandler (SparkleChangeSet change_set);
public event NewChangeSetEventHandler NewChangeSet;
public delegate void NewNoteEventHandler (string user_name, string user_email);
public event NewNoteEventHandler NewNote;
public delegate void ConflictResolvedEventHandler ();
public event ConflictResolvedEventHandler ConflictResolved;
@ -253,6 +256,8 @@ namespace SparkleLib {
this.listener.Announcement += delegate (SparkleAnnouncement announcement) {
string identifier = Identifier;
Console.WriteLine (announcement.Message + " ! " + CurrentRevision);
if (announcement.FolderIdentifier == identifier &&
!announcement.Message.Equals (CurrentRevision)) {
if ((Status != SyncStatus.SyncUp) &&
@ -276,7 +281,6 @@ namespace SparkleLib {
{
lock (this.change_lock) {
if (this.has_changed) {
Console.WriteLine ("checking...");
if (this.sizebuffer.Count >= 4)
this.sizebuffer.RemoveAt (0);
@ -363,8 +367,8 @@ namespace SparkleLib {
if (match_notes.Success) {
SparkleNote note = new SparkleNote () {
UserName = match_notes.Groups [1].Value,
UserEmail = match_notes.Groups [2].Value,
User = new SparkleUser (match_notes.Groups [1].Value,
match_notes.Groups [2].Value),
Timestamp = new DateTime (1970, 1, 1).AddSeconds (int.Parse (match_notes.Groups [3].Value)),
Body = match_notes.Groups [4].Value
};
@ -446,13 +450,26 @@ namespace SparkleLib {
if (change_sets != null && change_sets.Count > 0) {
SparkleChangeSet change_set = change_sets [0];
if (NewChangeSet != null)
NewChangeSet (change_set, LocalPath);
bool note_added = false;
foreach (string added in change_set.Added) {
if (added.Contains (".notes")) {
if (NewNote != null)
NewNote (change_set.User.Name, change_set.User.Email);
note_added = true;
break;
}
}
if (!note_added) {
if (NewChangeSet != null)
NewChangeSet (change_set);
}
}
// There could be changes from a
// resolved conflict. Tries only once,
//then let the timer try again periodicallly
// There could be changes from a resolved
// conflict. Tries only once, then lets
// the timer try again periodically
if (HasUnsyncedChanges)
SyncUp ();
@ -510,8 +527,8 @@ namespace SparkleLib {
string n = Environment.NewLine;
note = "<note>" + n +
" <user>" + n +
" <name>" + SparkleConfig.DefaultConfig.UserName + "</name>" + n +
" <email>" + SparkleConfig.DefaultConfig.UserEmail + "</email>" + n +
" <name>" + SparkleConfig.DefaultConfig.User.Name + "</name>" + n +
" <email>" + SparkleConfig.DefaultConfig.User.Email + "</email>" + n +
" </user>" + n +
" <timestamp>" + timestamp + "</timestamp>" + n +
" <body>" + note + "</body>" + n +

View file

@ -79,16 +79,12 @@
<Compile Include="..\Hg\SparkleRepoHg.cs">
<Link>SparkleRepoHg.cs</Link>
</Compile>
<Compile Include="..\Scp\SparkleFetcherScp.cs">
<Link>SparkleFetcherScp.cs</Link>
<SubType>Component</SubType>
</Compile>
<Compile Include="..\Scp\SparkleRepoScp.cs">
<Link>SparkleRepoScp.cs</Link>
</Compile>
<Compile Include="..\SparkleConfig.cs">
<Link>SparkleConfig.cs</Link>
</Compile>
<Compile Include="..\SparklePaths.cs">
<Link>SparklePaths.cs</Link>
</Compile>
<Compile Include="..\SparkleRepoBase.cs">
<Link>SparkleRepoBase.cs</Link>
</Compile>
@ -105,7 +101,6 @@
</Compile>
<Compile Include="..\SparkleFetcherBase.cs" />
<Compile Include="..\SparkleHelpers.cs" />
<Compile Include="..\SparklePaths.cs" />
<Compile Include="..\SparkleOptions.cs" />
<Compile Include="..\SparkleChangeSet.cs" />
<Compile Include="..\SparkleListenerBase.cs" />

View file

@ -12,19 +12,20 @@ BUILD_DEFINES="-define:HAVE_APP_INDICATOR"
endif
SOURCES = \
Program.cs \
SparkleAbout.cs \
SparkleAboutController.cs \
SparkleBubbles.cs \
SparkleBubblesController.cs \
SparkleController.cs \
SparkleControllerBase.cs \
SparkleEntry.cs \
SparkleEventLog.cs \
SparkleEventLogController.cs \
SparkleLinController.cs \
SparkleExtensions.cs \
SparkleSetup.cs \
SparkleSetupController.cs \
SparkleSetupWindow.cs \
SparkleShare.cs \
SparkleSpinner.cs \
SparkleStatusIcon.cs \
SparkleStatusIconController.cs \
@ -40,7 +41,7 @@ SOURCES = \
SparkleSetup.cs \
SparkleSetupController.cs \
SparkleSetupWindow.cs \
SparkleShare.cs \
Program.cs \
SparkleSpinner.cs \
SparkleStatusIcon.cs \
SparkleStatusIconController.cs \

131
SparkleShare/Program.cs Normal file
View file

@ -0,0 +1,131 @@
// SparkleShare, a collaboration and sharing tool.
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using Mono.Unix;
//using Mono.Unix.Native;
using SparkleLib;
using SparkleLib.Options;
namespace SparkleShare {
// This is SparkleShare!
public class Program {
public static SparkleController Controller;
public static SparkleUI UI;
// Short alias for the translations
public static string _ (string s)
{
return Catalog.GetString (s);
}
public static void Main (string [] args)
{
// Parse the command line options
bool show_help = false;
OptionSet option_set = new OptionSet () {
{ "v|version", _("Print version information"), v => { PrintVersion (); } },
{ "h|help", _("Show this help text"), v => show_help = v != null }
};
try {
option_set.Parse (args);
} catch (OptionException e) {
Console.Write ("SparkleShare: ");
Console.WriteLine (e.Message);
Console.WriteLine ("Try `sparkleshare --help' for more information.");
}
if (show_help)
ShowHelp (option_set);
// Initialize the controller this way so that
// there aren't any exceptions in the OS specific UI's
Controller = new SparkleController ();
Controller.Initialize ();
if (Controller != null) {
UI = new SparkleUI ();
UI.Run ();
}
}
// Prints the help output
public static void ShowHelp (OptionSet option_set)
{
Console.WriteLine (" ");
Console.WriteLine (_("SparkleShare, a collaboration and sharing tool."));
Console.WriteLine (_("Copyright (C) 2010 Hylke Bons"));
Console.WriteLine (" ");
Console.WriteLine (_("This program comes with ABSOLUTELY NO WARRANTY."));
Console.WriteLine (" ");
Console.WriteLine (_("This is free software, and you are welcome to redistribute it "));
Console.WriteLine (_("under certain conditions. Please read the GNU GPLv3 for details."));
Console.WriteLine (" ");
Console.WriteLine (_("SparkleShare automatically syncs Git repositories in "));
Console.WriteLine (_("the ~/SparkleShare folder with their remote origins."));
Console.WriteLine (" ");
Console.WriteLine (_("Usage: sparkleshare [start|stop|restart] [OPTION]..."));
Console.WriteLine (_("Sync SparkleShare folder with remote repositories."));
Console.WriteLine (" ");
Console.WriteLine (_("Arguments:"));
option_set.WriteOptionDescriptions (Console.Out);
Environment.Exit (0);
}
// Prints the version information
public static void PrintVersion ()
{
Console.WriteLine (_("SparkleShare " + Defines.VERSION));
Environment.Exit (0);
}
// Strange magic needed by SetProcessName ()
[DllImport ("libc")]
private static extern int prctl (int option, byte [] arg2, IntPtr arg3, IntPtr arg4, IntPtr arg5);
// Sets the Unix process name to 'sparkleshare' instead of 'mono'
private static void SetProcessName (string name)
{
try {
if (prctl (15, Encoding.ASCII.GetBytes (name + "\0"), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero) != 0)
throw new ApplicationException ("Error setting process name: " +
Mono.Unix.Native.Stdlib.GetLastError ());
} catch (EntryPointNotFoundException) {
Console.WriteLine ("SetProcessName: Entry point not found");
}
}
}
}

View file

@ -21,20 +21,20 @@ using System.IO;
using System.Net;
using Gtk;
using Mono.Unix;
namespace SparkleShare {
public class SparkleAbout : Window {
public SparkleAboutController Controller = new SparkleAboutController ();
public SparkleAboutController Controller;
private Label updates;
// Short alias for the translations
public static string _(string s)
{
return s;
return Catalog.GetString (s);
}
@ -53,21 +53,22 @@ namespace SparkleShare {
Title = _("About SparkleShare");
AppPaintable = true;
MemoryStream MemStream = new MemoryStream();
Icons.about.Save(MemStream, System.Drawing.Imaging.ImageFormat.Png);
MemStream.Seek(0, SeekOrigin.Begin);
string image_path = new string [] {SparkleUI.AssetsPath,
"pixmaps", "about.png"}.Combine ();
Realize ();
Gdk.Pixbuf buf = new Gdk.Pixbuf(MemStream);
Gdk.Pixbuf buf = new Gdk.Pixbuf (image_path);
Gdk.Pixmap map, map2;
buf.RenderPixmapAndMask (out map, out map2, 255);
GdkWindow.SetBackPixmap (map, false);
CreateAbout ();
Controller = new SparkleAboutController ();
Controller.NewVersionEvent += delegate (string new_version) {
Application.Invoke (delegate {
this.updates.Markup = String.Format ("<span font_size='small' fgcolor='#f57900'>{0}</span>",
String.Format (_("A newer version ({0}) is available!"), new_version));
this.updates.ShowAll ();
});
};
@ -76,6 +77,7 @@ namespace SparkleShare {
Application.Invoke (delegate {
this.updates.Markup = String.Format ("<span font_size='small' fgcolor='#4e9a06'>{0}</span>",
_("You are running the latest version."));
this.updates.ShowAll ();
});
};
@ -84,9 +86,12 @@ namespace SparkleShare {
Application.Invoke (delegate {
this.updates.Markup = String.Format ("<span font_size='small' fgcolor='#4e9a06'>{0}</span>",
_("Checking for updates..."));
this.updates.ShowAll ();
});
};
this.CreateAbout ();
}

View file

@ -68,24 +68,24 @@ namespace SparkleShare {
Uri uri = new Uri ("http://www.sparkleshare.org/version");
web_client.DownloadStringCompleted += delegate (object o, DownloadStringCompletedEventArgs args) {
if (args.Error != null) {
Console.WriteLine ("Error during version check: {0}", args.Error.Message);
if (args.Error != null)
return;
string new_version = args.Result.Trim ();
// Add a little delay, making it seems we're
// actually doing hard work
Thread.Sleep (2 * 1000);
if (RunningVersion.Equals (new_version)) {
if (VersionUpToDateEvent != null)
VersionUpToDateEvent ();
} else {
string new_version = args.Result.Trim ();
// Add a little delay, making it seems we're
// actually doing hard work
Thread.Sleep (2 * 1000);
if (RunningVersion.Equals (new_version)) {
if (VersionUpToDateEvent != null)
VersionUpToDateEvent ();
} else {
if (NewVersionEvent != null)
NewVersionEvent (new_version);
}
if (NewVersionEvent != null)
NewVersionEvent (new_version);
}
this.version_checker.Start ();
};

View file

@ -30,27 +30,24 @@ namespace SparkleShare {
public SparkleBubbles ()
{
Controller.ShowBubbleEvent += delegate (string title, string subtext, string image_path) {
Notification notification = new Notification () {
Timeout = 5 * 1000,
Urgency = Urgency.Low
};
try {
Notification notification = new Notification () {
Timeout = 5 * 1000,
Urgency = Urgency.Low
};
if (image_path != null)
notification.Icon = new Gdk.Pixbuf (image_path);
else
notification.IconName = "folder-sparkleshare";
if (image_path != null)
notification.Icon = new Gdk.Pixbuf (image_path);
else
notification.IconName = "folder-sparkleshare";
notification.Show ();
notification.Show ();
} catch (Exception) {
// Ignore exceptions thrown by libnotify,
// they're not important enough to crash
}
};
}
// Checks whether the system allows adding buttons to a notification,
// prevents error messages in Ubuntu.
// new public void AddAction (string action, string label, ActionHandler handler)
// {
// if (Array.IndexOf (Notifications.Global.Capabilities, "actions") > -1)
// base.AddAction (action, label, handler);
// }
}
}

View file

@ -27,19 +27,24 @@ namespace SparkleShare {
public SparkleBubblesController ()
{
SparkleShare.Controller.ConflictNotificationRaised += delegate {
if (ShowBubbleEvent != null && SparkleShare.Controller.NotificationsEnabled)
ShowBubbleEvent ("Ouch! Mid-air collision!",
"Don't worry, SparkleShare made a copy of each conflicting file.", null);
Program.Controller.ConflictNotificationRaised += delegate {
ShowBubble ("Ouch! Mid-air collision!",
"Don't worry, SparkleShare made a copy of each conflicting file.",
null);
};
SparkleShare.Controller.NotificationRaised += delegate (string user_name, string user_email,
Program.Controller.NotificationRaised += delegate (string user_name, string user_email,
string message, string folder_path) {
if (ShowBubbleEvent != null && SparkleShare.Controller.NotificationsEnabled)
ShowBubbleEvent (user_name, message,
SparkleShare.Controller.GetAvatar (user_email, 36));
ShowBubble (user_name, message,
Program.Controller.GetAvatar (user_email, 36));
};
}
public void ShowBubble (string title, string subtext, string image_path)
{
if (ShowBubbleEvent != null && Program.Controller.NotificationsEnabled)
ShowBubbleEvent (title, subtext, image_path);
}
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -23,24 +23,21 @@ using System.Threading;
using Gtk;
using Mono.Unix;
using SparkleLib;
using WebKit;
namespace SparkleShare {
public class SparkleEventLog : Window {
private ScrolledWindow ScrolledWindow;
private MenuBar MenuBar;
private WebView WebView;
private string LinkStatus;
private SparkleSpinner Spinner;
private string HTML;
private EventBox LogContent;
private List<SparkleChangeSet> change_sets;
private string selected_log = null;
private ComboBox combo_box;
public SparkleEventLogController Controller = new SparkleEventLogController ();
private HBox layout_horizontal;
private ComboBox combo_box;
private EventBox content_wrapper;
private ScrolledWindow scrolled_window;
private WebView web_view;
private SparkleSpinner spinner;
private string link_status;
// Short alias for the translations
@ -63,49 +60,43 @@ namespace SparkleShare {
DeleteEvent += Close;
CreateEvents ();
UpdateEvents (false);
UpdateChooser ();
}
private void CreateEvents ()
{
VBox layout_vertical = new VBox (false, 0);
LogContent = new EventBox ();
this.spinner = new SparkleSpinner (22);
this.content_wrapper = new EventBox ();
this.scrolled_window = new ScrolledWindow ();
ScrolledWindow = new ScrolledWindow ();
WebView = new WebView () {
this.web_view = new WebView () {
Editable = false
};
WebView.HoveringOverLink += delegate (object o, WebKit.HoveringOverLinkArgs args) {
LinkStatus = args.Link;
this.web_view.HoveringOverLink += delegate (object o, WebKit.HoveringOverLinkArgs args) {
this.link_status = args.Link;
};
WebView.NavigationRequested += delegate (object o, WebKit.NavigationRequestedArgs args) {
if (args.Request.Uri == LinkStatus) {
this.web_view.NavigationRequested += delegate (object o, WebKit.NavigationRequestedArgs args) {
if (args.Request.Uri == this.link_status) {
// TODO: controller
Process process = new Process ();
process.StartInfo.FileName = "xdg-open";
process.StartInfo.Arguments = args.Request.Uri.Replace (" ", "\\ "); // Escape space-characters
process.Start ();
} else {
Regex regex = new Regex (@"(.+)~(.+)~(.+)");
Match match = regex.Match (args.Request.Uri);
//TODO: controller
Regex regex = new Regex (@"(.+)~(.+)~(.+)");
Match match = regex.Match (args.Request.Uri);
if (match.Success) {
string folder_name = match.Groups [1].Value;
string revision = match.Groups [2].Value;
string note = match.Groups [3].Value.Replace ("%20", " ");
if (match.Success) {
string folder_name = match.Groups [1].Value;
string revision = match.Groups [2].Value;
string note = match.Groups [3].Value;
Thread thread = new Thread (new ThreadStart (delegate {
SparkleShare.Controller.AddNoteToFolder (folder_name, revision, note);
}));
Thread thread = new Thread (new ThreadStart (delegate {
Program.Controller.AddNoteToFolder (folder_name, revision, note);
}));
thread.Start ();
}
thread.Start ();
}
}
// Don't follow HREFs (as this would cause a page refresh)
@ -113,44 +104,75 @@ namespace SparkleShare {
args.RetVal = 1;
};
ScrolledWindow.Add (WebView);
LogContent.Add (ScrolledWindow);
this.scrolled_window.Add (this.web_view);
this.content_wrapper.Add (this.spinner);
this.spinner.Start ();
this.layout_horizontal = new HBox (true, 0);
this.layout_horizontal.PackStart (new Label (""), true, true, 0);
this.layout_horizontal.PackStart (new Label (""), true, true, 0);
layout_vertical.PackStart (layout_horizontal, false, false, 0);
layout_vertical.PackStart (LogContent, true, true, 0);
// We have to hide the menubar somewhere...
layout_vertical.PackStart (this.layout_horizontal, false, false, 0);
layout_vertical.PackStart (CreateShortcutsBar (), false, false, 0);
layout_vertical.PackStart (this.content_wrapper, true, true, 0);
Add (layout_vertical);
ShowAll ();
UpdateChooser (null);
UpdateContent (null);
// Hook up the controller events
Controller.UpdateChooserEvent += delegate (string [] folders) {
Application.Invoke (delegate {
UpdateChooser (folders);
});
};
Controller.UpdateContentEvent += delegate (string html) {
Application.Invoke (delegate {
UpdateContent (html);
});
};
Controller.ContentLoadingEvent += delegate {
Application.Invoke (delegate {
if (this.content_wrapper.Child != null)
this.content_wrapper.Remove (this.content_wrapper.Child);
this.content_wrapper.Add (this.spinner);
this.spinner.Start ();
this.content_wrapper.ShowAll ();
});
};
}
public void UpdateChooser ()
public void UpdateChooser (string [] folders)
{
if (folders == null)
folders = Controller.Folders;
if (this.combo_box != null && this.combo_box.Parent != null)
this.layout_horizontal.Remove (this.combo_box);
this.combo_box = new ComboBox ();
this.layout_horizontal.BorderWidth = 9;
CellRendererText cell = new CellRendererText();
this.combo_box.PackStart (cell, false);
this.combo_box.AddAttribute (cell, "text", 0);
ListStore store = new ListStore (typeof (string));
this.combo_box.Model = store;
store.AppendValues (_("All Folders"));
store.AppendValues ("---");
foreach (string folder_name in SparkleShare.Controller.Folders)
store.AppendValues (folder_name);
foreach (string folder in folders)
store.AppendValues (folder);
this.combo_box.Model = store;
this.combo_box.Active = 0;
this.combo_box.RowSeparatorFunc = delegate (TreeModel model, TreeIter iter) {
@ -158,116 +180,75 @@ namespace SparkleShare {
return (item == "---");
};
if (this.selected_log != null &&
!SparkleShare.Controller.Folders.Contains (this.selected_log)) {
this.selected_log = null;
}
this.combo_box.Changed += delegate {
TreeIter iter;
this.combo_box.GetActiveIter (out iter);
string selection = (string) this.combo_box.Model.GetValue (iter, 0);
if (selection.Equals (_("All Folders")))
this.selected_log = null;
Controller.SelectedFolder = null;
else
this.selected_log = selection;
UpdateEvents (false);
Controller.SelectedFolder = selection;
};
this.layout_horizontal.BorderWidth = 9;
this.layout_horizontal.PackStart (this.combo_box, true, true, 0);
this.layout_horizontal.ShowAll ();
}
public void UpdateEvents ()
public void UpdateContent (string html)
{
UpdateEvents (true);
}
public void UpdateEvents (bool silent)
{
if (!silent) {
LogContent.Remove (LogContent.Child);
Spinner = new SparkleSpinner (22);
LogContent.Add (Spinner);
LogContent.ShowAll ();
}
Thread thread = new Thread (new ThreadStart (delegate {
Stopwatch watch = new Stopwatch ();
watch.Start ();
this.change_sets = SparkleShare.Controller.GetLog (this.selected_log);
GenerateHTML ();
watch.Stop ();
if (html == null)
html = Controller.HTML;
// A short delay is less annoying than
// a flashing window
if (watch.ElapsedMilliseconds < 500 && !silent)
Thread.Sleep (500 - (int) watch.ElapsedMilliseconds);
if (html == null)
return;
AddHTML ();
html = html.Replace ("<!-- $body-font-size -->", (double) (Style.FontDescription.Size / 1024 + 3) + "px");
html = html.Replace ("<!-- $day-entry-header-font-size -->", (Style.FontDescription.Size / 1024 + 3) + "px");
html = html.Replace ("<!-- $a-color -->", "#0085cf");
html = html.Replace ("<!-- $a-hover-color -->", "#009ff8");
html = html.Replace ("<!-- $body-font-family -->", "\"" + Style.FontDescription.Family + "\"");
html = html.Replace ("<!-- $body-color -->", SparkleUIHelpers.GdkColorToHex (Style.Foreground (StateType.Normal)));
html = html.Replace ("<!-- $body-background-color -->", SparkleUIHelpers.GdkColorToHex (new TreeView ().Style.Base (StateType.Normal)));
html = html.Replace ("<!-- $day-entry-header-background-color -->", SparkleUIHelpers.GdkColorToHex (Style.Background (StateType.Normal)));
html = html.Replace ("<!-- $secondary-font-color -->", SparkleUIHelpers.GdkColorToHex (Style.Foreground (StateType.Insensitive)));
html = html.Replace ("<!-- $small-color -->", SparkleUIHelpers.GdkColorToHex (Style.Foreground (StateType.Insensitive)));
html = html.Replace ("<!-- $no-buddy-icon-background-image -->", "file://" +
new string [] {SparkleUI.AssetsPath, "icons",
"hicolor", "32x32", "status", "avatar-default.png"}.Combine ());
html = html.Replace ("<!-- $document-added-background-image -->", "file://" +
new string [] {SparkleUI.AssetsPath, "icons",
"hicolor", "12x12", "status", "document-added.png"}.Combine ());
html = html.Replace ("<!-- $document-edited-background-image -->", "file://" +
new string [] {SparkleUI.AssetsPath, "icons",
"hicolor", "12x12", "status", "document-edited.png"}.Combine ());
html = html.Replace ("<!-- $document-deleted-background-image -->", "file://" +
new string [] {SparkleUI.AssetsPath, "icons",
"hicolor", "12x12", "status", "document-deleted.png"}.Combine ());
html = html.Replace ("<!-- $document-moved-background-image -->", "file://" +
new string [] {SparkleUI.AssetsPath, "icons",
"hicolor", "12x12", "status", "document-moved.png"}.Combine ());
Application.Invoke (delegate {
this.spinner.Stop ();
this.web_view.LoadString (html, null, null, "file://");
this.content_wrapper.Remove (this.content_wrapper.Child);
this.content_wrapper.Add (this.scrolled_window);
this.content_wrapper.ShowAll ();
});
}));
thread.Start ();
}
private void GenerateHTML ()
{
HTML = SparkleShare.Controller.GetHTMLLog (this.change_sets);
HTML = HTML.Replace ("<!-- $body-font-size -->", (double) (Style.FontDescription.Size / 1024 + 3) + "px");
HTML = HTML.Replace ("<!-- $day-entry-header-font-size -->", (Style.FontDescription.Size / 1024 + 3) + "px");
HTML = HTML.Replace ("<!-- $a-color -->", "#0085cf");
HTML = HTML.Replace ("<!-- $a-hover-color -->", "#009ff8");
HTML = HTML.Replace ("<!-- $body-font-family -->", "\"" + Style.FontDescription.Family + "\"");
HTML = HTML.Replace ("<!-- $body-color -->", SparkleUIHelpers.GdkColorToHex (Style.Foreground (StateType.Normal)));
HTML = HTML.Replace ("<!-- $body-background-color -->", SparkleUIHelpers.GdkColorToHex (new TreeView ().Style.Base (StateType.Normal)));
HTML = HTML.Replace ("<!-- $day-entry-header-background-color -->", SparkleUIHelpers.GdkColorToHex (Style.Background (StateType.Normal)));
HTML = HTML.Replace ("<!-- $secondary-font-color -->", SparkleUIHelpers.GdkColorToHex (Style.Foreground (StateType.Insensitive)));
HTML = HTML.Replace ("<!-- $small-color -->", SparkleUIHelpers.GdkColorToHex (Style.Foreground (StateType.Insensitive)));
HTML = HTML.Replace ("<!-- $no-buddy-icon-background-image -->", "file://" +
SparkleHelpers.CombineMore (Defines.PREFIX, "share", "sparkleshare", "icons",
"hicolor", "32x32", "status", "avatar-default.png"));
HTML = HTML.Replace ("<!-- $document-added-background-image -->", "file://" +
SparkleHelpers.CombineMore (Defines.PREFIX, "share", "sparkleshare", "icons",
"hicolor", "12x12", "status", "document-added.png"));
HTML = HTML.Replace ("<!-- $document-edited-background-image -->", "file://" +
SparkleHelpers.CombineMore (Defines.PREFIX, "share", "sparkleshare", "icons",
"hicolor", "12x12", "status", "document-edited.png"));
HTML = HTML.Replace ("<!-- $document-deleted-background-image -->", "file://" +
SparkleHelpers.CombineMore (Defines.PREFIX, "share", "sparkleshare", "icons",
"hicolor", "12x12", "status", "document-deleted.png"));
HTML = HTML.Replace ("<!-- $document-moved-background-image -->", "file://" +
SparkleHelpers.CombineMore (Defines.PREFIX, "share", "sparkleshare", "icons",
"hicolor", "12x12", "status", "document-moved.png"));
}
private void AddHTML ()
{
Application.Invoke (delegate {
Spinner.Stop ();
LogContent.Remove (LogContent.Child);
WebView.LoadString (HTML, null, null, "file://");
LogContent.Add (ScrolledWindow);
LogContent.ShowAll ();
});
}
public void Close (object o, DeleteEventArgs args)
{
HideAll ();
args.RetVal = true;
// TODO: window positions aren't saved
}
@ -275,7 +256,7 @@ namespace SparkleShare {
{
// Adds a hidden menubar that contains to enable keyboard
// shortcuts to close the log
MenuBar = new MenuBar ();
MenuBar menu_bar = new MenuBar ();
MenuItem file_item = new MenuItem ("File");
@ -304,15 +285,14 @@ namespace SparkleShare {
file_item.Submenu = file_menu;
MenuBar.Append (file_item);
menu_bar.Append (file_item);
// Hacky way to hide the menubar, but the accellerators
// will simply be disabled when using Hide ()
MenuBar.HeightRequest = 1;
MenuBar.ModifyBg (StateType.Normal, Style.Background (StateType.Normal));
menu_bar.HeightRequest = 1;
menu_bar.ModifyBg (StateType.Normal, Style.Background (StateType.Normal));
return MenuBar;
return menu_bar;
}
}
}

View file

@ -69,14 +69,14 @@ namespace SparkleShare {
public string HTML {
get {
List<SparkleChangeSet> change_sets = SparkleShare.Controller.GetLog (this.selected_folder);
return SparkleShare.Controller.GetHTMLLog (change_sets);
List<SparkleChangeSet> change_sets = Program.Controller.GetLog (this.selected_folder);
return Program.Controller.GetHTMLLog (change_sets);
}
}
public string [] Folders {
get {
return SparkleShare.Controller.Folders.ToArray ();
return Program.Controller.Folders.ToArray ();
}
}
@ -86,19 +86,19 @@ namespace SparkleShare {
public SparkleEventLogController ()
{
SparkleShare.Controller.AvatarFetched += delegate {
Program.Controller.AvatarFetched += delegate {
if (UpdateContentEvent != null)
UpdateContentEvent (HTML);
};
SparkleShare.Controller.OnIdle += delegate {
Program.Controller.OnIdle += delegate {
if (UpdateContentEvent != null)
UpdateContentEvent (HTML);
};
SparkleShare.Controller.FolderListChanged += delegate {
Program.Controller.FolderListChanged += delegate {
if (this.selected_folder != null &&
!SparkleShare.Controller.Folders.Contains (this.selected_folder)) {
!Program.Controller.Folders.Contains (this.selected_folder)) {
this.selected_folder = null;
}
@ -110,7 +110,7 @@ namespace SparkleShare {
UpdateContentEvent (HTML);
};
SparkleShare.Controller.NotificationRaised += delegate {
Program.Controller.NotificationRaised += delegate {
if (UpdateContentEvent != null)
UpdateContentEvent (HTML);
};

View file

@ -0,0 +1,35 @@
// SparkleShare, a collaboration and sharing tool.
// Copyright (C) 2010 Hylke Bons (hylkebons@gmail.com)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see (http://www.gnu.org/licenses/).
using System;
using System.IO;
namespace SparkleShare {
public static class Extensions {
public static string Combine (this String [] parts)
{
string new_path = "";
foreach (string part in parts)
new_path = Path.Combine (new_path, part);
return new_path;
}
}
}

View file

@ -73,8 +73,11 @@ namespace SparkleShare {
// from the Internet category if needed
public override void InstallLauncher ()
{
string apps_path = SparkleHelpers.CombineMore (SparklePaths.HomePath, ".local", "share", "applications");
string desktopfile_path = SparkleHelpers.CombineMore (apps_path, "sparkleshare.desktop");
string apps_path =
new string [] {SparkleConfig.DefaultConfig.HomePath,
".local", "share", "applications"}.Combine ();
string desktopfile_path = Path.Combine (apps_path, "sparkleshare.desktop");
if (!File.Exists (desktopfile_path)) {
if (!Directory.Exists (apps_path))
@ -104,8 +107,8 @@ namespace SparkleShare {
// list of bookmarked places
public override void AddToBookmarks ()
{
string bookmarks_file_path = Path.Combine (SparklePaths.HomePath, ".gtk-bookmarks");
string sparkleshare_bookmark = "file://" + SparklePaths.SparklePath + " SparkleShare";
string bookmarks_file_path = Path.Combine (SparkleConfig.DefaultConfig.HomePath, ".gtk-bookmarks");
string sparkleshare_bookmark = "file://" + SparkleConfig.DefaultConfig.FoldersPath + " SparkleShare";
if (File.Exists (bookmarks_file_path)) {
StreamReader reader = new StreamReader (bookmarks_file_path);
@ -114,12 +117,12 @@ namespace SparkleShare {
if (!bookmarks.Contains (sparkleshare_bookmark)) {
TextWriter writer = File.AppendText (bookmarks_file_path);
writer.WriteLine ("file://" + SparklePaths.SparklePath + " SparkleShare");
writer.WriteLine ("file://" + SparkleConfig.DefaultConfig.FoldersPath + " SparkleShare");
writer.Close ();
}
} else {
StreamWriter writer = new StreamWriter (bookmarks_file_path);
writer.WriteLine ("file://" + SparklePaths.SparklePath + " SparkleShare");
writer.WriteLine ("file://" + SparkleConfig.DefaultConfig.FoldersPath + " SparkleShare");
writer.Close ();
}
}
@ -128,13 +131,14 @@ namespace SparkleShare {
// Creates the SparkleShare folder in the user's home folder
public override bool CreateSparkleShareFolder ()
{
if (!Directory.Exists (SparklePaths.SparklePath)) {
if (!Directory.Exists (SparkleConfig.DefaultConfig.FoldersPath)) {
Directory.CreateDirectory (SparklePaths.SparklePath);
SparkleHelpers.DebugInfo ("Controller", "Created '" + SparklePaths.SparklePath + "'");
Directory.CreateDirectory (SparkleConfig.DefaultConfig.FoldersPath);
SparkleHelpers.DebugInfo ("Controller", "Created '" + SparkleConfig.DefaultConfig.FoldersPath + "'");
string gvfs_command_path = SparkleHelpers.CombineMore (Path.VolumeSeparatorChar.ToString (),
"usr", "bin", "gvfs-set-attribute");
string gvfs_command_path =
new string [] {Path.VolumeSeparatorChar.ToString (),
"usr", "bin", "gvfs-set-attribute"}.Combine ();
// Add a special icon to the SparkleShare folder
if (File.Exists (gvfs_command_path)) {
@ -145,12 +149,12 @@ namespace SparkleShare {
process.StartInfo.FileName = "gvfs-set-attribute";
// Clear the custom (legacy) icon path
process.StartInfo.Arguments = "-t unset " + SparklePaths.SparklePath + " metadata::custom-icon";
process.StartInfo.Arguments = "-t unset " + SparkleConfig.DefaultConfig.FoldersPath + " metadata::custom-icon";
process.Start ();
process.WaitForExit ();
// Give the SparkleShare folder an icon name, so that it scales
process.StartInfo.Arguments = SparklePaths.SparklePath + " metadata::custom-icon-name 'folder-sparkleshare'";
process.StartInfo.Arguments = SparkleConfig.DefaultConfig.FoldersPath + " metadata::custom-icon-name 'folder-sparkleshare'";
process.Start ();
process.WaitForExit ();
}
@ -164,13 +168,13 @@ namespace SparkleShare {
public override string EventLogHTML {
get {
string path = SparkleHelpers.CombineMore (Defines.PREFIX,
"share", "sparkleshare", "html", "event-log.html");
string path = new string [] {Defines.PREFIX,
"share", "sparkleshare", "html", "event-log.html"}.Combine ();
string html = String.Join (Environment.NewLine, File.ReadAllLines (path));
html = html.Replace ("<!-- $jquery-url -->", "file://" +
SparkleHelpers.CombineMore (Defines.PREFIX, "share", "sparkleshare", "html", "jquery.js"));
new string [] {Defines.PREFIX, "share", "sparkleshare", "html", "jquery.js"}.Combine ());
return html;
}
@ -179,8 +183,8 @@ namespace SparkleShare {
public override string DayEntryHTML {
get {
string path = SparkleHelpers.CombineMore (Defines.PREFIX,
"share", "sparkleshare", "html", "day-entry.html");
string path = new string [] {Defines.PREFIX,
"share", "sparkleshare", "html", "day-entry.html"}.Combine ();
return String.Join (Environment.NewLine, File.ReadAllLines (path));
}
@ -189,8 +193,8 @@ namespace SparkleShare {
public override string EventEntryHTML {
get {
string path = SparkleHelpers.CombineMore (Defines.PREFIX,
"share", "sparkleshare", "html", "event-entry.html");
string path = new string [] {Defines.PREFIX,
"share", "sparkleshare", "html", "event-entry.html"}.Combine ();
return String.Join (Environment.NewLine, File.ReadAllLines (path));
}
@ -199,7 +203,7 @@ namespace SparkleShare {
public override void OpenSparkleShareFolder (string subfolder)
{
string folder = Path.Combine (SparklePaths.SparklePath, subfolder);
string folder = Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, subfolder);
Process process = new Process ();
process.StartInfo.FileName = "xdg-open";

View file

@ -43,10 +43,8 @@ namespace SparkleShare {
private Button SyncButton;
private Table Table;
private ProgressBar progress_bar = new ProgressBar () { PulseStep = 0.01 };
private Timer progress_bar_pulse_timer = new Timer () { Interval = 25, Enabled = true };
private ProgressBar progress_bar = new ProgressBar ();
// Short alias for the translations
public static string _ (string s)
@ -64,7 +62,7 @@ namespace SparkleShare {
Reset ();
switch (type) {
case PageType.Setup:
case PageType.Setup: {
Header = _("Welcome to SparkleShare!");
Description = _("Before we can create a SparkleShare folder on this " +
@ -79,12 +77,12 @@ namespace SparkleShare {
Xalign = 0
};
NameEntry = new Entry (SparkleShare.Controller.UserName);
NameEntry = new Entry (Controller.GuessedUserName);
NameEntry.Changed += delegate {
CheckSetupPage ();
};
EmailEntry = new Entry ();
EmailEntry = new Entry (Controller.GuessedUserEmail);
EmailEntry.Changed += delegate {
CheckSetupPage ();
};
@ -116,13 +114,14 @@ namespace SparkleShare {
CheckSetupPage ();
break;
}
case PageType.Add:
case PageType.Add: {
Header = _("Where is your remote folder?");
Header = _("Where is your project?");
Table = new Table (6, 2, false) {
RowSpacing = 12
RowSpacing = 0
};
HBox layout_server = new HBox (true, 0);
@ -150,8 +149,8 @@ namespace SparkleShare {
ListStore server_store = new ListStore (typeof (string));
//TODO foreach (string host in SparkleShare.Controller.PreviousHosts)
// server_store.AppendValues (host);
foreach (string host in Program.Controller.PreviousHosts)
server_store.AppendValues (host);
ServerEntry.Completion.Model = server_store;
ServerEntry.Completion.TextColumn = 0;
@ -173,11 +172,7 @@ namespace SparkleShare {
Table.Attach (layout_server, 0, 2, 1, 2);
// Github radiobutton
string github_text = "<b>" + "Github" + "</b>\n" +
"<span fgcolor='" + SecondaryTextColor + "' size='small'>" +
_("Free hosting for Free and Open Source Software projects.") + "\n" +
_("Also has paid accounts for extra private space and bandwidth.") +
"</span>";
string github_text = "<b>" + "Github" + "</b>";
RadioButton radio_button_github = new RadioButton (radio_button, github_text);
(radio_button_github.Child as Label).UseMarkup = true;
@ -190,11 +185,7 @@ namespace SparkleShare {
// Gitorious radiobutton
string gitorious_text = "<b>" + _("Gitorious") + "</b>\n" +
"<span fgcolor='" + SecondaryTextColor + "' size='small'>" +
_("Completely Free as in Freedom infrastructure.") + "\n" +
_("Free accounts for Free and Open Source projects.") +
"</span>";
string gitorious_text = "<b>" + _("Gitorious") + "</b>";
RadioButton radio_button_gitorious = new RadioButton (radio_button, gitorious_text);
(radio_button_gitorious.Child as Label).UseMarkup = true;
@ -207,11 +198,7 @@ namespace SparkleShare {
// GNOME radiobutton
string gnome_text = "<b>" + _("The GNOME Project") + "</b>\n"+
"<span fgcolor='" + SecondaryTextColor + "' size='small'>" +
_("GNOME is an easy to understand interface to your computer.") + "\n" +
_("Select this option if youre a developer or designer working on GNOME.") +
"</span>";
string gnome_text = "<b>" + _("The GNOME Project") + "</b>";
RadioButton radio_button_gnome = new RadioButton (radio_button, gnome_text);
(radio_button_gnome.Child as Label).UseMarkup = true;
@ -236,6 +223,15 @@ namespace SparkleShare {
FolderEntry = new SparkleEntry ();
FolderEntry.ExampleText = _("Folder");
FolderEntry.Completion = new EntryCompletion();
ListStore folder_store = new ListStore (typeof (string));
//foreach (string host in Program.Controller.FolderPaths)
// folder_store.AppendValues (host);
FolderEntry.Completion.Model = folder_store;
FolderEntry.Completion.TextColumn = 0;
FolderEntry.Changed += delegate {
CheckAddPage ();
@ -245,7 +241,10 @@ namespace SparkleShare {
layout_folder.PackStart (FolderEntry, true, true, 0);
Table.Attach (layout_folder, 0, 2, 5, 6);
Add (Table);
VBox box = new VBox (false, 0);
box.PackStart (Table, false, false, 0);
Add (box);
// Cancel button
Button cancel_button = new Button (_("Cancel"));
@ -256,7 +255,7 @@ namespace SparkleShare {
// Sync button
SyncButton = new Button (_("Sync"));
SyncButton = new Button (_("Add"));
SyncButton.Clicked += delegate {
string server = ServerEntry.Text;
@ -280,27 +279,33 @@ namespace SparkleShare {
CheckAddPage ();
break;
}
case PageType.Syncing:
case PageType.Syncing: {
Header = String.Format (_("Syncing folder {0}’…"), Controller.SyncingFolder);
Header = String.Format (_("Adding project {0}’…"), Controller.SyncingFolder);
Description = _("This may take a while." + Environment.NewLine) +
_("Are you sure its not coffee o'clock?");
Button button = new Button () {
Button finish_button = new Button () {
Sensitive = false,
Label = _("Finish")
};
button.Clicked += delegate {
Close ();
Button cancel_button = new Button () {
Label = _("Cancel")
};
AddButton (button);
cancel_button.Clicked += delegate {
Controller.SyncingCancelled ();
};
this.progress_bar_pulse_timer.Elapsed += delegate {
AddButton (cancel_button);
AddButton (finish_button);
Controller.UpdateProgressBarEvent += delegate (double percentage) {
Application.Invoke (delegate {
progress_bar.Pulse ();
this.progress_bar.Fraction = percentage / 100;
});
};
@ -313,32 +318,59 @@ namespace SparkleShare {
Add (bar_wrapper);
break;
}
case PageType.Error:
string n = Environment.NewLine;
case PageType.Error: {
Header = _("Something went wrong") + "…";
Description = "We don't know exactly what the problem is, " +
"but we can try to help you pinpoint it.";
VBox points = new VBox (false, 0);
Image list_point_one = new Image (SparkleUIHelpers.GetIcon ("list-point", 16)) { };
Image list_point_two = new Image (SparkleUIHelpers.GetIcon ("list-point", 16)) { };
Image list_point_three = new Image (SparkleUIHelpers.GetIcon ("list-point", 16)) { };
Label label_one = new Label () {
Text = "First, have you tried turning it off and on again?",
Wrap = true,
Xalign = 0
};
Label label_two = new Label () {
Markup = "<b>" + Controller.PreviousUrl + "</b> is the address we've compiled. " +
"Does this look alright?",
Wrap = true,
Xalign = 0
};
Label label_three = new Label () {
Text = "The host needs to know who you are. Did you upload the key that's in " +
"your SparkleShare folder?",
Wrap = true,
Xalign = 0
};
points.PackStart (new Label ("Please check the following:") { Xalign = 0 }, false, false, 6);
HBox point_one = new HBox (false, 0);
point_one.PackStart (list_point_one, false, false, 0);
point_one.PackStart (label_one, true, true, 12);
points.PackStart (point_one, false, false, 12);
HBox point_two = new HBox (false, 0);
point_two.PackStart (list_point_two, false, false, 0);
point_two.PackStart (label_two, true, true, 12);
points.PackStart (point_two, false, false, 12);
HBox point_three = new HBox (false, 0);
point_three.PackStart (list_point_three, false, false, 0);
point_three.PackStart (label_three, true, true, 12);
points.PackStart (point_three, false, false, 12);
points.PackStart (new Label (""), true, true, 0);
Label l = new Label (
"First, have you tried turning it off and on again?" + n +
n +
Controller.SyncingFolder +" is the address we've compiled from the information " +
"you entered. Does this look correct?" + n +
n +
"The host needs to know who you are. Have you uploaded the key that sits in your SparkleShare folder?");
l.Xpad = 12;
l.Wrap = true;
Button try_again_button = new Button (_("Try Again")) {
Button try_again_button = new Button (_("Try Again…")) {
Sensitive = true
};
@ -347,34 +379,36 @@ namespace SparkleShare {
};
AddButton (try_again_button);
Add (l);
Add (points);
break;
}
case PageType.Finished:
case PageType.Finished: {
UrgencyHint = true;
if (!HasToplevelFocus) {
string title = String.Format (_("{0} has been successfully added"), Controller.SyncingFolder);
string subtext = _("");
string subtext = "";
//TODO new SparkleBubble (title, subtext).Show ();
SparkleUI.Bubbles.Controller.ShowBubble (title, subtext, null);
}
Header = _("Folder synced successfully!");
Description = _("Access the synced files from your SparkleShare folder.");
Header = _("Project successfully added!");
Description = _("Access the files from your SparkleShare folder.");
// A button that opens the synced folder
Button open_folder_button = new Button (_("Open Folder"));
open_folder_button.Clicked += delegate {
SparkleShare.Controller.OpenSparkleShareFolder (Controller.SyncingFolder);
Program.Controller.OpenSparkleShareFolder (Controller.SyncingFolder);
};
Button finish_button = new Button (_("Finish"));
finish_button.Clicked += delegate {
Controller.FinishedPageCompleted ();
Close ();
};
@ -386,10 +420,116 @@ namespace SparkleShare {
break;
}
case PageType.Tutorial: {
switch (Controller.TutorialPageNumber) {
case 1: {
Header = _("What's happening next?");
Description = _("SparkleShare creates a special folder in your personal folder " +
"that will keep track of your projects.");
Button skip_tutorial_button = new Button (_("Skip Tutorial"));
skip_tutorial_button.Clicked += delegate {
Controller.TutorialSkipped ();
};
Button continue_button = new Button (_("Continue"));
continue_button.Clicked += delegate {
Controller.TutorialPageCompleted ();
};
Image slide = SparkleUIHelpers.GetImage ("tutorial-slide-1.png");
Add (slide);
AddButton (skip_tutorial_button);
AddButton (continue_button);
break;
}
case 2: {
Header = _("Sharing files with others");
Description = _("All files added to your project folders are synced with the host " +
"automatically, as well as with your collaborators.");
Button continue_button = new Button (_("Continue"));
continue_button.Clicked += delegate {
Controller.TutorialPageCompleted ();
};
Image slide = SparkleUIHelpers.GetImage ("tutorial-slide-2.png");
Add (slide);
AddButton (continue_button);
break;
}
case 3: {
Header = _("The status icon is here to help");
Description = _("It shows the syncing process status, " +
"and contains links to your projects and the event log.");
Button continue_button = new Button (_("Continue"));
continue_button.Clicked += delegate {
Controller.TutorialPageCompleted ();
};
Image slide = SparkleUIHelpers.GetImage ("tutorial-slide-3.png");
Add (slide);
AddButton (continue_button);
break;
}
case 4: {
Header = _("Adding projects to SparkleShare");
Description = _("Just click this button when you see it on the web, and " +
"the project will be automatically added:");
Label label = new Label (_("…or select <b>Add Project…</b> from the status icon menu " +
"to add one by hand.")) {
Wrap = true,
Xalign = 0,
UseMarkup = true
};
Image slide = SparkleUIHelpers.GetImage ("tutorial-slide-4.png");
Button add_project_button = new Button (_("Add Project…"));
add_project_button.Clicked += delegate {
Controller.TutorialPageCompleted ();
};
Button finish_button = new Button (_("Finish"));
finish_button.Clicked += delegate {
Close ();
};
VBox box = new VBox (false, 0);
box.Add (slide);
box.Add (label);
Add (box);
AddButton (add_project_button);
AddButton (finish_button);
break;
}
}
break;
}
}
ShowAll ();
});
};
}
@ -398,7 +538,7 @@ namespace SparkleShare {
private void CheckSetupPage ()
{
if (NameEntry.Text.Length > 0 &&
SparkleShare.Controller.IsValidEmail (EmailEntry.Text)) {
Program.Controller.IsValidEmail (EmailEntry.Text)) {
NextButton.Sensitive = true;
} else {

View file

@ -25,7 +25,8 @@ namespace SparkleShare {
Add,
Syncing,
Error,
Finished
Finished,
Tutorial
}
@ -33,6 +34,22 @@ namespace SparkleShare {
public event ChangePageEventHandler ChangePageEvent;
public delegate void ChangePageEventHandler (PageType page);
public event UpdateProgressBarEventHandler UpdateProgressBarEvent;
public delegate void UpdateProgressBarEventHandler (double percentage);
public int TutorialPageNumber {
get {
return this.tutorial_page_number;
}
}
public string PreviousUrl {
get {
return this.previous_url;
}
}
public string PreviousServer {
get {
@ -58,11 +75,30 @@ namespace SparkleShare {
}
}
private string previous_server = "";
private string previous_folder = "";
private string syncing_folder = "";
public string GuessedUserName {
get {
return Program.Controller.UserName;
}
}
public string GuessedUserEmail {
get {
if (Program.Controller.UserEmail.Equals ("Unknown"))
return "";
else
return Program.Controller.UserEmail;
}
}
private string previous_server = "";
private string previous_folder = "";
private string previous_url = "";
private string syncing_folder = "";
private int tutorial_page_number = 1;
private PageType previous_page;
public SparkleSetupController ()
{
ChangePageEvent += delegate (PageType page) {
@ -94,34 +130,59 @@ namespace SparkleShare {
Program.Controller.UpdateState ();
if (ChangePageEvent != null)
ChangePageEvent (PageType.Add);
ChangePageEvent (PageType.Tutorial);
}
public void TutorialPageCompleted ()
{
this.tutorial_page_number++;
if (ChangePageEvent != null)
ChangePageEvent (PageType.Tutorial);
}
public void TutorialSkipped ()
{
this.tutorial_page_number = 4;
if (ChangePageEvent != null)
ChangePageEvent (PageType.Tutorial);
}
public void AddPageCompleted (string server, string folder_name)
{
this.syncing_folder = folder_name;
this.syncing_folder = Path.GetFileNameWithoutExtension (folder_name);
this.previous_server = server;
this.previous_folder = folder_name;
if (ChangePageEvent != null)
ChangePageEvent (PageType.Syncing);
Program.Controller.FolderFetched += (target_folder_name) => {
this.syncing_folder = target_folder_name;
Program.Controller.FolderFetched += delegate {
if (ChangePageEvent != null)
ChangePageEvent (PageType.Finished);
this.syncing_folder = "";
};
Program.Controller.FolderFetchError += delegate {
Program.Controller.FolderFetchError += delegate (string remote_url) {
this.previous_url = remote_url;
if (ChangePageEvent != null)
ChangePageEvent (PageType.Error);
this.syncing_folder = "";
};
Program.Controller.FolderFetching += delegate (double percentage) {
if (UpdateProgressBarEvent != null)
UpdateProgressBarEvent (percentage);
};
Program.Controller.FetchFolder (server, this.syncing_folder);
Program.Controller.FetchFolder (server, folder_name);
}
@ -132,6 +193,15 @@ namespace SparkleShare {
}
public void SyncingCancelled ()
{
Program.Controller.StopFetcher ();
if (ChangePageEvent != null)
ChangePageEvent (PageType.Add);
}
public void FinishedPageCompleted ()
{
this.previous_server = "";

View file

@ -23,6 +23,7 @@ using System.Text.RegularExpressions;
using System.Timers;
using Gtk;
using Mono.Unix;
using SparkleLib;
namespace SparkleShare {
@ -41,7 +42,7 @@ namespace SparkleShare {
public SparkleSetupWindow () : base ("")
{
Title = "SparkleShare Setup";
Title = Catalog.GetString ("SparkleShare Setup");
BorderWidth = 0;
IconName = "folder-sparkleshare";
Resizable = false;
@ -70,17 +71,13 @@ namespace SparkleShare {
EventBox box = new EventBox ();
Gdk.Color bg_color = new Gdk.Color ();
Gdk.Color.Parse ("#2e3336", ref bg_color);
Gdk.Color.Parse ("#000", ref bg_color);
box.ModifyBg (StateType.Normal, bg_color);
string image_path = SparkleHelpers.CombineMore (Defines.DATAROOTDIR, "sparkleshare",
"pixmaps", "side-splash.png");
Image side_splash = SparkleUIHelpers.GetImage ("side-splash.png");
side_splash.Yalign = 1;
Image side_splash = new Image (image_path) {
Yalign = 1
};
box.Add (side_splash);
box.Add (side_splash);
HBox.PackStart (box, false, false, 0);
HBox.PackStart (VBox, true, true, 0);
@ -125,7 +122,7 @@ namespace SparkleShare {
layout_vertical.PackStart (description, false, false, 21);
if (widget != null)
layout_vertical.PackStart (widget, true, true, 21);
layout_vertical.PackStart (widget, true, true, 0);
Wrapper.PackStart (layout_vertical, true, true, 0);
ShowAll ();
@ -148,9 +145,7 @@ namespace SparkleShare {
new public void ShowAll ()
{
Present ();
Present ();
base.ShowAll ();
}

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -9,6 +9,7 @@
<AssemblyName>SparkleShare</AssemblyName>
<SchemaVersion>2.0</SchemaVersion>
<RootNamespace>SparkleShare</RootNamespace>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -37,15 +38,9 @@
<Reference Include="System" />
<Reference Include="Mono.Posix" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SparkleLib\SparkleLib.csproj">
<Project>{2C914413-B31C-4362-93C7-1AE34F09112A}</Project>
<Name>SparkleLib</Name>
</ProjectReference>
</ItemGroup>
<ProjectExtensions>
<MonoDevelop>
<Properties InternalTargetFrameworkVersion="3.5">
<Properties>
<MonoDevelop.Autotools.MakefileInfo IntegrationEnabled="true" RelativeMakefileName="Makefile.am">
<BuildFilesVar Sync="true" Name="SOURCES" />
<DeployFilesVar />
@ -63,11 +58,10 @@
<Compile Include="SparkleBubblesController.cs" />
<Compile Include="SparkleController.cs" />
<Compile Include="SparkleEntry.cs" />
<Compile Include="SparkleLinController.cs" />
<Compile Include="SparkleSetup.cs" />
<Compile Include="SparkleSetupController.cs" />
<Compile Include="SparkleSetupWindow.cs" />
<Compile Include="SparkleShare.cs" />
<Compile Include="Program.cs" />
<Compile Include="SparkleSpinner.cs" />
<Compile Include="SparkleStatusIcon.cs" />
<Compile Include="SparkleStatusIconController.cs" />
@ -77,5 +71,7 @@
<Compile Include="SparkleEventLog.cs" />
<Compile Include="SparkleAboutController.cs" />
<Compile Include="SparkleAbout.cs" />
<Compile Include="SparkleExtensions.cs" />
<Compile Include="SparkleControllerBase.cs" />
</ItemGroup>
</Project>

View file

@ -1,20 +1,14 @@

Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SparkleShare", "SparkleShare.csproj", "{728483AA-E34B-4441-BF2C-C8BC2901E4E0}"
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
{728483AA-E34B-4441-BF2C-C8BC2901E4E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{728483AA-E34B-4441-BF2C-C8BC2901E4E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{728483AA-E34B-4441-BF2C-C8BC2901E4E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -22,7 +16,5 @@ Global
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = SparkleShare.csproj
outputpath = ..\bin
name = SparkleShare
EndGlobalSection
EndGlobal

View file

@ -23,7 +23,7 @@ using System.Timers;
using AppIndicator;
#endif
using Gtk;
using SparkleLib;
using Mono.Unix;
namespace SparkleShare {
@ -31,6 +31,8 @@ namespace SparkleShare {
// user's notification area
public class SparkleStatusIcon {
public SparkleStatusIconController Controller = new SparkleStatusIconController ();
private Timer Animation;
private Gdk.Pixbuf [] AnimationFrames;
private int FrameNumber;
@ -46,14 +48,14 @@ namespace SparkleShare {
// Short alias for the translations
public static string _ (string s)
{
return s;
return Catalog.GetString (s);
}
public SparkleStatusIcon ()
{
AnimationFrames = CreateAnimationFrames ();
Animation = CreateAnimation ();
Animation = CreateAnimation ();
#if HAVE_APP_INDICATOR
this.indicator = new ApplicationIndicator ("sparkleshare",
@ -66,45 +68,63 @@ namespace SparkleShare {
this.status_icon.Activate += ShowMenu; // Primary mouse button click
this.status_icon.PopupMenu += ShowMenu; // Secondary mouse button click
this.status_icon.Pixbuf = AnimationFrames [0];
#endif
SetNormalState ();
if (Controller.Folders.Length == 0)
StateText = _("Welcome to SparkleShare!");
else
StateText = _("Up to date") + " — " + Controller.FolderSize;
CreateMenu ();
SparkleShare.Controller.FolderSizeChanged += delegate {
Controller.UpdateMenuEvent += delegate (IconState state) {
Application.Invoke (delegate {
if (!Animation.Enabled)
SetNormalState ();
switch (state) {
case IconState.Idle:
UpdateMenu ();
});
};
SparkleShare.Controller.FolderListChanged += delegate {
Application.Invoke (delegate {
SetNormalState ();
CreateMenu ();
});
};
Animation.Stop ();
SparkleShare.Controller.OnIdle += delegate {
Application.Invoke (delegate {
SetNormalState ();
UpdateMenu ();
});
};
if (Controller.Folders.Length == 0)
StateText = _("Welcome to SparkleShare!");
else
StateText = _("Up to date") + " — " + Controller.FolderSize;
SparkleShare.Controller.OnSyncing += delegate {
Application.Invoke (delegate {
SetAnimationState ();
UpdateMenu ();
});
};
#if HAVE_APP_INDICATOR
this.indicator.IconName = "process-syncing-sparkleshare-i";
#else
this.status_icon.Pixbuf = AnimationFrames [0];
#endif
SparkleShare.Controller.OnError += delegate {
Application.Invoke (delegate {
SetNormalState (true);
UpdateMenu ();
UpdateStateText ();
CreateMenu ();
break;
case IconState.Syncing:
StateText = _("Syncing…");
UpdateStateText (); // TODO
if (!Animation.Enabled)
Animation.Start ();
break;
case IconState.Error:
StateText = _("Not everything is synced");
UpdateStateText ();
CreateMenu ();
#if HAVE_APP_INDICATOR
this.indicator.IconName = "sparkleshare-syncing-error";
#else
this.status_icon.Pixbuf = SparkleUIHelpers.GetIcon ("sparkleshare-syncing-error", 24);
#endif
break;
}
});
};
}
@ -176,18 +196,18 @@ namespace SparkleShare {
};
folder_item.Activated += delegate {
SparkleShare.Controller.OpenSparkleShareFolder ();
Program.Controller.OpenSparkleShareFolder ();
};
Menu.Add (folder_item);
if (SparkleShare.Controller.Folders.Count > 0) {
if (Program.Controller.Folders.Count > 0) {
// Creates a menu item for each repository with a link to their logs
foreach (string folder_name in SparkleShare.Controller.Folders) {
foreach (string folder_name in Program.Controller.Folders) {
Gdk.Pixbuf folder_icon;
if (SparkleShare.Controller.UnsyncedFolders.Contains (folder_name)) {
if (Program.Controller.UnsyncedFolders.Contains (folder_name)) {
folder_icon = IconTheme.Default.LoadIcon ("dialog-error", 16,
IconLookupFlags.GenericFallback);
@ -205,7 +225,7 @@ namespace SparkleShare {
}
} else {
MenuItem no_folders_item = new MenuItem (_("No Remote Folders Yet")) {
MenuItem no_folders_item = new MenuItem (_("No projects yet")) {
Sensitive = false
};
@ -215,9 +235,9 @@ namespace SparkleShare {
Menu.Add (new SeparatorMenuItem ());
// Opens the wizard to add a new remote folder
MenuItem sync_item = new MenuItem (_("Add Remote Folder…"));
MenuItem sync_item = new MenuItem (_("Add Project…"));
if (SparkleShare.Controller.FirstRun)
if (Program.Controller.FirstRun)
sync_item.Sensitive = false;
sync_item.Activated += delegate {
@ -241,7 +261,7 @@ namespace SparkleShare {
MenuItem recent_events_item = new MenuItem (_("Show Recent Events"));
if (SparkleShare.Controller.Folders.Count < 1)
if (Program.Controller.Folders.Count < 1)
recent_events_item.Sensitive = false;
recent_events_item.Activated += delegate {
@ -258,13 +278,13 @@ namespace SparkleShare {
MenuItem notify_item;
if (SparkleShare.Controller.NotificationsEnabled)
if (Program.Controller.NotificationsEnabled)
notify_item = new MenuItem (_("Turn Notifications Off"));
else
notify_item = new MenuItem (_("Turn Notifications On"));
notify_item.Activated += delegate {
SparkleShare.Controller.ToggleNotifications ();
Program.Controller.ToggleNotifications ();
CreateMenu ();
};
@ -291,7 +311,7 @@ namespace SparkleShare {
MenuItem quit_item = new MenuItem (_("Quit"));
quit_item.Activated += delegate {
SparkleShare.Controller.Quit ();
Program.Controller.Quit ();
};
Menu.Add (quit_item);
@ -308,12 +328,12 @@ namespace SparkleShare {
private EventHandler OpenFolderDelegate (string name)
{
return delegate {
SparkleShare.Controller.OpenSparkleShareFolder (name);
Program.Controller.OpenSparkleShareFolder (name);
};
}
public void UpdateMenu ()
public void UpdateStateText ()
{
((Menu.Children [0] as MenuItem).Child as Label).Text = StateText;
Menu.ShowAll ();
@ -323,11 +343,7 @@ namespace SparkleShare {
// Makes the menu visible
private void ShowMenu (object o, EventArgs args)
{
if ((SparkleBackend.Platform == PlatformID.Unix ||
SparkleBackend.Platform == PlatformID.MacOSX))
Menu.Popup (null, null, SetPosition, 0, Global.CurrentEventTime);
else
Menu.Popup (null, null, null, 0, Global.CurrentEventTime);
Menu.Popup (null, null, SetPosition, 0, Global.CurrentEventTime);
}
@ -337,63 +353,6 @@ namespace SparkleShare {
StatusIcon.PositionMenu (menu, out x, out y, out push_in, this.status_icon.Handle);
}
#endif
// The state when there's nothing going on
private void SetNormalState ()
{
SetNormalState (false);
}
// The state when there's nothing going on
private void SetNormalState (bool error)
{
Animation.Stop ();
if (SparkleShare.Controller.Folders.Count == 0) {
StateText = _("Welcome to SparkleShare!");
Application.Invoke (delegate {
#if HAVE_APP_INDICATOR
this.indicator.IconName = "process-syncing-sparkleshare-i";
#else
this.status_icon.Pixbuf = AnimationFrames [0];
#endif
});
} else {
if (error) {
StateText = _("Not everything is synced");
Application.Invoke (delegate {
#if HAVE_APP_INDICATOR
this.indicator.IconName = "sparkleshare-syncing-error";
#else
this.status_icon.Pixbuf = SparkleUIHelpers.GetIcon ("sparkleshare-syncing-error", 24);
#endif
});
} else {
StateText = _("Up to date") + " (" + SparkleShare.Controller.FolderSize + ")";
Application.Invoke (delegate {
#if HAVE_APP_INDICATOR
this.indicator.IconName = "process-syncing-sparkleshare-i";
#else
this.status_icon.Pixbuf = AnimationFrames [0];
#endif
});
}
}
}
// The state when animating
private void SetAnimationState ()
{
StateText = _("Syncing…");
if (!Animation.Enabled)
Animation.Start ();
}
}

View file

@ -38,29 +38,29 @@ namespace SparkleShare {
public string [] Folders {
get {
return SparkleShare.Controller.Folders.ToArray ();
return Program.Controller.Folders.ToArray ();
}
}
public string FolderSize {
get {
return SparkleShare.Controller.FolderSize;
return Program.Controller.FolderSize;
}
}
public SparkleStatusIconController ()
{
SparkleShare.Controller.FolderSizeChanged += delegate {
Program.Controller.FolderSizeChanged += delegate {
if (UpdateMenuEvent != null)
UpdateMenuEvent (CurrentState);
};
SparkleShare.Controller.FolderListChanged += delegate {
Program.Controller.FolderListChanged += delegate {
if (UpdateMenuEvent != null)
UpdateMenuEvent (CurrentState);
};
SparkleShare.Controller.OnIdle += delegate {
Program.Controller.OnIdle += delegate {
if (CurrentState != IconState.Error)
CurrentState = IconState.Idle;
@ -68,14 +68,16 @@ namespace SparkleShare {
UpdateMenuEvent (CurrentState);
};
SparkleShare.Controller.OnSyncing += delegate {
Program.Controller.OnSyncing += delegate {
CurrentState = IconState.Syncing;
// TODO up down both
if (UpdateMenuEvent != null)
UpdateMenuEvent (IconState.Syncing);
};
SparkleShare.Controller.OnError += delegate {
Program.Controller.OnError += delegate {
CurrentState = IconState.Error;
if (UpdateMenuEvent != null)

View file

@ -40,14 +40,20 @@ namespace SparkleShare {
public static Gdk.Pixbuf GetIcon (string name, int size)
{
IconTheme icon_theme = new IconTheme ();
icon_theme.AppendSearchPath (SparklePaths.SparkleIconPath);
icon_theme.AppendSearchPath (SparklePaths.SparkleLocalIconPath);
icon_theme.AppendSearchPath (
Path.Combine (SparkleUI.AssetsPath, "icons"));
icon_theme.AppendSearchPath (
Path.Combine (SparkleConfig.ConfigPath, "icons"));
try {
return icon_theme.LoadIcon (name, size, IconLookupFlags.GenericFallback);
} catch {
try {
return icon_theme.LoadIcon ("gtk-missing-image", size, IconLookupFlags.GenericFallback);
} catch {
return null;
}
@ -55,6 +61,15 @@ namespace SparkleShare {
}
public static Image GetImage (string name)
{
string image_path = SparkleHelpers.CombineMore (Defines.DATAROOTDIR, "sparkleshare",
"pixmaps", name);
return new Image (image_path);
}
// Converts a Gdk RGB color to a hex value.
// Example: from "rgb:0,0,0" to "#000000"
public static string GdkColorToHex (Gdk.Color color)

View file

@ -22,13 +22,16 @@ using System.IO;
using System.Runtime.InteropServices;
using System.Text;
#if __MonoCS__
using Mono.Unix;
//using Mono.Unix.Native;
#endif
using SparkleLib;
using SparkleLib.Options;
namespace SparkleShare {
// This is SparkleShare!
// http://blogs.msdn.com/b/ericlippert/archive/2010/03/09/do-not-name-a-class-the-same-as-its-namespace-part-one.aspx
public class Program {
public static SparkleController Controller;
@ -38,22 +41,18 @@ namespace SparkleShare {
// Short alias for the translations
public static string _ (string s)
{
#if __MonoCS__
return Catalog.GetString (s);
#else
return s;
#endif
}
#if !__MonoCS__
[STAThread]
#endif
public static void Main (string [] args)
{
// Don't allow running as root on Linux or Mac
#if __MonoCS__
if (new Mono.Unix.UnixUserInfo (Mono.Unix.UnixEnvironment.UserName).UserId == 0) {
Console.WriteLine (_("Sorry, you can't run SparkleShare with these permissions."));
Console.WriteLine (_("Things would go utterly wrong."));
Environment.Exit (-1);
}
#endif
// Parse the command line options
bool show_help = false;
OptionSet option_set = new OptionSet () {
@ -73,25 +72,10 @@ namespace SparkleShare {
if (show_help)
ShowHelp (option_set);
// Load the right controller for the OS
string controller_name = "Lin";
switch (SparkleBackend.Platform) {
case PlatformID.Unix:
SetProcessName ("sparkleshare");
break;
case PlatformID.MacOSX:
controller_name = "Mac";
break;
case PlatformID.Win32NT:
controller_name = "Win";
break;
}
// Initialize the controller this way so that
// there aren't any exceptions in the OS specific UI's
Controller = (SparkleController) Activator.CreateInstance (
Type.GetType ("SparkleShare.Sparkle" + controller_name + "Controller"));
Controller = new SparkleController ();
Controller.Initialize ();
if (Controller != null) {

View file

@ -28,9 +28,9 @@ using CefSharp;
namespace SparkleShare {
public class SparkleWinController : SparkleController {
public class SparkleController : SparkleControllerBase {
public SparkleWinController () : base ()
public SparkleController () : base ()
{
}

View file

@ -71,6 +71,12 @@
<DesignTime>True</DesignTime>
<DependentUpon>GlobalAssemblyInfo.tt</DependentUpon>
</Compile>
<Compile Include="..\SparkleControllerBase.cs">
<Link>SparkleControllerBase.cs</Link>
</Compile>
<Compile Include="..\SparkleExtensions.cs">
<Link>SparkleExtensions.cs</Link>
</Compile>
<Compile Include="ApplicationSchemeHandler.cs" />
<Compile Include="AssemblyInfo.cs" />
<Compile Include="controls\ExampleTextBox.cs">
@ -104,8 +110,8 @@
</Compile>
<Compile Include="..\SparkleSetupController.cs" />
<Compile Include="..\SparkleUI.cs" />
<Compile Include="..\SparkleController.cs" />
<Compile Include="..\SparkleAboutController.cs" />
<Compile Include="SparkleController.cs" />
<Compile Include="SparkleEventLog.cs">
<SubType>Form</SubType>
</Compile>
@ -121,7 +127,6 @@
<Compile Include="Program.cs" />
<Compile Include="SparkleStatusIcon.cs" />
<Compile Include="SparkleUIHelpers.cs" />
<Compile Include="SparkleWinController.cs" />
<Compile Include="controls\TablessControl.cs">
<SubType>Component</SubType>
</Compile>

View file

@ -1,5 +1,10 @@
#!/bin/bash
if [[ $UID -eq 0 ]]; then
echo "Cannot run as root. Things would go utterly wrong."
exit 1
fi
if [ "$XDG_RUNTIME_DIR" ]; then
pidfile=${XDG_RUNTIME_DIR}/sparkleshare.pid
else