Merge branch 'master' of ssh://github.com/hbons/SparkleShare

This commit is contained in:
Hylke Bons 2012-10-19 23:42:43 +01:00
commit a679e29d4c
18 changed files with 456 additions and 91 deletions

View file

@ -1,4 +1,15 @@
0.9.3 for Linux, Mac and Windows (??? 2012)
0.9.4 for Linux, Mac and Windows (Fri Oct 19 2012)
Hylke:
- Remove Nautilus extension
- Restore previous revisions of files from the event log
- Fix Mac file system watcher not always triggering
- Add symbolic icon for GNOME 3 (by Lapo)
- New Bitbucket and default user icon
- For encrypted projects, use a different salt for each project
0.9.3 for Linux, Mac and Windows (Mon Oct 1 2012)
Hylke:
- Fix endless loop when adding empty folders

View file

@ -19,7 +19,7 @@ using System;
using System.Reflection;
[assembly:AssemblyTitle ("SparkleLib")]
[assembly:AssemblyVersion ("0.9.3")]
[assembly:AssemblyVersion ("0.9.4")]
[assembly:AssemblyCopyright ("Copyright (c) 2010 Hylke Bons and others")]
[assembly:AssemblyTrademark ("SparkleShare is a trademark of SparkleShare Ltd.")]

View file

