This commit is contained in:
Alex Hudson 2011-06-13 13:30:11 +01:00
commit d139a53a3f
36 changed files with 2697 additions and 567 deletions

13
README
View file

@ -63,13 +63,18 @@ Note:
Build on Linux:
===============
Installing the build dependencies on Debian:
Installing the build dependencies on Debian or Ubuntu:
$ sudo apt-get install gtk-sharp2 mono-runtime mono-devel monodevelop \
libndesk-dbus1.0-cil-dev nant libnotify-cil-dev libgtk2.0-cil-dev \
libwebkit-cil-dev intltool libtool python-nautilus libndesk-dbus-glib1.0-cil-dev
Or on Fedora:
For Ubuntu libappindicator support, run the following before building:
$ sudo apt-get install libappindicator0.1-cil-dev
On Fedora:
$ sudo yum install gtk-sharp2-devel mono-core mono-devel monodevelop \
ndesk-dbus-devel ndesk-dbus-glib-devel nautilus-python-devel nant \
@ -79,13 +84,13 @@ Or on Fedora:
You can build and install SparkleShare like this:
$ ./configure (or ./autogen if you got SparkleShare from the repository)
$ ./configure --prefix=/usr (or ./autogen.sh if you build from the repository)
$ make
$ sudo make install
Note:
Use './configure --prefix=/usr' if you want the Nautilus extension to work.
Use '--prefix=/usr' if you want the Nautilus extension to work.
Run on Mac:

View file