@ -40,6 +40,8 @@ namespace SparkleLib.Git {
// Check if the repo's salt is stored in a branch...
SparkleGit git = new SparkleGit (TargetFolder, "branch -a");
git.StartAndWaitForExit ();
string [] branches = git.StartAndReadStandardOutput ().Split (Environment.NewLine.ToCharArray ());
// TODO double check env.newline ^

View file

@ -20,6 +20,7 @@ using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using SparkleLib;
@ -29,6 +30,7 @@ namespace SparkleLib.Git {
private bool user_is_set;
private bool use_git_bin;
private bool is_encrypted;
public SparkleRepo (string path, SparkleConfig config) : base (path, config)
@ -50,6 +52,11 @@ namespace SparkleLib.Git {
git = new SparkleGit (LocalPath, "rebase --abort");
git.StartAndWaitForExit ();
}
string password_file_path = Path.Combine (LocalPath, ".git", "password");
if (File.Exists (password_file_path))
this.is_encrypted = true;
}
@ -238,9 +245,8 @@ namespace SparkleLib.Git {
if (line.Contains ("|")) {
speed = line.Substring (line.IndexOf ("|") + 1).Trim ();
speed = speed.Replace (", done.", "").Trim ();
speed = speed.Replace ("i", "");
speed = speed.Replace ("KB/s", "ᴋʙ/s");
speed = speed.Replace ("MB/s", "ᴍʙ/s");
speed = speed.Replace ("KiB/s", "ᴋʙ/s");
speed = speed.Replace ("MiB/s", "ᴍʙ/s");
}
}
@ -468,6 +474,7 @@ namespace SparkleLib.Git {
foreach (string line in lines) {
string conflicting_path = line.Substring (3);
conflicting_path = EnsureSpecialCharacters (conflicting_path);
conflicting_path = conflicting_path.Replace ("\"", "\\\"");
SparkleLogger.LogInfo ("Git", Name + " | Conflict type: " + line);
@ -539,7 +546,7 @@ namespace SparkleLib.Git {
}
public override void RevertFile (string path, string revision)
public override void RestoreFile (string path, string revision, string target_file_path)
{
if (path == null)
throw new ArgumentNullException ("path");
@ -547,27 +554,58 @@ namespace SparkleLib.Git {
if (revision == null)
throw new ArgumentNullException ("revision");
path = path.Replace ("\\", "/");
SparkleLogger.LogInfo ("Git", Name + " | Restoring \"" + path + "\" (revision " + revision + ")");
SparkleGit git = new SparkleGit (LocalPath, "checkout " + revision + " \"" + path + "\"");
git.StartAndWaitForExit ();
// FIXME: git-show doesn't decrypt objects, so we can't use it to retrieve
// files from the index. This is a suboptimal workaround but it does the job
if (this.is_encrypted) {
// Restore the older file...
SparkleGit git = new SparkleGit (LocalPath, "checkout " + revision + " \"" + path + "\"");
git.StartAndWaitForExit ();
if (git.ExitCode == 0)
SparkleLogger.LogInfo ("Git", Name + " | Checked out \"" + path + "\" (" + revision + ")");
else
SparkleLogger.LogInfo ("Git", Name + " | Failed to check out \"" + path + "\" (" + revision + ")");
string local_file_path = Path.Combine (LocalPath, path);
// ...move it...
try {
File.Move (local_file_path, target_file_path);
} catch {
SparkleLogger.LogInfo ("Git",
Name + " | Could not move \"" + local_file_path + "\" to \"" + target_file_path + "\"");
}
// ...and restore the most recent revision
git = new SparkleGit (LocalPath, "checkout " + CurrentRevision + " \"" + path + "\"");
git.StartAndWaitForExit ();
// The correct way
} else {
path = path.Replace ("\"", "\\\"");
SparkleGit git = new SparkleGit (LocalPath, "show " + revision + ":\"" + path + "\"");
git.Start ();
FileStream stream = File.OpenWrite (target_file_path);
git.StandardOutput.BaseStream.CopyTo (stream);
stream.Close ();
git.WaitForExit ();
}
if (target_file_path.StartsWith (LocalPath))
new Thread (() => OnFileActivity (null)).Start ();
}
public override List<SparkleChangeSet> GetChangeSets (string path, int count)
public override List<SparkleChangeSet> GetChangeSets (string path)
{
return GetChangeSetsInternal (path, count);
return GetChangeSetsInternal (path);
}
public override List<SparkleChangeSet> GetChangeSets (int count)
public override List<SparkleChangeSet> GetChangeSets ()
{
return GetChangeSetsInternal (null, count);
return GetChangeSetsInternal (null);
}
@ -590,31 +628,27 @@ namespace SparkleLib.Git {
if (Error != ErrorStatus.None) {
SparkleLogger.LogInfo ("Git", Name + " | Error status changed to " + Error);
return true;
} else {
return false;
}
}
private List<SparkleChangeSet> GetChangeSetsInternal (string path, int count)
private List<SparkleChangeSet> GetChangeSetsInternal (string path)
{
if (count < 1)
throw new ArgumentOutOfRangeException ("count");
count = 150;
List <SparkleChangeSet> change_sets = new List <SparkleChangeSet> ();
SparkleGit git;
if (path == null) {
git = new SparkleGit (LocalPath, "log -" + count + " --raw --find-renames --date=iso " +
git = new SparkleGit (LocalPath, "log --since=1.month --raw --find-renames --date=iso " +
"--format=medium --no-color --no-merges");
} else {
path = path.Replace ("\\", "/");
git = new SparkleGit (LocalPath, "log -" + count + " --raw --find-renames --date=iso " +
"--format=medium --no-color --no-merges -- " + path);
git = new SparkleGit (LocalPath, "log --raw --find-renames --date=iso " +
"--format=medium --no-color --no-merges -- \"" + path + "\"");
}
string output = git.StartAndReadStandardOutput ();
@ -681,13 +715,16 @@ namespace SparkleLib.Git {
if (entry_line.StartsWith (":")) {
string type_letter = entry_line [37].ToString ();
string file_path = entry_line.Substring (39);
if (file_path.EndsWith (".empty"))
file_path = file_path.Substring (0, file_path.Length - ".empty".Length);
bool change_is_folder = false;
if (file_path.Equals (".sparkleshare"))
continue;
if (file_path.EndsWith (".empty")) {
file_path = file_path.Substring (0, file_path.Length - ".empty".Length);
change_is_folder = true;
}
file_path = EnsureSpecialCharacters (file_path);
file_path = file_path.Replace ("\\\"", "\"");
@ -702,15 +739,20 @@ namespace SparkleLib.Git {
file_path = file_path.Replace ("\\\"", "\"");
to_file_path = to_file_path.Replace ("\\\"", "\"");
if (file_path.EndsWith (".empty"))
if (file_path.EndsWith (".empty")) {
file_path = file_path.Substring (0, file_path.Length - 6);
change_is_folder = true;
}
if (to_file_path.EndsWith (".empty"))
if (to_file_path.EndsWith (".empty")) {
to_file_path = to_file_path.Substring (0, to_file_path.Length - 6);
change_is_folder = true;
}
change_set.Changes.Add (
new SparkleChange () {
Path = file_path,
IsFolder = change_is_folder,
MovedToPath = to_file_path,
Timestamp = change_set.Timestamp,
Type = SparkleChangeType.Moved
@ -730,6 +772,7 @@ namespace SparkleLib.Git {
change_set.Changes.Add (
new SparkleChange () {
Path = file_path,
IsFolder = change_is_folder,
Timestamp = change_set.Timestamp,
Type = change_type
}

View file

@ -184,6 +184,7 @@ namespace SparkleLib {
if (File.Exists (identifier_path)) {
Identifier = File.ReadAllText (identifier_path).Trim ();
File.SetAttributes (identifier_path, FileAttributes.Hidden);
} else {
Identifier = CreateIdentifier ();
@ -220,9 +221,8 @@ namespace SparkleLib {
"Any files you add or change in this folder will be automatically synced to " + n +
uri_builder.ToString () + " and everyone connected to it." + n +
n +
"SparkleShare is an Open Source software program that helps people " + n +
"collaborate and share files. If you like what we do, please consider a small " + n +
"donation to support the project: http://www.sparkleshare.org/" + n +
"SparkleShare is an Open Source software program that helps people collaborate and " + n +
"share files. If you like what we do, consider buying us a beer: http://www.sparkleshare.org/" + n +
n +
"Have fun! :)" + n;
}

View file

@ -54,9 +54,9 @@ namespace SparkleLib {
public abstract bool HasRemoteChanges { get; }
public abstract bool SyncUp ();
public abstract bool SyncDown ();
public abstract List<SparkleChangeSet> GetChangeSets (int count);
public abstract List<SparkleChangeSet> GetChangeSets (string path, int count);
public abstract void RevertFile (string path, string revision);
public abstract List<SparkleChangeSet> GetChangeSets ();
public abstract List<SparkleChangeSet> GetChangeSets (string path);
public abstract void RestoreFile (string path, string revision, string target_file_path);
public event SyncStatusChangedEventHandler SyncStatusChanged = delegate { };
public delegate void SyncStatusChangedEventHandler (SyncStatus new_status);
@ -195,19 +195,17 @@ namespace SparkleLib {
// Sync up everything that changed
// since we've been offline
if (!this.is_syncing && (HasLocalChanges || HasUnsyncedChanges)) {
SyncUpBase ();
while (HasLocalChanges)
new Thread (() => {
if (!this.is_syncing && (HasLocalChanges || HasUnsyncedChanges)) {
SyncUpBase ();
}
this.remote_timer.Start ();
}
while (HasLocalChanges && !this.is_syncing)
SyncUpBase ();
}
public List<SparkleChangeSet> GetChangeSets () {
return GetChangeSets (30);
this.remote_timer.Start ();
}).Start ();
}
@ -218,9 +216,11 @@ namespace SparkleLib {
if (IsBuffering)
return;
foreach (string exclude_path in ExcludePaths) {
if (args.FullPath.Contains (exclude_path))
return;
if (args != null) {
foreach (string exclude_path in ExcludePaths) {
if (args.FullPath.Contains (exclude_path))
return;
}
}
lock (this.buffer_lock) {

View file

@ -47,6 +47,7 @@ namespace SparkleLib {
public SparkleChangeType Type;
public DateTime Timestamp;
public bool IsFolder = false;
public string Path;
public string MovedToPath;

View file

@ -10,8 +10,9 @@
$('dl dd:nth-child(-n+10)').css('display', 'block');
$('.day-entry-content .event-entry:last-child').css('border', 'none');
$('dd a.windows').click(function () {
$('a').click(function (event) {
window.external.LinkClicked($(this).attr("href"));
event.preventDefault();
});
// Update the Today and Yesterday labels after midnight
@ -26,7 +27,7 @@
}
}, 60 * 1000);
// Hide the 'Show all' link when there are less than 10 events
// Hide the 'Show all' link when there are fewer than 10 events
$('.show').each (function () {
var entry_count = $(this).parent ().find ('dl').children ().length;
@ -67,7 +68,6 @@
a.show {
font-size: 80%;
margin-bottom: 9px;
}
a:hover {
@ -76,7 +76,7 @@
cursor: pointer;
}
small {
small, small a, small a:hover {
font-size: <!-- $small-font-size -->;
color: <!-- $secondary-font-color -->;
}
@ -91,13 +91,12 @@
display: none;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 90%;
padding: 0 0 1px 20px;
margin: 0 0 4px 0;
background-repeat: no-repeat;
background-position: center left;
text-overflow: ellipsis;
white-space: nowrap;
}
.day-entry-header {
@ -107,13 +106,24 @@
font-weight: bold;
}
.history-header {
color: #aaa;
padding-top: 22px;
float: left;
width: 90%;
margin-left: 32px;
margin-right: 32px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.event-entry {
padding: 24px 14px 14px 64px;
margin: 0 32px 0 32px;
border-bottom: 1px #ddd solid;
background-repeat: no-repeat;
background-position: 36px 24px;
min-height: 100px;
}
.event-user-name {
@ -152,7 +162,54 @@
.moved {
background-image: url('<!-- $document-moved-background-image -->');
}
}
table {
width: 100%;
}
.table-wrapper {
padding: 64px 32px;
}
td {
padding: 0;
margin: 0;
}
td.name {
font-weight: bold;
width: 45%;
}
td.time {
color: <!-- $secondary-font-color -->;
padding-right: 9px;
font-size: <!-- $small-font-size -->;
}
td.date {
color: <!-- $secondary-font-color -->;
text-align: right;
padding-right: 6px;
font-size: <!-- $small-font-size -->;
}
td.restore {
text-align: right;
font-size: <!-- $small-font-size -->;
}
td.avatar {
width: 32px;
}
td.avatar img {
margin-top: 2px;
border-radius: 3px;
width: 24px;
height: 24px;
}
</style>
</head>
<body oncontextmenu="return false;">

View file

@ -131,12 +131,35 @@ namespace SparkleShare {
Present ();
});
};
Controller.ShowSaveDialogEvent += delegate (string file_name, string target_folder_path) {
Application.Invoke (delegate {
FileChooserDialog dialog = new FileChooserDialog ("Restore from History",
this, FileChooserAction.Save, "Cancel", ResponseType.Cancel, "Save", ResponseType.Ok);
dialog.CurrentName = file_name;
dialog.SetCurrentFolder (target_folder_path);
if (dialog.Run () == (int) ResponseType.Ok)
Controller.SaveDialogCompleted (dialog.Filename);
else
Controller.SaveDialogCancelled ();
dialog.Destroy ();
});
};
Controller.UpdateChooserEvent += delegate (string [] folders) {
Application.Invoke (delegate {
UpdateChooser (folders);
});
};
Controller.UpdateChooserEnablementEvent += delegate (bool enabled) {
Application.Invoke (delegate {
this.combo_box.Sensitive = enabled;
});
};
Controller.UpdateContentEvent += delegate (string html) {
Application.Invoke (delegate {
@ -168,7 +191,7 @@ namespace SparkleShare {
private void WebViewNavigationRequested (object o, WebKit.NavigationRequestedArgs args) {
Controller.LinkClicked (args.Request.Uri.Substring (7));
Controller.LinkClicked (args.Request.Uri);
// Don't follow HREFs (as this would cause a page refresh)
if (!args.Request.Uri.Equals ("file:"))
@ -260,7 +283,8 @@ namespace SparkleShare {
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 ("<!-- $small-font-size -->", "85%");
html = html.Replace ("<!-- $pixmaps-path -->", pixmaps_path);
html = html.Replace ("<!-- $document-added-background-image -->",

View file

@ -83,5 +83,5 @@ SparkleShare/Windows/SparkleShare.wxs
### Uninstalling
Simple remove the SparkleShare bundle.
Simply remove the SparkleShare bundle.

View file

@ -80,6 +80,7 @@ namespace SparkleShare {
new SizeF (ContentView.Frame.Width, ContentView.Frame.Height - 39))
};
this.hidden_close_button = new NSButton () {
KeyEquivalentModifierMask = NSEventModifierMask.CommandKeyMask,
KeyEquivalent = "w"
@ -197,7 +198,7 @@ namespace SparkleShare {
});
}
};
Controller.UpdateChooserEvent += delegate (string [] folders) {
using (var a = new NSAutoreleasePool ())
{
@ -207,6 +208,15 @@ namespace SparkleShare {
}
};
Controller.UpdateChooserEnablementEvent += delegate (bool enabled) {
using (var a = new NSAutoreleasePool ())
{
InvokeOnMainThread (delegate {
this.popup_button.Enabled = enabled;
});
}
};
Controller.UpdateContentEvent += delegate (string html) {
using (var a = new NSAutoreleasePool ())
{
@ -228,7 +238,7 @@ namespace SparkleShare {
});
}
};
Controller.UpdateSizeInfoEvent += delegate (string size, string history_size) {
using (var a = new NSAutoreleasePool ())
{
@ -238,6 +248,30 @@ namespace SparkleShare {
});
}
};
Controller.ShowSaveDialogEvent += delegate (string file_name, string target_folder_path) {
using (var a = new NSAutoreleasePool ())
{
InvokeOnMainThread (() => {
// TODO: Make this a sheet
NSSavePanel panel = new NSSavePanel () {
DirectoryUrl = new NSUrl (target_folder_path, true),
NameFieldStringValue = file_name,
ParentWindow = this,
Title = "Restore from History",
PreventsApplicationTerminationWhenModal = false
};
if ((NSPanelButtonType) panel.RunModal ()== NSPanelButtonType.Ok) {
string target_file_path = Path.Combine (panel.DirectoryUrl.RelativePath, panel.NameFieldStringValue);
Controller.SaveDialogCompleted (target_file_path);
} else {
Controller.SaveDialogCancelled ();
}
});
}
};
}
@ -346,6 +380,7 @@ namespace SparkleShare {
html = html.Replace ("<!-- $body-font-size -->", "13.4px");
html = html.Replace ("<!-- $secondary-font-color -->", "#bbb");
html = html.Replace ("<!-- $small-color -->", "#ddd");
html = html.Replace ("<!-- $small-font-size -->", "10px");
html = html.Replace ("<!-- $day-entry-header-background-color -->", "#f5f5f5");
html = html.Replace ("<!-- $a-color -->", "#0085cf");
html = html.Replace ("<!-- $a-hover-color -->", "#009ff8");
@ -372,7 +407,7 @@ namespace SparkleShare {
this.web_view.MainFrame.LoadHtmlString (html, new NSUrl (""));
web_view.PolicyDelegate = new SparkleWebPolicyDelegate ();
this.web_view.PolicyDelegate = new SparkleWebPolicyDelegate ();
ContentView.AddSubview (this.web_view);
(this.web_view.PolicyDelegate as SparkleWebPolicyDelegate).LinkClicked +=

View file

@ -76,13 +76,13 @@ namespace SparkleShare {
this.syncing_idle_image = new NSImage (Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "process-syncing-idle.png"));
this.syncing_up_image = new NSImage (Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "process-syncing-up.png"));
this.syncing_down_image = new NSImage (Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "process-syncing-down.png"));
this.syncing_image = new NSImage (Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "process-syncing.png"));
this.syncing_image = new NSImage (Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "process-syncing.png"));
this.syncing_error_image = new NSImage (Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "process-syncing-error.png"));
this.syncing_idle_image_active = new NSImage (Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "process-syncing-idle-active.png"));
this.syncing_up_image_active = new NSImage (Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "process-syncing-up-active.png"));
this.syncing_down_image_active = new NSImage (Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "process-syncing-down-active.png"));
this.syncing_image_active = new NSImage (Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "process-syncing-active.png"));
this.syncing_image_active = new NSImage (Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "process-syncing-active.png"));
this.syncing_error_image_active = new NSImage (Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "process-syncing-error-active.png"));
this.status_item.Image = this.syncing_idle_image;

View file

@ -260,6 +260,7 @@ namespace SparkleShare {
CheckRepositories ();
RepositoriesLoaded = true;
FolderListChanged ();
UpdateState ();
}).Start ();
}

View file

@ -19,6 +19,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading;
using SparkleLib;
@ -33,15 +34,23 @@ namespace SparkleShare {
public event UpdateContentEventEventHandler UpdateContentEvent = delegate { };
public delegate void UpdateContentEventEventHandler (string html);
public event UpdateChooserEventHandler UpdateChooserEvent = delegate { };
public delegate void UpdateChooserEventHandler (string [] folders);
public event UpdateChooserEnablementEventHandler UpdateChooserEnablementEvent = delegate { };
public delegate void UpdateChooserEnablementEventHandler (bool enabled);
public event UpdateSizeInfoEventHandler UpdateSizeInfoEvent = delegate { };
public delegate void UpdateSizeInfoEventHandler (string size, string history_size);
public event ShowSaveDialogEventHandler ShowSaveDialogEvent = delegate { };
public delegate void ShowSaveDialogEventHandler (string file_name, string target_folder_path);
private string selected_folder;
private RevisionInfo restore_revision_info;
private bool history_view_active;
public bool WindowIsOpen { get; private set; }
@ -57,10 +66,10 @@ namespace SparkleShare {
ContentLoadingEvent ();
UpdateSizeInfoEvent ("…", "…");
Stopwatch watch = new Stopwatch ();
watch.Start ();
new Thread (() => {
Stopwatch watch = new Stopwatch ();
watch.Start ();
string html = HTML;
watch.Stop ();
@ -161,6 +170,7 @@ namespace SparkleShare {
Thread.Sleep (delay - (int) watch.ElapsedMilliseconds);
UpdateChooserEvent (Folders);
UpdateChooserEnablementEvent (true);
UpdateContentEvent (html);
UpdateSizeInfoEvent (Size, HistorySize);
@ -173,6 +183,9 @@ namespace SparkleShare {
};
Program.Controller.OnIdle += delegate {
if (this.history_view_active)
return;
ContentLoadingEvent ();
UpdateSizeInfoEvent ("…", "…");
@ -212,15 +225,98 @@ namespace SparkleShare {
public void LinkClicked (string url)
{
url = url.Replace ("%20", " ");
if (url.StartsWith (Path.VolumeSeparatorChar.ToString ()) ||
url.Substring (1, 1).Equals (":")) {
Program.Controller.OpenFile (url);
} else if (url.StartsWith ("http")) {
if (url.StartsWith ("http")) {
Program.Controller.OpenWebsite (url);
} else if (url.StartsWith ("restore://") && this.restore_revision_info == null) {
Regex regex = new Regex ("restore://(.+)/([a-f0-9]+)/(.+)/(.{3} [0-9]+ [0-9]+h[0-9]+)/(.+)", RegexOptions.Compiled);
Match match = regex.Match (url);
if (match.Success) {
string author_name = match.Groups [3].Value;
string timestamp = match.Groups [4].Value;
this.restore_revision_info = new RevisionInfo () {
Folder = new SparkleFolder (match.Groups [1].Value),
Revision = match.Groups [2].Value,
FilePath = match.Groups [5].Value
};
string file_name = Path.GetFileNameWithoutExtension (this.restore_revision_info.FilePath) +
" (" + author_name + " " + timestamp + ")" + Path.GetExtension (this.restore_revision_info.FilePath);
string target_folder_path = Path.Combine (this.restore_revision_info.Folder.FullPath,
Path.GetDirectoryName (this.restore_revision_info.FilePath));
ShowSaveDialogEvent (file_name, target_folder_path);
}
} else if (url.StartsWith ("back://")) {
this.history_view_active = false;
SelectedFolder = this.selected_folder; // TODO: Return to the same position on the page
UpdateChooserEnablementEvent (true);
} else if (url.StartsWith ("history://")) {
this.history_view_active = true;
ContentLoadingEvent ();
UpdateSizeInfoEvent ("…", "…");
UpdateChooserEnablementEvent (false);
string folder = url.Replace ("history://", "").Split ("/".ToCharArray ()) [0];
string file_path = url.Replace ("history://" + folder + "/", "");
foreach (SparkleRepoBase repo in Program.Controller.Repositories) {
if (!repo.Name.Equals (folder))
continue;
new Thread (() => {
Stopwatch watch = new Stopwatch ();
watch.Start ();
List<SparkleChangeSet> change_sets = repo.GetChangeSets (file_path);
string html = GetHistoryHTMLLog (change_sets, file_path);
watch.Stop ();
int delay = 500;
if (watch.ElapsedMilliseconds < delay)
Thread.Sleep (delay - (int) watch.ElapsedMilliseconds);
UpdateContentEvent (html);
}).Start ();
break;
}
} else {
Program.Controller.OpenFile (url);
}
}
public void SaveDialogCompleted (string target_file_path)
{
foreach (SparkleRepoBase repo in Program.Controller.Repositories) {
if (repo.Name.Equals (this.restore_revision_info.Folder.Name)) {
repo.RestoreFile (this.restore_revision_info.FilePath,
this.restore_revision_info.Revision, target_file_path);
break;
}
}
this.restore_revision_info = null;
Program.Controller.OpenFolder (Path.GetDirectoryName (target_file_path));
}
public void SaveDialogCancelled ()
{
this.restore_revision_info = null;
}
@ -261,6 +357,56 @@ namespace SparkleShare {
}
public string GetHistoryHTMLLog (List<SparkleChangeSet> change_sets, string file_path)
{
string html = "<div class='history-header'>" +
"<a class='windows' href='back://'>&laquo; Back</a> &nbsp;|&nbsp; ";
if (change_sets.Count > 1)
html += "Revisions for <b>&ldquo;";
else
html += "No revisions for <b>&ldquo;";
html += Path.GetFileName (file_path) + "&rdquo;</b>";
html += "</div><div class='table-wrapper'><table>";
int count = 0;
foreach (SparkleChangeSet change_set in change_sets) {
count++;
if (count == 1)
continue;
string change_set_avatar = Program.Controller.GetAvatar (change_set.User.Email, 24);
if (change_set_avatar != null)
change_set_avatar = "file://" + change_set_avatar.Replace ("\\", "/");
else
change_set_avatar = "file://<!-- $pixmaps-path -->/user-icon-default.png";
html += "<tr>" +
"<td class='avatar'><img src='" + change_set_avatar + "'></td>" +
"<td class='name'>" + change_set.User.Name + "</td>" +
"<td class='date'>" + change_set.Timestamp.ToString ("d MMM yyyy") + "</td>" +
"<td class='time'>" + change_set.Timestamp.ToString ("HH:mm") + "</td>" +
"<td class='restore'>" +
"<a href='restore://" + change_set.Folder.Name + "/" +
change_set.Revision + "/" + change_set.User.Name + "/" +
change_set.Timestamp.ToString ("MMM d H\\hmm") + "/" +
file_path + "'>Restore&hellip;</a>" +
"</td>" +
"</tr>";
count++;
}
html += "</table></div>";
html = Program.Controller.EventLogHTML.Replace ("<!-- $event-log-content -->", html);
return html.Replace ("<!-- $midnight -->", "100000000");
}
public string GetHTMLLog (List<SparkleChangeSet> change_sets)
{
if (change_sets.Count == 0)
@ -307,12 +453,22 @@ namespace SparkleShare {
foreach (SparkleChange change in change_set.Changes) {
if (change.Type != SparkleChangeType.Moved) {
event_entry += "<dd class='" + change.Type.ToString ().ToLower () + "'>";
event_entry += "<small>" + change.Timestamp.ToString ("HH:mm") +"</small> &nbsp;";
if (!change.IsFolder) {
event_entry += "<small><a href=\"history://" + change_set.Folder.Name + "/" +
change.Path + "\" title=\"View revisions\">" + change.Timestamp.ToString ("HH:mm") +
"</a></small> &nbsp;";
} else {
event_entry += "<small>" + change.Timestamp.ToString ("HH:mm") + "</small> &nbsp;";
}
event_entry += FormatBreadCrumbs (change_set.Folder.FullPath, change.Path);
event_entry += "</dd>";
} else {
event_entry += "<dd class='moved'>";
event_entry += "<small>" + change.Timestamp.ToString ("HH:mm") +"</small> &nbsp;";
event_entry += FormatBreadCrumbs (change_set.Folder.FullPath, change.Path);
event_entry += "<br>";
event_entry += "<small>" + change.Timestamp.ToString ("HH:mm") +"</small> &nbsp;";
@ -444,5 +600,12 @@ namespace SparkleShare {
Date = new DateTime (date_time.Year, date_time.Month, date_time.Day);
}
}
private class RevisionInfo {
public SparkleFolder Folder;
public string FilePath;
public string Revision;
}
}
}

View file

@ -120,7 +120,7 @@ namespace SparkleShare {
SparkleLink website_link = new SparkleLink ("Website", Controller.WebsiteLinkAddress);
SparkleLink credits_link = new SparkleLink ("Credits", Controller.CreditsLinkAddress);
SparkleLink report_problem_link = new SparkleLink ("Report a problem", Controller.ReportProblemLinkAddress);
SparkleLink debug_log_link = new SparkleLink ("Debig log", Controller.DebugLogLinkAddress);
SparkleLink debug_log_link = new SparkleLink ("Debug log", Controller.DebugLogLinkAddress);
Canvas canvas = new Canvas ();
@ -154,7 +154,7 @@ namespace SparkleShare {
canvas.Children.Add (debug_log_link);
Canvas.SetLeft (debug_log_link, 289 + website_link.ActualWidth + credits_link.ActualWidth +
report_problem_link.ActualWidth + 180);
report_problem_link.ActualWidth + 220);
Canvas.SetTop (debug_log_link, 222);
Content = canvas;

View file

@ -14,7 +14,6 @@
// 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.ComponentModel;
using System.IO;
@ -26,6 +25,7 @@ using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Microsoft.Win32;
using Shapes = System.Windows.Shapes;
namespace SparkleShare {
@ -50,7 +50,7 @@ namespace SparkleShare {
ResizeMode = ResizeMode.NoResize; // TODO
Background = new SolidColorBrush (Color.FromRgb (240, 240, 240));
AllowsTransparency = false;
Icon = SparkleUIHelpers.GetImageSource("sparkleshare-app", "ico");
Icon = SparkleUIHelpers.GetImageSource ("sparkleshare-app", "ico");
int x = (int) (SystemParameters.PrimaryScreenWidth * 0.61);
int y = (int) (SystemParameters.PrimaryScreenHeight * 0.5 - (Height * 0.5));
@ -104,6 +104,7 @@ namespace SparkleShare {
this.web_browser.ObjectForScripting = new SparkleScriptingObject ();
spinner = new SparkleSpinner (22);
// Disable annoying IE clicking sound
@ -177,6 +178,12 @@ namespace SparkleShare {
});
};
Controller.UpdateChooserEnablementEvent += delegate (bool enabled) {
Dispatcher.BeginInvoke ((Action) delegate {
this.combo_box.IsEnabled = enabled;
});
};
Controller.UpdateContentEvent += delegate (string html) {
Dispatcher.BeginInvoke ((Action) delegate {
UpdateContent (html);
@ -191,6 +198,25 @@ namespace SparkleShare {
this.canvas.Children.Remove (this.web_browser);
});
};
Controller.ShowSaveDialogEvent += delegate (string file_name, string target_folder_path) {
Dispatcher.BeginInvoke ((Action) delegate {
SaveFileDialog dialog = new SaveFileDialog () {
FileName = file_name,
InitialDirectory = target_folder_path,
Title = "Restore from History",
DefaultExt = "." + Path.GetExtension (file_name),
Filter = "All Files|*.*"
};
Nullable<bool> result = dialog.ShowDialog (this);
if (result == true)
Controller.SaveDialogCompleted (dialog.FileName);
else
Controller.SaveDialogCancelled ();
});
};
}
@ -262,6 +288,7 @@ namespace SparkleShare {
html = html.Replace ("<!-- $body-font-size -->", "12px");
html = html.Replace ("<!-- $secondary-font-color -->", "#bbb");
html = html.Replace ("<!-- $small-color -->", "#ddd");
html = html.Replace ("<!-- $small-font-size -->", "90%");
html = html.Replace ("<!-- $day-entry-header-background-color -->", "#f5f5f5");
html = html.Replace ("<!-- $a-color -->", "#0085cf");
html = html.Replace ("<!-- $a-hover-color -->", "#009ff8");
@ -282,9 +309,10 @@ namespace SparkleShare {
Dispatcher.BeginInvoke ((Action) delegate {
this.spinner.Stop ();
this.web_browser.NavigateToString (html);
this.web_browser.ObjectForScripting = new SparkleScriptingObject ();
this.web_browser.NavigateToString (html);
if (!this.canvas.Children.Contains (this.web_browser)) {
this.canvas.Children.Add (this.web_browser);
Canvas.SetLeft (this.web_browser, 0);
@ -322,8 +350,8 @@ namespace SparkleShare {
string [] actions = new string [] {"added", "deleted", "edited", "moved"};
foreach (string action in actions) {
BitmapSource image = SparkleUIHelpers.GetImageSource ("document-" + action + "-12");
string file_path = Path.Combine (pixmaps_path, "document-" + action + "-12.png");
image = SparkleUIHelpers.GetImageSource ("document-" + action + "-12");
file_path = Path.Combine (pixmaps_path, "document-" + action + "-12.png");
using (FileStream stream = new FileStream (file_path, FileMode.Create))
{
@ -345,8 +373,8 @@ namespace SparkleShare {
[DllImport ("urlmon.dll")]
[PreserveSig]
[return:MarshalAs (UnmanagedType.Error)]
static extern int CoInternetSetFeatureEnabled (
int feature, [MarshalAs (UnmanagedType.U4)] int flags, bool enable);
static extern int CoInternetSetFeatureEnabled (int feature,
[MarshalAs (UnmanagedType.U4)] int flags, bool enable);
}

View file

@ -2,7 +2,7 @@
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi' xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Product Name='SparkleShare' Id='184950D5-67F6-4D06-9717-7E2F1607A7B0' UpgradeCode='D3DF1D99-87F5-47A7-A349-863DD6E4B73A'
Language='1033' Codepage='1252' Version='0.9.3' Manufacturer='SparkleShare'>
Language='1033' Codepage='1252' Version='0.9.4' Manufacturer='SparkleShare'>
<Package Id='*' Keywords='Installer' Description="SparkleShare Setup" Manufacturer='SparkleShare'
InstallerVersion='100' Languages='1033' Compressed='yes' SummaryCodepage='1252' />

View file

@ -1,5 +1,5 @@
dnl Process this file with autoconf to produce a configure script.
m4_define([sparkleshare_version], [0.9.3])
m4_define([sparkleshare_version], [0.9.4])
AC_PREREQ([2.54])
AC_INIT([SparkleShare], sparkleshare_version)