@ -198,7 +198,7 @@ namespace SparkleLib {
if (!AnyDifferences)
return;
SparkleGit git = new SparkleGit (LocalPath, "commit -m '" + message + "'");
SparkleGit git = new SparkleGit (LocalPath, "commit -m \"" + message + "\"");
git.Start ();
git.WaitForExit ();
@ -405,18 +405,17 @@ namespace SparkleLib {
if (match.Success) {
SparkleChangeSet change_set = new SparkleChangeSet ();
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.Timestamp = new DateTime (int.Parse (match.Groups [4].Value),
int.Parse (match.Groups [5].Value), int.Parse (match.Groups [6].Value),
int.Parse (match.Groups [7].Value), int.Parse (match.Groups [8].Value),
int.Parse (match.Groups [9].Value));
string time_zone = match.Groups [10].Value;
int our_offset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now).Hours;
int their_offset = int.Parse (time_zone.Substring (1, 2));
@ -445,10 +444,13 @@ namespace SparkleLib {
if (change_type.Equals ("A")) {
change_set.Added.Add (file_path);
} else if (change_type.Equals ("M")) {
change_set.Edited.Add (file_path);
} else if (change_type.Equals ("D")) {
change_set.Deleted.Add (file_path);
} else if (change_type.Equals ("R")) {
int tab_pos = entry_line.LastIndexOf ("\t");
file_path = entry_line.Substring (42, tab_pos - 42);
@ -531,6 +533,7 @@ namespace SparkleLib {
return message + "..." + n;
}
message = message.Replace ("\"", "");
return message.TrimEnd ();
}

View file

@ -24,6 +24,7 @@ namespace SparkleLib {
public string UserName;
public string UserEmail;
public string Folder;
public string Revision;
public DateTime Timestamp;
public bool IsMerge = false;

View file

@ -56,18 +56,23 @@ namespace SparkleLib {
private void CreateInitialConfig ()
{
string user_name = Environment.UserName;
string user_name = "Unknown";
if (SparkleBackend.Platform == PlatformID.Unix ||
SparkleBackend.Platform == PlatformID.MacOSX) {
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;
}
if (string.IsNullOrEmpty (user_name))
user_name = Environment.UserName;
else
user_name = user_name.TrimEnd (",".ToCharArray());
user_name = "Unknown";
TextWriter writer = new StreamWriter (Path);
string n = Environment.NewLine;

View file

@ -34,19 +34,21 @@ namespace SparkleLib {
public abstract class SparkleRepoBase {
private TimeSpan short_interval = new TimeSpan (0, 0, 3, 0);
private TimeSpan long_interval = new TimeSpan (0, 0, 10, 0);
private Timer local_timer = new Timer () { Interval = 250 };
private Timer remote_timer = new Timer () { Interval = 60000 };
private FileSystemWatcher watcher;
private SparkleListenerBase listener;
private TimeSpan poll_interval;
private Timer local_timer = new Timer () { Interval = 0.25 * 1000 };
private Timer remote_timer = new Timer () { Interval = 10 * 1000 };
private DateTime last_poll = DateTime.Now;
private List <double> sizebuffer = new List<double> ();
private bool has_changed = false;
private Object change_lock = new Object ();
private bool has_changed = false;
private Object change_lock = new Object ();
protected SyncStatus status;
protected bool is_buffering = false;
protected bool is_polling = true;
protected bool server_online = true;
public readonly SparkleBackend Backend;
@ -75,9 +77,10 @@ namespace SparkleLib {
public SparkleRepoBase (string path, SparkleBackend backend)
{
LocalPath = path;
Name = Path.GetFileName (LocalPath);
Backend = backend;
LocalPath = path;
Name = Path.GetFileName (LocalPath);
Backend = backend;
this.poll_interval = this.short_interval;
SyncStatusChanged += delegate (SyncStatus status) {
this.status = status;
@ -96,7 +99,12 @@ namespace SparkleLib {
};
this.remote_timer.Elapsed += delegate {
if (this.is_polling) {
bool time_to_poll = (DateTime.Compare (this.last_poll,
DateTime.Now.Subtract (this.poll_interval)) < 0);
if (time_to_poll) {
this.last_poll = DateTime.Now;
if (CheckForRemoteChanges ())
SyncDownBase ();
}
@ -192,13 +200,6 @@ namespace SparkleLib {
}
public bool IsPolling {
get {
return this.is_polling;
}
}
// Disposes all resourses of this object
public void Dispose ()
{
@ -230,7 +231,8 @@ namespace SparkleLib {
// Stop polling when the connection to the irc channel is succesful
this.listener.Connected += delegate {
this.is_polling = false;
this.poll_interval = this.long_interval;
this.last_poll = DateTime.Now;
// Check for changes manually one more time
if (CheckForRemoteChanges ())
@ -243,8 +245,8 @@ namespace SparkleLib {
// Start polling when the connection to the irc channel is lost
this.listener.Disconnected += delegate {
this.poll_interval = this.short_interval;
SparkleHelpers.DebugInfo (Name, "Falling back to polling");
this.is_polling = true;
};
// Fetch changes when there is a message in the irc channel
@ -262,12 +264,11 @@ namespace SparkleLib {
}
}
};
// Start listening
if (!this.listener.IsConnected && !this.listener.IsConnecting)
if (!this.listener.IsConnected && !this.listener.IsConnecting) {
this.listener.Connect ();
else
this.is_polling = false;
}
}
@ -302,7 +303,7 @@ namespace SparkleLib {
// Starts a timer when something changes
public void OnFileActivity (object o, FileSystemEventArgs args)
{
if (args.FullPath.Contains ("/."))
if (args.FullPath.Contains (Path.DirectorySeparatorChar + "."))
return;
WatcherChangeTypes wct = args.ChangeType;

View file

@ -56,25 +56,6 @@
<string key="NSTitle">SparkleShare</string>
<object class="NSMutableArray" key="NSMenuItems">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSMenuItem" id="238522557">
<reference key="NSMenu" ref="110575045"/>
<string key="NSTitle">About SparkleShare</string>
<string key="NSKeyEquiv"/>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="35465992"/>
<reference key="NSMixedImage" ref="502551668"/>
</object>
<object class="NSMenuItem" id="304266470">
<reference key="NSMenu" ref="110575045"/>
<bool key="NSIsDisabled">YES</bool>
<bool key="NSIsSeparator">YES</bool>
<string key="NSTitle"/>
<string key="NSKeyEquiv"/>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="35465992"/>
<reference key="NSMixedImage" ref="502551668"/>
</object>
<object class="NSMenuItem" id="1046388886">
<reference key="NSMenu" ref="110575045"/>
<string key="NSTitle">Services</string>
@ -949,14 +930,6 @@
</object>
<int key="connectionID">534</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">delegate</string>
<reference key="source" ref="1050"/>
<reference key="destination" ref="238522557"/>
</object>
<int key="connectionID">538</int>
</object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
@ -1184,23 +1157,16 @@
<reference key="object" ref="110575045"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="238522557"/>
<reference ref="755159360"/>
<reference ref="908899353"/>
<reference ref="632727374"/>
<reference ref="646227648"/>
<reference ref="304266470"/>
<reference ref="1046388886"/>
<reference ref="1056857174"/>
<reference ref="342932134"/>
</object>
<reference key="parent" ref="694149608"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">58</int>
<reference key="object" ref="238522557"/>
<reference key="parent" ref="110575045"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">134</int>
<reference key="object" ref="755159360"/>
@ -1221,11 +1187,6 @@
<reference key="object" ref="646227648"/>
<reference key="parent" ref="110575045"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">236</int>
<reference key="object" ref="304266470"/>
<reference key="parent" ref="110575045"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">131</int>
<reference key="object" ref="1046388886"/>
@ -1548,8 +1509,6 @@
<string>221.ImportedFromIB2</string>
<string>23.IBPluginDependency</string>
<string>23.ImportedFromIB2</string>
<string>236.IBPluginDependency</string>
<string>236.ImportedFromIB2</string>
<string>239.IBPluginDependency</string>
<string>239.ImportedFromIB2</string>
<string>24.IBEditorWindowLastContentRect</string>
@ -1600,8 +1559,6 @@
<string>57.IBPluginDependency</string>
<string>57.ImportedFromIB2</string>
<string>57.editorWindowContentRectSynchronizationRect</string>
<string>58.IBPluginDependency</string>
<string>58.ImportedFromIB2</string>
<string>92.IBPluginDependency</string>
<string>92.ImportedFromIB2</string>
</object>
@ -1693,8 +1650,6 @@
<integer value="1"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<integer value="1"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<integer value="1"/>
<string>{{514, 649}, {194, 73}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<integer value="1"/>
@ -1739,14 +1694,12 @@
<integer value="1"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<integer value="1"/>
<string>{{358, 569}, {223, 153}}</string>
<string>{{358, 599}, {213, 123}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<integer value="1"/>
<string>{{23, 794}, {245, 183}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<integer value="1"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<integer value="1"/>
</object>
</object>
<object class="NSMutableDictionary" key="unlocalizedProperties">

View file

@ -0,0 +1,219 @@
// 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.Drawing;
using System.IO;
using System.Threading;
using MonoMac.Foundation;
using MonoMac.AppKit;
using MonoMac.ObjCRuntime;
using MonoMac.WebKit;
using SparkleLib; // Only used for SparkleChangeSet
namespace SparkleShare {
public class SparkleEventLog : NSWindow {
private WebView WebView;
private NSBox Separator;
private string HTML;
private NSPopUpButton popup_button;
private NSProgressIndicator ProgressIndicator;
private List<SparkleChangeSet> change_sets;
private string selected_log = null;
public SparkleEventLog (IntPtr handle) : base (handle) { }
public SparkleEventLog () : base ()
{
Title = "Recent Events";
Delegate = new SparkleEventsDelegate ();
SetFrame (new RectangleF (0, 0, 480, 640), true);
Center ();
StyleMask = (NSWindowStyle.Closable |
NSWindowStyle.Miniaturizable |
NSWindowStyle.Titled);
MaxSize = new SizeF (480, 640);
MinSize = new SizeF (480, 640);
HasShadow = true;
BackingType = NSBackingStore.Buffered;
CreateEvents ();
UpdateEvents (false);
UpdateChooser ();
OrderFrontRegardless ();
}
private void CreateEvents ()
{
Separator = new NSBox (new RectangleF (0, 573, 480, 1)) {
BorderColor = NSColor.LightGray,
BoxType = NSBoxType.NSBoxCustom
};
ContentView.AddSubview (Separator);
WebView = new WebView (new RectangleF (0, 0, 480, 573 ), "", ""){
PolicyDelegate = new SparkleWebPolicyDelegate ()
};
ProgressIndicator = new NSProgressIndicator () {
Style = NSProgressIndicatorStyle.Spinning,
Frame = new RectangleF (WebView.Frame.Width / 2 - 10, WebView.Frame.Height / 2 + 10, 20, 20)
};
ProgressIndicator.StartAnimation (this);
Update ();
}
public void UpdateChooser ()
{
if (this.popup_button != null)
this.popup_button.RemoveFromSuperview ();
this.popup_button = new NSPopUpButton () {
Frame = new RectangleF (480 - 156 - 8, 640 - 31 - 26, 156, 26),
PullsDown = false
};
this.popup_button.AddItem ("All Folders");
this.popup_button.Menu.AddItem (NSMenuItem.SeparatorItem);
this.popup_button.AddItems (SparkleShare.Controller.Folders.ToArray ());
this.popup_button.Activated += delegate {
if (popup_button.IndexOfSelectedItem == 0)
this.selected_log = null;
else
this.selected_log = this.popup_button.SelectedItem.Title;
UpdateEvents (false);
};
ContentView.AddSubview (this.popup_button);
}
public void UpdateEvents ()
{
UpdateEvents (true);
}
public void UpdateEvents (bool silent)
{
if (!silent) {
InvokeOnMainThread (delegate {
if (WebView.Superview == ContentView)
WebView.RemoveFromSuperview ();
ContentView.AddSubview (ProgressIndicator);
});
}
Thread thread = new Thread (new ThreadStart (delegate {
using (NSAutoreleasePool pool = new NSAutoreleasePool ()) {
Stopwatch watch = new Stopwatch ();
watch.Start ();
this.change_sets = SparkleShare.Controller.GetLog (this.selected_log);
GenerateHTML ();
watch.Stop ();
// A short delay is less annoying than
// a flashing window
if (watch.ElapsedMilliseconds < 500 && !silent)
Thread.Sleep (500 - (int) watch.ElapsedMilliseconds);
AddHTML ();
}
}));
thread.Start ();
}
private void GenerateHTML ()
{
HTML = SparkleShare.Controller.GetHTMLLog (this.change_sets);
HTML = HTML.Replace ("<!-- $body-font-family -->", "Lucida Grande");
HTML = HTML.Replace ("<!-- $day-entry-header-font-size -->", "13.6px");
HTML = HTML.Replace ("<!-- $body-font-size -->", "13.4px");
HTML = HTML.Replace ("<!-- $secondary-font-color -->", "#bbb");
HTML = HTML.Replace ("<!-- $small-color -->", "#ddd");
HTML = HTML.Replace ("<!-- $day-entry-header-background-color -->", "#f5f5f5");
HTML = HTML.Replace ("<!-- $a-color -->", "#0085cf");
HTML = HTML.Replace ("<!-- $a-hover-color -->", "#009ff8");
HTML = HTML.Replace ("<!-- $no-buddy-icon-background-image -->",
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "avatar-default.png"));
HTML = HTML.Replace ("<!-- $document-added-background-image -->",
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "document-added-12.png"));
HTML = HTML.Replace ("<!-- $document-deleted-background-image -->",
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "document-deleted-12.png"));
HTML = HTML.Replace ("<!-- $document-edited-background-image -->",
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "document-edited-12.png"));
HTML = HTML.Replace ("<!-- $document-moved-background-image -->",
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "document-moved-12.png"));
}
private void AddHTML ()
{
InvokeOnMainThread (delegate {
if (ProgressIndicator.Superview == ContentView)
ProgressIndicator.RemoveFromSuperview ();
WebView.MainFrame.LoadHtmlString (HTML, new NSUrl (""));
ContentView.AddSubview (WebView);
Update ();
});
}
}
public class SparkleEventsDelegate : NSWindowDelegate {
public override bool WindowShouldClose (NSObject sender)
{
(sender as SparkleEventLog).OrderOut (this);
return false;
}
}
public class SparkleWebPolicyDelegate : WebPolicyDelegate {
public override void DecidePolicyForNavigation (WebView web_view, NSDictionary action_info,
NSUrlRequest request, WebFrame frame, NSObject decision_token)
{
string file_path = request.Url.ToString ();
file_path = file_path.Replace ("%20", " ");
NSWorkspace.SharedWorkspace.OpenFile (file_path);
}
}
}

View file

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

View file

@ -24,7 +24,7 @@
<ConsolePause>false</ConsolePause>
<CustomCommands>
<CustomCommands>
<Command type="AfterBuild" command="mkdir -p ${TargetDir}/${SolutionName}.app/Contents/Frameworks; cp -r /Users/hbons/Code/SparkleShare/SparkleShare/Mac/Growl.framework ${TargetDir}/${SolutionName}.app/Contents/Frameworks" externalConsole="true" />
<Command type="AfterBuild" command="mkdir -p ${TargetDir}/${SolutionName}.app/Contents/Frameworks; cp -r Growl.framework ${TargetDir}/${SolutionName}.app/Contents/Frameworks" externalConsole="true" />
</CustomCommands>
</CustomCommands>
</PropertyGroup>
@ -55,10 +55,6 @@
<Reference Include="MonoMac">
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="SparkleLib, Version=0.2.0.0, Culture=neutral, PublicKeyToken=null">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\bin\SparkleLib.dll</HintPath>
</Reference>
<Reference Include="Mono.Posix">
<SpecificVersion>False</SpecificVersion>
</Reference>
@ -66,6 +62,10 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\bin\Meebey.SmartIrc4net.dll</HintPath>
</Reference>
<Reference Include="SparkleLib, Version=0.2.1.0, Culture=neutral, PublicKeyToken=null">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\bin\SparkleLib.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="AppDelegate.cs">
@ -79,7 +79,6 @@
</Compile>
<Compile Include="SparkleWindow.cs" />
<Compile Include="SparkleIntro.cs" />
<Compile Include="SparkleLog.cs" />
<Compile Include="SparkleMacController.cs" />
<Compile Include="SparkleStatusIcon.cs" />
<Compile Include="SparkleUI.cs" />
@ -90,6 +89,7 @@
<Compile Include="SparkleAlert.cs" />
<Compile Include="SparkleBubble.cs" />
<Compile Include="SparkleMacWatcher.cs" />
<Compile Include="SparkleEventLog.cs" />
</ItemGroup>
<ItemGroup>
<Page Include="MainMenu.xib" />
@ -158,6 +158,18 @@
<Content Include="..\..\data\icons\error-active.png">
<Link>Pixmaps\error-active.png</Link>
</Content>
<Content Include="..\..\data\icons\document-added-12.png">
<Link>Pixmaps\document-added-12.png</Link>
</Content>
<Content Include="..\..\data\icons\document-edited-12.png">
<Link>Pixmaps\document-edited-12.png</Link>
</Content>
<Content Include="..\..\data\icons\document-deleted-12.png">
<Link>Pixmaps\document-deleted-12.png</Link>
</Content>
<Content Include="..\..\data\icons\document-moved-12.png">
<Link>Pixmaps\document-moved-12.png</Link>
</Content>
</ItemGroup>
<ItemGroup>
<Folder Include="Pixmaps\" />

View file

@ -43,6 +43,8 @@ namespace SparkleShare {
private NSMenuItem SyncMenuItem;
private NSMenuItem AboutMenuItem;
private NSMenuItem NotificationsMenuItem;
private NSMenuItem RecentEventsMenuItem;
private NSMenuItem QuitMenuItem;
private delegate void Task ();
private EventHandler [] Tasks;
@ -149,7 +151,7 @@ namespace SparkleShare {
Title = StateText
};
Menu.AddItem (StateMenuItem);
Menu.AddItem (StateMenuItem);
Menu.AddItem (NSMenuItem.SeparatorItem);
FolderMenuItem = new NSMenuItem () {
@ -176,7 +178,7 @@ namespace SparkleShare {
foreach (string folder_name in SparkleShare.Controller.Folders) {
NSMenuItem item = new NSMenuItem ();
item.Title = folder_name;
item.Title = folder_name;
if (SparkleShare.Controller.UnsyncedFolders.Contains (folder_name))
item.Image = NSImage.ImageNamed ("NSCaution");
@ -184,7 +186,7 @@ namespace SparkleShare {
item.Image = NSImage.ImageNamed ("NSFolder");
item.Image.Size = new SizeF (16, 16);
Tasks [i] = OpenEventLogDelegate (folder_name);
Tasks [i] = OpenFolderDelegate (folder_name);
FolderMenuItems [i] = item;
FolderMenuItems [i].Activated += Tasks [i];
@ -233,6 +235,25 @@ namespace SparkleShare {
Menu.AddItem (SyncMenuItem);
Menu.AddItem (NSMenuItem.SeparatorItem);
RecentEventsMenuItem = new NSMenuItem () {
Title = "Show Recent Events"
};
if (SparkleShare.Controller.Folders.Count > 0) {
RecentEventsMenuItem.Activated += delegate {
InvokeOnMainThread (delegate {
NSApplication.SharedApplication.ActivateIgnoringOtherApps (true);
if (SparkleUI.EventLog == null)
SparkleUI.EventLog = new SparkleEventLog ();
SparkleUI.EventLog.OrderFrontRegardless ();
SparkleUI.EventLog.MakeKeyAndOrderFront (this);
});
};
}
Menu.AddItem (RecentEventsMenuItem);
NotificationsMenuItem = new NSMenuItem ();
@ -255,28 +276,28 @@ namespace SparkleShare {
Menu.AddItem (NotificationsMenuItem);
Menu.AddItem (NSMenuItem.SeparatorItem);
AboutMenuItem = new NSMenuItem () {
Title = "About SparkleShare"
};
AboutMenuItem.Activated += delegate {
InvokeOnMainThread (delegate {
NSApplication.SharedApplication.ActivateIgnoringOtherApps (true);
AboutMenuItem.Activated += delegate {
InvokeOnMainThread (delegate {
NSApplication.SharedApplication.ActivateIgnoringOtherApps (true);
if (SparkleUI.About == null)
SparkleUI.About = new SparkleAbout ();
if (SparkleUI.About == null)
SparkleUI.About = new SparkleAbout ();
SparkleUI.About.OrderFrontRegardless ();
SparkleUI.About.MakeKeyAndOrderFront (this);
SparkleUI.About.CheckForNewVersion ();
});
};
SparkleUI.About.OrderFrontRegardless ();
SparkleUI.About.MakeKeyAndOrderFront (this);
SparkleUI.About.CheckForNewVersion ();
});
};
Menu.AddItem (AboutMenuItem);
StatusItem.Menu = Menu;
StatusItem.Menu.Update ();
}
@ -284,26 +305,10 @@ namespace SparkleShare {
// A method reference that makes sure that opening the
// event log for each repository works correctly
private EventHandler OpenEventLogDelegate (string path)
private EventHandler OpenFolderDelegate (string name)
{
return delegate {
InvokeOnMainThread (delegate {
NSApplication.SharedApplication.ActivateIgnoringOtherApps (true);
SparkleLog log = SparkleUI.OpenLogs.Find (delegate (SparkleLog l) {
return l.LocalPath.Equals (path);
});
// Check whether the log is already open, create a new one if
// that's not the case or present it to the user if it is
if (log == null) {
SparkleUI.OpenLogs.Add (new SparkleLog (path));
SparkleUI.OpenLogs [SparkleUI.OpenLogs.Count - 1].MakeKeyAndOrderFront (this);
} else {
log.OrderFrontRegardless ();
log.MakeKeyAndOrderFront (this);
}
});
SparkleShare.Controller.OpenSparkleShareFolder (name);
};
}

View file

@ -51,7 +51,7 @@ namespace SparkleShare {
public class SparkleUI : AppDelegate {
public static SparkleStatusIcon StatusIcon;
public static List <SparkleLog> OpenLogs;
public static SparkleEventLog EventLog;
public static SparkleIntro Intro;
public static SparkleAbout About;
public static NSFont Font;
@ -63,6 +63,7 @@ namespace SparkleShare {
{
string content_path = Directory.GetParent (
System.AppDomain.CurrentDomain.BaseDirectory).ToString ();
string app_path = Directory.GetParent (content_path).ToString ();
string growl_path = Path.Combine (app_path, "Frameworks", "Growl.framework", "Growl");
@ -88,18 +89,15 @@ namespace SparkleShare {
Font = NSFontManager.SharedFontManager.FontWithFamily
("Lucida Grande", NSFontTraitMask.Condensed, 0, 13);
OpenLogs = new List <SparkleLog> ();
StatusIcon = new SparkleStatusIcon ();
}
SparkleShare.Controller.NotificationRaised += delegate (string user_name, string user_email,
string message, string repository_path) {
InvokeOnMainThread (delegate {
foreach (SparkleLog log in OpenLogs) {
if (log.LocalPath.Equals (repository_path))
log.UpdateEventLog ();
}
if (EventLog != null)
EventLog.UpdateEvents ();
if (SparkleShare.Controller.NotificationsEnabled) {
if (NSApplication.SharedApplication.DockTile.BadgeLabel == null)
@ -134,20 +132,28 @@ namespace SparkleShare {
SparkleShare.Controller.AvatarFetched += delegate {
InvokeOnMainThread (delegate {
foreach (SparkleLog log in SparkleUI.OpenLogs)
log.UpdateEventLog ();
if (EventLog != null)
EventLog.UpdateEvents ();
});
};
SparkleShare.Controller.OnIdle += delegate {
InvokeOnMainThread (delegate {
foreach (SparkleLog log in SparkleUI.OpenLogs)
log.UpdateEventLog ();
});
};
SparkleShare.Controller.OnIdle += delegate {
InvokeOnMainThread (delegate {
if (EventLog != null)
EventLog.UpdateEvents ();
});
};
SparkleShare.Controller.FolderListChanged += delegate {
InvokeOnMainThread (delegate {
if (EventLog != null)
EventLog.UpdateChooser ();
});
};
if (SparkleShare.Controller.FirstRun) {
Intro = new SparkleIntro ();
Intro.ShowAccountForm ();
@ -179,5 +185,5 @@ namespace SparkleShare {
string path = NSBundle.MainBundle.PathForResource ("Growl", "plist");
return NSDictionary.FromFile (path);
}
}
}
}

View file

@ -7,6 +7,9 @@ TARGET = exe
LINK = $(REF_SPARKLESHARE) $(NOTIFY_SHARP_LIBS) $(WEBKIT_SHARP_LIBS)
if HAVE_APP_INDICATOR
BUILD_DEFINES="-define:HAVE_APP_INDICATOR"
endif
SOURCES = \
SparkleAbout.cs \
@ -16,7 +19,7 @@ SOURCES = \
SparkleInfobar.cs \
SparkleIntro.cs \
SparkleLinController.cs \
SparkleLog.cs \
SparkleEventLog.cs \
SparkleShare.cs \
SparkleSpinner.cs \
SparkleStatusIcon.cs \

View file

@ -19,6 +19,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
@ -222,7 +223,9 @@ namespace SparkleShare {
public List<string> Folders {
get {
return SparkleConfig.DefaultConfig.Folders;
List<string> folders = SparkleConfig.DefaultConfig.Folders;
folders.Sort ();
return folders;
}
}
@ -240,11 +243,31 @@ namespace SparkleShare {
}
}
public List <SparkleChangeSet> GetLog (string name)
public List<SparkleChangeSet> GetLog ()
{
List<SparkleChangeSet> list = new List<SparkleChangeSet> ();
foreach (SparkleRepoBase repo in Repositories)
list.AddRange (repo.GetChangeSets (50));
list.Sort ((x, y) => (x.Timestamp.CompareTo (y.Timestamp)));
list.Reverse ();
if (list.Count > 100)
return list.GetRange (0, 100);
else
return list.GetRange (0, list.Count);
}
public List<SparkleChangeSet> GetLog (string name)
{
if (name == null)
return GetLog ();
string path = Path.Combine (SparklePaths.SparklePath, name);
int log_size = 30;
int log_size = 50;
foreach (SparkleRepoBase repo in Repositories) {
if (repo.LocalPath.Equals (path))
@ -260,10 +283,9 @@ namespace SparkleShare {
public abstract string EventEntryHTML { get; }
public string GetHTMLLog (string name)
public string GetHTMLLog (List<SparkleChangeSet> change_sets)
{
List <SparkleChangeSet> change_sets = GetLog (name);
List <ActivityDay> activity_days = new List <ActivityDay> ();
List <ActivityDay> activity_days = new List <ActivityDay> ();
if (change_sets.Count == 0)
return null;
@ -302,68 +324,58 @@ namespace SparkleShare {
string event_entry = "<dl>";
if (change_set.IsMerge) {
event_entry += "<dt>Merged a branch</dt>";
event_entry += "<dd>Did something magical</dd>";
} else {
if (change_set.Edited.Count > 0) {
event_entry += "<dt>Edited</dt>";
foreach (string file_path in change_set.Edited) {
string absolute_file_path = SparkleHelpers.CombineMore (SparklePaths.SparklePath,
name, file_path);
change_set.Folder, file_path);
if (File.Exists (absolute_file_path))
event_entry += "<dd><a href='" + absolute_file_path + "'>" + file_path + "</a></dd>";
event_entry += "<dd class='document-edited'><a href='" + absolute_file_path + "'>" + file_path + "</a></dd>";
else
event_entry += "<dd>" + file_path + "</dd>";
event_entry += "<dd class='document-edited'>" + file_path + "</dd>";
}
}
if (change_set.Added.Count > 0) {
event_entry += "<dt>Added</dt>";
foreach (string file_path in change_set.Added) {
string absolute_file_path = SparkleHelpers.CombineMore (SparklePaths.SparklePath,
name, file_path);
change_set.Folder, file_path);
if (File.Exists (absolute_file_path))
event_entry += "<dd><a href='" + absolute_file_path + "'>" + file_path + "</a></dd>";
event_entry += "<dd class='document-added'><a href='" + absolute_file_path + "'>" + file_path + "</a></dd>";
else
event_entry += "<dd>" + file_path + "</dd>";
event_entry += "<dd class='document-added'>" + file_path + "</dd>";
}
}
if (change_set.Deleted.Count > 0) {
event_entry += "<dt>Deleted</dt>";
foreach (string file_path in change_set.Deleted) {
string absolute_file_path = SparkleHelpers.CombineMore (SparklePaths.SparklePath,
name, file_path);
change_set.Folder, file_path);
if (File.Exists (absolute_file_path))
event_entry += "<dd><a href='" + absolute_file_path + "'>" + file_path + "</a></dd>";
event_entry += "<dd class='document-deleted'><a href='" + absolute_file_path + "'>" + file_path + "</a></dd>";
else
event_entry += "<dd>" + file_path + "</dd>";
event_entry += "<dd class='document-deleted'>" + file_path + "</dd>";
}
}
if (change_set.MovedFrom.Count > 0) {
event_entry += "<dt>Moved</dt>";
int i = 0;
foreach (string file_path in change_set.MovedFrom) {
string to_file_path = change_set.MovedTo [i];
string absolute_file_path = SparkleHelpers.CombineMore (SparklePaths.SparklePath,
name, file_path);
change_set.Folder, file_path);
string absolute_to_file_path = SparkleHelpers.CombineMore (SparklePaths.SparklePath,
name, to_file_path);
change_set.Folder, to_file_path);
if (File.Exists (absolute_file_path))
event_entry += "<dd><a href='" + absolute_file_path + "'>" + file_path + "</a><br/>" +
"<span class='moved-arrow'>&rarr;</span> ";
event_entry += "<dd class='document-moved'><a href='" + absolute_file_path + "'>" + file_path + "</a><br/>";
else
event_entry += "<dd>" + file_path + "<br/>" +
"<span class='moved-arrow'>&rarr;</span> ";
event_entry += "<dd class='document-moved'>" + file_path + "<br/>";
if (File.Exists (absolute_to_file_path))
event_entry += "<a href='" + absolute_to_file_path + "'>" + to_file_path + "</a></dd>";
@ -378,8 +390,10 @@ namespace SparkleShare {
event_entry += "</dl>";
event_entries += event_entry_html.Replace ("<!-- $event-entry-content -->", event_entry)
.Replace ("<!-- $event-user-name -->", change_set.UserName)
.Replace ("<!-- $event-avatar-url -->", "file://" + GetAvatar (change_set.UserEmail, 36) )
.Replace ("<!-- $event-time -->", change_set.Timestamp.ToString ("H:mm"));
.Replace ("<!-- $event-avatar-url -->", "file://" + GetAvatar (change_set.UserEmail, 36))
.Replace ("<!-- $event-time -->", change_set.Timestamp.ToString ("H:mm"))
.Replace ("<!-- $event-folder -->", change_set.Folder)
.Replace ("<!-- $event-folder-color -->", AssignColor (change_set.Folder));
}
string day_entry = "";
@ -1015,6 +1029,20 @@ namespace SparkleShare {
web_client.DownloadStringAsync (uri);
}
private string [] tango_palette = new string [] {"#eaab00", "#e37222",
"#3892ab", "#33c2cb", "#19b271", "#9eab05", "#8599a8", "#9ca696",
"#b88454", "#cc0033", "#8f6678", "#8c6cd0", "#796cbf", "#4060af",
"#aa9c8f", "#818a8f"};
private string AssignColor (string s)
{
string hash = GetMD5 (s).Substring (0, 8);
string numbers = Regex.Replace (hash, "[a-z]", "");
int number = 3 + int.Parse (numbers);
return this.tango_palette [number % this.tango_palette.Length];
}
}

View file

@ -28,9 +28,7 @@ using WebKit;
namespace SparkleShare {
public class SparkleLog : Window {
public readonly string LocalPath;
public class SparkleEventLog : Window {
private ScrolledWindow ScrolledWindow;
private MenuBar MenuBar;
@ -39,6 +37,10 @@ namespace SparkleShare {
private SparkleSpinner Spinner;
private string HTML;
private EventBox LogContent;
private List<SparkleChangeSet> change_sets;
private string selected_log = null;
private ComboBox combo_box;
private HBox layout_horizontal;
// Short alias for the translations
@ -48,48 +50,35 @@ namespace SparkleShare {
}
public SparkleLog (string path) : base ("")
public SparkleEventLog () : base ("")
{
LocalPath = path;
string name = System.IO.Path.GetFileName (LocalPath);
SetSizeRequest (480, 640);
Resizable = false;
BorderWidth = 0;
SetPosition (WindowPosition.Center);
// Open slightly off center for each consecutive window
if (SparkleUI.OpenLogs.Count > 0) {
Resizable = false;
BorderWidth = 0;
int x, y;
GetPosition (out x, out y);
Move (x + SparkleUI.OpenLogs.Count * 20, y + SparkleUI.OpenLogs.Count * 20);
}
// TRANSLATORS: {0} is a folder name, and {1} is a server address
Title = String.Format(_("Events in {0}"), name);
Title = _("Recent Events");
IconName = "folder-sparkleshare";
DeleteEvent += Close;
DeleteEvent += Close;
CreateEventLog ();
UpdateEventLog ();
CreateEvents ();
UpdateEvents (false);
UpdateChooser ();
}
private void CreateEventLog ()
private void CreateEvents ()
{
LogContent = new EventBox ();
VBox layout_vertical = new VBox (false, 0);
LogContent = new EventBox ();
ScrolledWindow = new ScrolledWindow ();
ScrolledWindow = new ScrolledWindow ();
WebView = new WebView () {
Editable = false
};
WebView = new WebView () {
Editable = false
};
WebView.HoveringOverLink += delegate (object o, WebKit.HoveringOverLinkArgs args) {
LinkStatus = args.Link;
@ -103,50 +92,83 @@ namespace SparkleShare {
process.StartInfo.Arguments = args.Request.Uri.Replace (" ", "\\ "); // Escape space-characters
process.Start ();
UpdateEventLog ();
UpdateEvents ();
}
};
ScrolledWindow.Add (WebView);
LogContent.Add (ScrolledWindow);
ScrolledWindow.Add (WebView);
LogContent.Add (ScrolledWindow);
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);
HButtonBox dialog_buttons = new HButtonBox {
Layout = ButtonBoxStyle.Edge,
BorderWidth = 12
};
Button open_folder_button = new Button (_("_Open Folder")) {
UseUnderline = true
};
open_folder_button.Clicked += delegate (object o, EventArgs args) {
SparkleShare.Controller.OpenSparkleShareFolder (LocalPath);
};
Button close_button = new Button (Stock.Close);
close_button.Clicked += delegate {
HideAll ();
};
dialog_buttons.Add (open_folder_button);
dialog_buttons.Add (close_button);
// We have to hide the menubar somewhere...
layout_vertical.PackStart (CreateShortcutsBar (), false, false, 0);
layout_vertical.PackStart (dialog_buttons, false, false, 0);
Add (layout_vertical);
ShowAll ();
}
public void UpdateEventLog ()
public void UpdateChooser ()
{
if (HTML == null) { // TODO: there may be a race condition here
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);
this.combo_box.Active = 0;
this.combo_box.RowSeparatorFunc = delegate (TreeModel model, TreeIter iter) {
string item = (string) this.combo_box.Model.GetValue (iter, 0);
return (item == "---");
};
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;
else
this.selected_log = selection;
UpdateEvents (false);
};
this.layout_horizontal.PackStart (this.combo_box, true, true, 0);
this.layout_horizontal.ShowAll ();
}
public void UpdateEvents ()
{
UpdateEvents (true);
}
public void UpdateEvents (bool silent)
{
if (!silent) {
LogContent.Remove (LogContent.Child);
Spinner = new SparkleSpinner (22);
LogContent.Add (Spinner);
@ -154,7 +176,17 @@ namespace SparkleShare {
}
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 ();
// A short delay is less annoying than
// a flashing window
if (watch.ElapsedMilliseconds < 500 && !silent)
Thread.Sleep (500 - (int) watch.ElapsedMilliseconds);
AddHTML ();
}));
@ -164,7 +196,7 @@ namespace SparkleShare {
private void GenerateHTML ()
{
HTML = SparkleShare.Controller.GetHTMLLog (System.IO.Path.GetFileName (LocalPath));
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");
@ -179,6 +211,18 @@ namespace SparkleShare {
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"));
}
@ -248,3 +292,4 @@ namespace SparkleShare {
}
}
}

View file

@ -19,6 +19,9 @@ using System;
using System.IO;
using System.Timers;
#if HAVE_APP_INDICATOR
using AppIndicator;
#endif
using Gtk;
using Mono.Unix;
@ -26,7 +29,7 @@ namespace SparkleShare {
// The statusicon that stays in the
// user's notification area
public class SparkleStatusIcon : StatusIcon {
public class SparkleStatusIcon {
private Timer Animation;
private Gdk.Pixbuf [] AnimationFrames;
@ -34,6 +37,12 @@ namespace SparkleShare {
private string StateText;
private Menu Menu;
#if HAVE_APP_INDICATOR
private ApplicationIndicator indicator;
#else
private StatusIcon status_icon;
#endif
// Short alias for the translations
public static string _ (string s)
{
@ -41,13 +50,23 @@ namespace SparkleShare {
}
public SparkleStatusIcon () : base ()
public SparkleStatusIcon ()
{
AnimationFrames = CreateAnimationFrames ();
Animation = CreateAnimation ();
Activate += ShowMenu; // Primary mouse button click
PopupMenu += ShowMenu; // Secondary mouse button click
#if HAVE_APP_INDICATOR
this.indicator = new ApplicationIndicator ("sparkleshare",
"process-syncing-sparkleshare-i", Category.ApplicationStatus) {
Status = Status.Attention
};
#else
this.status_icon = new StatusIcon ();
this.status_icon.Activate += ShowMenu; // Primary mouse button click
this.status_icon.PopupMenu += ShowMenu; // Secondary mouse button click
#endif
SetNormalState ();
CreateMenu ();
@ -120,8 +139,17 @@ namespace SparkleShare {
else
FrameNumber = 0;
string icon_name = "process-syncing-sparkleshare-";
for (int i = 0; i <= FrameNumber; i++)
icon_name += "i";
Application.Invoke (delegate {
Pixbuf = AnimationFrames [FrameNumber];
#if HAVE_APP_INDICATOR
this.indicator.IconName = icon_name;
#else
this.status_icon.Pixbuf = SparkleUIHelpers.GetIcon (icon_name, 24);
#endif
});
};
@ -156,20 +184,23 @@ namespace SparkleShare {
if (SparkleShare.Controller.Folders.Count > 0) {
// Creates a menu item for each repository with a link to their logs
foreach (string path in SparkleShare.Controller.Folders) {
foreach (string folder_name in SparkleShare.Controller.Folders) {
Gdk.Pixbuf folder_icon;
Gdk.Pixbuf folder_icon = IconTheme.Default.LoadIcon ("folder", 16,
IconLookupFlags.GenericFallback);
ImageMenuItem subfolder_item = new SparkleMenuItem (Path.GetFileName (path)) {
if (SparkleShare.Controller.UnsyncedFolders.Contains (folder_name)) {
folder_icon = IconTheme.Default.LoadIcon ("dialog-error", 16,
IconLookupFlags.GenericFallback);
} else {
folder_icon = IconTheme.Default.LoadIcon ("folder", 16,
IconLookupFlags.GenericFallback);
}
ImageMenuItem subfolder_item = new SparkleMenuItem (folder_name) {
Image = new Image (folder_icon)
};
// if (repo.HasUnsyncedChanges)
// folder_action.IconName = "dialog-error";
subfolder_item.Activated += OpenEventLogDelegate (path);
subfolder_item.Activated += OpenFolderDelegate (folder_name);
Menu.Add (subfolder_item);
}
@ -181,6 +212,8 @@ namespace SparkleShare {
Menu.Add (no_folders_item);
}
Menu.Add (new SeparatorMenuItem ());
// Opens the wizard to add a new remote folder
MenuItem sync_item = new MenuItem (_("Add Remote Folder…"));
@ -206,7 +239,24 @@ namespace SparkleShare {
Menu.Add (sync_item);
Menu.Add (new SeparatorMenuItem ());
MenuItem notify_item;
MenuItem recent_events_item = new MenuItem (_("Show Recent Events"));
if (SparkleShare.Controller.Folders.Count < 1)
recent_events_item.Sensitive = false;
recent_events_item.Activated += delegate {
Application.Invoke (delegate {
if (SparkleUI.EventLog == null)
SparkleUI.EventLog = new SparkleEventLog ();
SparkleUI.EventLog.ShowAll ();
SparkleUI.EventLog.Present ();
});
};
Menu.Add (recent_events_item);
MenuItem notify_item;
if (SparkleShare.Controller.NotificationsEnabled)
notify_item = new MenuItem (_("Turn Notifications Off"));
@ -241,34 +291,30 @@ namespace SparkleShare {
Menu.Add (quit_item);
Menu.ShowAll ();
#if HAVE_APP_INDICATOR
this.indicator.Menu = Menu;
#endif
}
// A method reference that makes sure that opening the
// event log for each repository works correctly
private EventHandler OpenEventLogDelegate (string path)
private EventHandler OpenFolderDelegate (string name)
{
return delegate {
SparkleShare.UI.AddEventLog (path);
SparkleShare.Controller.OpenSparkleShareFolder (name);
};
}
public void UpdateMenu ()
{
Menu.Remove (Menu.Children [0]);
MenuItem status_menu_item = new MenuItem (StateText) {
Sensitive = false
};
Menu.Add (status_menu_item);
Menu.ReorderChild (status_menu_item, 0);
((Menu.Children [0] as MenuItem).Child as Label).Text = StateText;
Menu.ShowAll ();
}
#if !HAVE_APP_INDICATOR
// Makes the menu visible
private void ShowMenu (object o, EventArgs args)
{
@ -279,9 +325,9 @@ namespace SparkleShare {
// Makes sure the menu pops up in the right position
private void SetPosition (Menu menu, out int x, out int y, out bool push_in)
{
PositionMenu (menu, out x, out y, out push_in, Handle);
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 ()
@ -299,19 +345,32 @@ namespace SparkleShare {
StateText = _("Welcome to SparkleShare!");
Application.Invoke (delegate {
Pixbuf = AnimationFrames [0];
#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 {
Pixbuf = SparkleUIHelpers.GetIcon ("sparkleshare-syncing-error", 24);
#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 {
Pixbuf = AnimationFrames [0];
#if HAVE_APP_INDICATOR
this.indicator.IconName = "process-syncing-sparkleshare-i";
#else
this.status_icon.Pixbuf = AnimationFrames [0];
#endif
});
}
}

View file

@ -33,7 +33,7 @@ namespace SparkleShare {
public class SparkleUI {
public static SparkleStatusIcon StatusIcon;
public static List <SparkleLog> OpenLogs;
public static SparkleEventLog EventLog;
public static SparkleIntro Intro;
@ -52,9 +52,6 @@ namespace SparkleShare {
// Create the statusicon
StatusIcon = new SparkleStatusIcon ();
// Keep track of which event logs are open
OpenLogs = new List <SparkleLog> ();
if (SparkleShare.Controller.FirstRun) {
Intro = new SparkleIntro ();
Intro.ShowAccountForm ();
@ -75,10 +72,8 @@ namespace SparkleShare {
SparkleShare.Controller.NotificationRaised += delegate (string user_name, string user_email,
string message, string repository_path) {
Application.Invoke (delegate {
foreach (SparkleLog log in OpenLogs) {
if (log.LocalPath.Equals (repository_path))
log.UpdateEventLog ();
}
if (EventLog != null)
EventLog.UpdateEvents ();
if (!SparkleShare.Controller.NotificationsEnabled)
return;
@ -91,10 +86,6 @@ namespace SparkleShare {
else
bubble.Icon = SparkleUIHelpers.GetIcon ("avatar-default", 32);
bubble.AddAction ("", "Show Events", delegate {
AddEventLog (repository_path);
});
bubble.Show ();
});
};
@ -111,38 +102,25 @@ namespace SparkleShare {
SparkleShare.Controller.AvatarFetched += delegate {
Application.Invoke (delegate {
foreach (SparkleLog log in OpenLogs)
log.UpdateEventLog ();
if (EventLog != null)
EventLog.UpdateEvents ();
});
};
SparkleShare.Controller.OnIdle += delegate {
Application.Invoke (delegate {
foreach (SparkleLog log in OpenLogs)
log.UpdateEventLog ();
if (EventLog != null)
EventLog.UpdateEvents ();
});
};
}
public void AddEventLog (string path)
{
SparkleLog log = SparkleUI.OpenLogs.Find (delegate (SparkleLog l) {
return l.LocalPath.Equals (path);
});
// Check whether the log is already open, create a new one if
// that's not the case or present it to the user if it is
if (log == null) {
OpenLogs.Add (new SparkleLog (path));
OpenLogs [OpenLogs.Count - 1].ShowAll ();
OpenLogs [OpenLogs.Count - 1].Present ();
} else {
log.ShowAll ();
log.Present ();
}
}
SparkleShare.Controller.FolderListChanged += delegate {
Application.Invoke (delegate {
if (EventLog != null)
EventLog.UpdateChooser ();
});
};
}
// Runs the application
public void Run ()

View file

@ -17,6 +17,7 @@ LINK_DBUS = $(NDESK_DBUS_LIBS) $(NDESK_DBUS_GLIB_LIBS)
LINK_DBUS_NO_GLIB = $(NDESK_DBUS_LIBS)
LINK_SMARTIRC4NET_SYSTEM = $(SMARTIRC4NET_LIBS)
LINK_SMARTIRC4NET_LOCAL = -r:$(abs_top_builddir)/$(SMARTIRC4NET_ASSEMBLY)
LINK_APP_INDICATOR = $(APP_INDICATOR_LIBS)
REF_NOTIFY_SHARP = $(LINK_SYSTEM) $(LINK_DBUS) $(GTKSHARP_LIBS) $(GLIBSHARP_LIBS)
LINK_NOTIFY_SHARP = -r:$(DIR_BIN)/NotifySharp.dll
@ -30,7 +31,7 @@ REF_SPARKLELIB = $(LINK_SYSTEM) $(LINK_MONO_POSIX)
LINK_SPARKLELIB = -r:$(DIR_BIN)/SparkleLib.dll
LINK_SPARKLELIB_DEPS = $(REF_SPARKLELIB) $(LINK_SPARKLELIB)
REF_SPARKLESHARE = $(LINK_DBUS) $(LINK_GTK) $(LINK_SPARKLELIB_DEPS)
REF_SPARKLESHARE = $(LINK_DBUS) $(LINK_GTK) $(LINK_SPARKLELIB_DEPS) $(LINK_APP_INDICATOR)
REF_SPARKLEDIFF = $(LINK_FRIENDFACE_DEPS) $(LINK_GTK) $(LINK_SPARKLELIB_DEPS)

View file

@ -96,6 +96,30 @@ AC_SUBST(WEBKIT_SHARP_LIBS)
SHAMROCK_CHECK_NUNIT
APPINDICATOR_REQUIRED=0.0.7
AC_ARG_ENABLE(appindicator,
AS_HELP_STRING([--enable-appindicator[=@<:@no/auto/yes@:>@]],[Build support for application indicators ]),
[enable_appindicator=$enableval],
[enable_appindicator="auto"])
if test x$enable_appindicator = xauto ; then
PKG_CHECK_EXISTS([appindicator-sharp-0.1 >= $APPINDICATOR_REQUIRED],
enable_appindicator="yes",
enable_appindicator="no")
fi
if test x$enable_appindicator = xyes ; then
PKG_CHECK_EXISTS([appindicator-sharp-0.1 >= $APPINDICATOR_REQUIRED],,
AC_MSG_ERROR([appindicator-sharp-0.1 is not installed]))
PKG_CHECK_MODULES(APP_INDICATOR,
appindicator-sharp-0.1 >= $APPINDICATOR_REQUIRED)
AC_SUBST(APP_INDICATOR_CFLAGS)
AC_SUBST(APP_INDICATOR_LIBS)
AC_DEFINE(HAVE_APP_INDICATOR, 1, [Have AppIndicator])
fi
AM_CONDITIONAL(HAVE_APP_INDICATOR, test x"$enable_appindicator" = xyes)
dnl Get nautilus extensions directory
SPARKLESHARE_NAUTILUS_PYTHON

1960
data/actions.svg Normal file

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 64 KiB

View file

@ -1,20 +1,16 @@
<div class='event-entry'>
<div class='event-entry-content'>
<div class='no-buddy-icon'>
<div class='buddy-icon' style='background-image: url("<!-- $event-avatar-url -->");'></div>
</div>
<div class='event-info'>
<b><!-- $event-user-name --></b>
<!-- $event-entry-content -->
<div class='wrapper'>
<div class='no-buddy-icon'>
<div class='buddy-icon' style='background-image: url("<!-- $event-avatar-url -->");'></div>
</div>
<b><!-- $event-user-name --></b><br/>
<small><!-- $event-time --></small>
</div>
<div class='event-time' style='background-color: <!-- $event-folder-color -->'><!-- $event-folder --></div>
</div>
<div class='event-time'><!-- $event-time --></div>
<!-- $event-entry-content -->
<div style='clear: both'></div>
</div>
</div>

View file

@ -4,7 +4,7 @@
<title>SparkleShare Event Log</title>
<style>
body {
background-color: #f0f0f0;
background-color: #dedede;
color: <!-- $body-color -->;
font-size: <!-- $body-font-size -->;
font-family: <!-- $body-font-family -->;
@ -16,7 +16,7 @@
small {
font-size: <!-- $small-font-size -->;
color: <!-- $small-color -->;
color: <!-- $secondary-font-color -->;
}
.moved-arrow {
@ -25,13 +25,9 @@
.day-entry-header {
font-size: <!-- $day-entry-header-font-size -->;
color: #babdb6;
text-align: center;
width: 90%;
text-shadow: 0 1px 0 rgba(255, 255, 255, 1.0);
color: #444;
margin-bottom: 9px;
margin-left: auto;
margin-right: auto;
margin-left: 30px;
}
.day-entry-content {
@ -48,43 +44,70 @@
}
.event-time {
opacity: 0.8;
font-size: 80%;
color: <!-- $secondary-font-color -->;
float: right;
color: #fff;
float: right;
padding: 3px 15px;
font-weight: bold;
-webkit-border-radius: 100px;
}
.event-entry-content {
display: block;
width: 400px;
background-color: #fff;
width: 440px;
background-color: #f0f0f0;
margin-left: auto;
margin-right: auto;
margin-bottom: 9px;
padding: 18px;
-webkit-border-radius: 6px;
border: #ddd 1px solid;
margin-bottom: 12px;
padding: 0px;
padding-bottom: 6px;
border: #ccc 1px solid;
}
.wrapper {
float: left;
}
dl {
padding: 0;
margin: 0;
padding-bottom: 15px;
}
dt {
padding-bottom: 12px;
padding-top: 12px;
font-size: 80%;
color: <!-- $secondary-font-color -->;
padding : 0;
margin: 0;
}
dd {
width: 300px;
width: 90%;
overflow: hidden;
padding-left: 0;
margin-left: 12px;
text-overflow: ellipsis;
padding-bottom: 9px;
padding: 0;
padding-top: 2px;
padding-bottom: 4px;
padding-left: 22px;
margin: 0;
margin-bottom: 2px;
margin-left: 12px;
border-bottom: 1px solid #ddd;
background-repeat: no-repeat;
background-position: center left;
}
dd:last-child {
border: none;
}
.document-added {
background-image: url('<!-- $document-added-background-image -->');
}
.document-deleted {
background-image: url('<!-- $document-deleted-background-image -->');
}
.document-edited {
background-image: url('<!-- $document-edited-background-image -->');
}
.document-moved {
background-image: url('<!-- $document-moved-background-image -->');
}
.no-buddy-icon {
@ -104,6 +127,11 @@
.event-info {
float: left;
padding: 15px;
margin-bottom: 6px;
width: 410px;
background-color: #fff;
border-bottom: 1px #ccc solid;
}
</style>
</head>

View file

@ -8,7 +8,12 @@ system_theme_icons = \
apps,folder-sparkleshare-24.png \
apps,folder-sparkleshare-256.png \
apps,folder-sparkleshare-32.png \
apps,folder-sparkleshare-48.png
apps,folder-sparkleshare-48.png \
status,process-syncing-sparkleshare-i-24.png \
status,process-syncing-sparkleshare-ii-24.png \
status,process-syncing-sparkleshare-iii-24.png \
status,process-syncing-sparkleshare-iiii-24.png \
status,process-syncing-sparkleshare-iiiii-24.png
app_theme_icons = \
animations,process-syncing-sparkleshare-24.png \
@ -25,10 +30,10 @@ app_theme_icons = \
status,avatar-default-24.png \
status,avatar-default-32.png \
status,avatar-default-48.png \
status,document-added-16.png \
status,document-edited-16.png \
status,document-moved-16.png \
status,document-removed-16.png \
status,document-added-12.png \
status,document-edited-12.png \
status,document-deleted-12.png \
status,document-moved-12.png \
status,dialog-error-16.png \
status,dialog-error-24.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 487 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 610 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 589 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 994 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,002 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 990 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 989 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 993 B

View file

@ -69,15 +69,15 @@ msgstr "Über SparkleShare"
#: ../SparkleShare/SparkleAbout.cs:54
msgid "A newer version is available"
msgstr ""
msgstr "Eine neuere Version ist verfügbar"
#: ../SparkleShare/SparkleAbout.cs:61
msgid "You are running the latest version."
msgstr ""
msgstr "Sie verwenden die aktuelle Version."
#: ../SparkleShare/SparkleAbout.cs:88
msgid "Checking for updates..."
msgstr ""
msgstr "Suche Aktualisierungen..."
#: ../SparkleShare/SparkleAbout.cs:117
msgid "_Show Credits"
@ -103,7 +103,7 @@ msgstr "{0} hinzugefügt"
#: ../SparkleShare/SparkleController.cs:613
#, csharp-format
msgid "moved {0}"
msgstr ""
msgstr "{0} verschoben"
#: ../SparkleShare/SparkleController.cs:618
#, csharp-format
@ -132,7 +132,7 @@ msgid ""
"bits of information from you."
msgstr ""
"Bevor wir einen SparkleShare-Ordner auf diesem Computer einrichten können, "
"benötigen wir ein paar Informationen von Ihnen."
"benötigen wir einige Informationen von Ihnen."
#: ../SparkleShare/SparkleIntro.cs:81
msgid "Full Name:"
@ -178,7 +178,7 @@ msgstr "Das GNOME Project"
#: ../SparkleShare/SparkleIntro.cs:195
msgid "GNOME is an easy to understand interface to your computer."
msgstr "GNOME ist ein einfach verständliches Interface zu Ihrem Computer"
msgstr "GNOME ist ein einfach verständliches Interface für Ihrem Computer"
#: ../SparkleShare/SparkleIntro.cs:196
msgid "Select this option if youre a developer or designer working on GNOME."
@ -356,7 +356,7 @@ msgstr "Diesen Hilfetext anzeigen"
#: ../SparkleShare/SparkleShare.cs:114
msgid "SparkleShare, a collaboration and sharing tool."
msgstr ""
msgstr "SparkleShare, ein Werkzeug für verteilte Zusammenarbeit."
#: ../SparkleShare/SparkleShare.cs:115
msgid "Copyright (C) 2010 Hylke Bons"
@ -434,6 +434,6 @@ msgstr ""
#: ../SparkleShare/SparkleWindow.cs:41
msgid "SparkleShare Setup"
msgstr ""
msgstr "SparkleShare Konfiguration"