statusicon: On sync fail, add error descriptions as submenus. Closes #874

This commit is contained in:
Hylke Bons 2012-09-18 19:40:06 +01:00
parent 06f7a12c72
commit cb5617c300
7 changed files with 225 additions and 95 deletions

View file

@ -33,6 +33,8 @@ namespace SparkleLib.Git {
public SparkleRepo (string path, SparkleConfig config) : base (path, config) public SparkleRepo (string path, SparkleConfig config) : base (path, config)
{ {
// TODO: Set git locale to en-US
SparkleGit git = new SparkleGit (LocalPath, "config --get filter.bin.clean"); SparkleGit git = new SparkleGit (LocalPath, "config --get filter.bin.clean");
git.StartAndWaitForExit (); git.StartAndWaitForExit ();
@ -157,6 +159,7 @@ namespace SparkleLib.Git {
SparkleLogger.LogInfo ("Git", Name + " | Remote changes found, local: " + SparkleLogger.LogInfo ("Git", Name + " | Remote changes found, local: " +
current_revision + ", remote: " + remote_revision); current_revision + ", remote: " + remote_revision);
Error = ErrorStatus.None;
return true; return true;
} else { } else {
@ -212,11 +215,6 @@ namespace SparkleLib.Git {
number = (number / 100 * 20); number = (number / 100 * 20);
} else { } else {
if (line.StartsWith ("ERROR: QUOTA EXCEEDED")) {
int quota_limit = int.Parse (line.Substring (21).Trim ());
throw new QuotaExceededException ("Quota exceeded", quota_limit);
}
// "Writing objects" stage // "Writing objects" stage
number = (number / 100 * 80 + 20); number = (number / 100 * 80 + 20);
@ -231,6 +229,9 @@ namespace SparkleLib.Git {
} else { } else {
SparkleLogger.LogInfo ("Git", Name + " | " + line); SparkleLogger.LogInfo ("Git", Name + " | " + line);
if (FindError (line))
return false;
} }
if (number >= percentage) { if (number >= percentage) {
@ -247,6 +248,7 @@ namespace SparkleLib.Git {
return true; return true;
} else { } else {
Error = ErrorStatus.HostUnreachable;
return false; return false;
} }
} }
@ -293,6 +295,9 @@ namespace SparkleLib.Git {
} else { } else {
SparkleLogger.LogInfo ("Git", Name + " | " + line); SparkleLogger.LogInfo ("Git", Name + " | " + line);
if (FindError (line))
return false;
} }
@ -316,6 +321,7 @@ namespace SparkleLib.Git {
return true; return true;
} else { } else {
Error = ErrorStatus.HostUnreachable;
return false; return false;
} }
} }
@ -548,6 +554,31 @@ namespace SparkleLib.Git {
} }
private bool FindError (string line)
{
Error = ErrorStatus.None;
if (line.StartsWith ("WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!") ||
line.StartsWith ("WARNING: POSSIBLE DNS SPOOFING DETECTED!")) {
Error = ErrorStatus.HostIdentityChanged;
} else if (line.StartsWith ("Permission denied")) {
Error = ErrorStatus.AuthenticationFailed;
} else if (line.StartsWith ("error: Disk space exceeded")) {
Error = ErrorStatus.DiskSpaceExcedeed;
}
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, int count)
{ {
if (count < 1) if (count < 1)

View file

@ -32,6 +32,15 @@ namespace SparkleLib {
} }
public enum ErrorStatus {
None,
HostUnreachable,
HostIdentityChanged,
AuthenticationFailed,
DiskSpaceExcedeed
}
public abstract class SparkleRepoBase { public abstract class SparkleRepoBase {
public static bool UseCustomWatcher = false; public static bool UseCustomWatcher = false;
@ -67,7 +76,7 @@ namespace SparkleLib {
public readonly Uri RemoteUrl; public readonly Uri RemoteUrl;
public List<SparkleChangeSet> ChangeSets { get; protected set; } public List<SparkleChangeSet> ChangeSets { get; protected set; }
public SyncStatus Status { get; private set; } public SyncStatus Status { get; private set; }
public bool ServerOnline { get; private set; } public ErrorStatus Error { get; protected set; }
public bool IsBuffering { get; private set; } public bool IsBuffering { get; private set; }
public double ProgressPercentage { get; private set; } public double ProgressPercentage { get; private set; }
public string ProgressSpeed { get; private set; } public string ProgressSpeed { get; private set; }
@ -136,12 +145,13 @@ namespace SparkleLib {
public SparkleRepoBase (string path, SparkleConfig config) public SparkleRepoBase (string path, SparkleConfig config)
{ {
Status = SyncStatus.Idle;
Error = ErrorStatus.None;
this.local_config = config; this.local_config = config;
LocalPath = path; LocalPath = path;
Name = Path.GetFileName (LocalPath); Name = Path.GetFileName (LocalPath);
RemoteUrl = new Uri (this.local_config.GetUrlForFolder (Name)); RemoteUrl = new Uri (this.local_config.GetUrlForFolder (Name));
IsBuffering = false; IsBuffering = false;
ServerOnline = true;
this.identifier = Identifier; this.identifier = Identifier;
ChangeSets = GetChangeSets (); ChangeSets = GetChangeSets ();
@ -170,7 +180,7 @@ namespace SparkleLib {
// In the unlikely case that we haven't synced up our // In the unlikely case that we haven't synced up our
// changes or the server was down, sync up again // changes or the server was down, sync up again
if (HasUnsyncedChanges && !is_syncing && ServerOnline) if (HasUnsyncedChanges && !is_syncing && Error == ErrorStatus.None)
SyncUpBase (); SyncUpBase ();
}; };
} }
@ -309,14 +319,13 @@ namespace SparkleLib {
if (!UseCustomWatcher) if (!UseCustomWatcher)
this.watcher.Disable (); this.watcher.Disable ();
if (ServerOnline && SyncUp ()) { if (Error == ErrorStatus.None && SyncUp ()) {
HasUnsyncedChanges = false; HasUnsyncedChanges = false;
SyncStatusChanged (SyncStatus.Idle); SyncStatusChanged (SyncStatus.Idle);
this.listener.Announce (new SparkleAnnouncement (Identifier, CurrentRevision)); this.listener.Announce (new SparkleAnnouncement (Identifier, CurrentRevision));
} else { } else {
ServerOnline = false;
SyncStatusChanged (SyncStatus.Error); SyncStatusChanged (SyncStatus.Error);
} }
} }
@ -341,7 +350,7 @@ namespace SparkleLib {
if (SyncDown ()) { if (SyncDown ()) {
SparkleLogger.LogInfo ("SyncDown", Name + " | Done"); SparkleLogger.LogInfo ("SyncDown", Name + " | Done");
ServerOnline = true; Error = ErrorStatus.None;
ChangeSets = GetChangeSets (); ChangeSets = GetChangeSets ();
@ -373,10 +382,8 @@ namespace SparkleLib {
} else { } else {
SparkleLogger.LogInfo ("SyncDown", Name + " | Error"); SparkleLogger.LogInfo ("SyncDown", Name + " | Error");
ServerOnline = false;
ChangeSets = GetChangeSets (); ChangeSets = GetChangeSets ();
SyncStatusChanged (SyncStatus.Error); SyncStatusChanged (SyncStatus.Error);
} }

View file

@ -130,7 +130,7 @@ namespace SparkleShare {
}); });
}; };
Controller.UpdateOpenRecentEventsItemEvent += delegate (bool item_enabled) { Controller.UpdateRecentEventsItemEvent += delegate (bool item_enabled) {
Application.Invoke (delegate { Application.Invoke (delegate {
this.recent_events_item.Sensitive = item_enabled; this.recent_events_item.Sensitive = item_enabled;
this.recent_events_item.ShowAll (); this.recent_events_item.ShowAll ();
@ -167,46 +167,66 @@ namespace SparkleShare {
this.menu.Add (folder_item); this.menu.Add (folder_item);
if (Program.Controller.Folders.Count > 0) { if (Program.Controller.Folders.Count > 0) {
int i = 0;
foreach (string folder_name in Controller.Folders) { foreach (string folder_name in Controller.Folders) {
ImageMenuItem item = new SparkleMenuItem (folder_name);
Gdk.Pixbuf folder_icon; Gdk.Pixbuf folder_icon;
if (Program.Controller.UnsyncedFolders.Contains (folder_name)) { if (!string.IsNullOrEmpty (Controller.FolderErrors [i])) {
folder_icon = IconTheme.Default.LoadIcon ("dialog-error", 16, folder_icon = IconTheme.Default.LoadIcon ("dialog-warning", 16,
IconLookupFlags.GenericFallback); IconLookupFlags.GenericFallback);
item.Submenu = new Menu ();
MenuItem error_item = new MenuItem (Controller.FolderErrors [i]) {
Sensitive = false
};
item.Submenu.Add (error_item);
} else { } else {
folder_icon = IconTheme.Default.LoadIcon ("folder", 16, folder_icon = IconTheme.Default.LoadIcon ("folder", 16,
IconLookupFlags.GenericFallback); IconLookupFlags.GenericFallback);
} }
ImageMenuItem subfolder_item = new SparkleMenuItem (folder_name) { item.Image = new Image (folder_icon);
Image = new Image (folder_icon)
};
subfolder_item.Activated += OpenFolderDelegate (folder_name); item.Activated += OpenFolderDelegate (folder_name);
this.menu.Add (subfolder_item); this.menu.Add (item);
i++;
} }
Menu submenu = new Menu (); Menu submenu = new Menu ();
i = 0;
foreach (string folder_name in Controller.OverflowFolders) { foreach (string folder_name in Controller.OverflowFolders) {
ImageMenuItem item = new SparkleMenuItem (folder_name);
Gdk.Pixbuf folder_icon; Gdk.Pixbuf folder_icon;
if (Program.Controller.UnsyncedFolders.Contains (folder_name)) { if (!string.IsNullOrEmpty (Controller.OverflowFolderErrors [i])) {
folder_icon = IconTheme.Default.LoadIcon ("dialog-error", 16, folder_icon = IconTheme.Default.LoadIcon ("dialog-warning", 16,
IconLookupFlags.GenericFallback); IconLookupFlags.GenericFallback);
item.Submenu = new Menu ();
MenuItem error_item = new MenuItem (Controller.OverflowFolderErrors [i]) {
Sensitive = false
};
item.Submenu.Add (error_item);
} else { } else {
folder_icon = IconTheme.Default.LoadIcon ("folder", 16, folder_icon = IconTheme.Default.LoadIcon ("folder", 16,
IconLookupFlags.GenericFallback); IconLookupFlags.GenericFallback);
} }
ImageMenuItem subfolder_item = new SparkleMenuItem (folder_name) { item.Image = new Image (folder_icon);
Image = new Image (folder_icon)
}; item.Activated += OpenFolderDelegate (folder_name);
submenu.Add (item);
subfolder_item.Activated += OpenFolderDelegate (folder_name); i++;
submenu.Add (subfolder_item);
} }
if (submenu.Children.Length > 0) { if (submenu.Children.Length > 0) {
@ -232,10 +252,10 @@ namespace SparkleShare {
this.recent_events_item = new MenuItem ("Recent Changes…"); this.recent_events_item = new MenuItem ("Recent Changes…");
this.recent_events_item.Sensitive = Controller.OpenRecentEventsItemEnabled; this.recent_events_item.Sensitive = Controller.RecentEventsItemEnabled;
this.recent_events_item.Activated += delegate { this.recent_events_item.Activated += delegate {
Controller.OpenRecentEventsClicked (); Controller.RecentEventsClicked ();
}; };
this.menu.Add (this.recent_events_item); this.menu.Add (this.recent_events_item);

View file

@ -162,7 +162,7 @@ namespace SparkleShare {
} }
}; };
Controller.UpdateOpenRecentEventsItemEvent += delegate (bool events_item_enabled) { Controller.UpdateRecentEventsItemEvent += delegate (bool events_item_enabled) {
using (var a = new NSAutoreleasePool ()) using (var a = new NSAutoreleasePool ())
{ {
InvokeOnMainThread (delegate { InvokeOnMainThread (delegate {
@ -208,12 +208,12 @@ namespace SparkleShare {
this.recent_events_item = new NSMenuItem () { this.recent_events_item = new NSMenuItem () {
Title = "Recent Changes…", Title = "Recent Changes…",
Enabled = Controller.OpenRecentEventsItemEnabled Enabled = Controller.RecentEventsItemEnabled
}; };
if (Controller.Folders.Length > 0) { if (Controller.Folders.Length > 0) {
this.recent_events_item.Activated += delegate { this.recent_events_item.Activated += delegate {
Controller.OpenRecentEventsClicked (); Controller.RecentEventsClicked ();
}; };
} }
@ -272,10 +272,19 @@ namespace SparkleShare {
NSMenuItem item = new NSMenuItem (); NSMenuItem item = new NSMenuItem ();
item.Title = folder_name; item.Title = folder_name;
if (Program.Controller.UnsyncedFolders.Contains (folder_name)) if (!string.IsNullOrEmpty (Controller.FolderErrors [i])) {
item.Image = this.caution_image; item.Image = this.caution_image;
else item.Submenu = new NSMenu ();
NSMenuItem error_item = new NSMenuItem () {
Title = Controller.FolderErrors [i]
};
item.Submenu.AddItem (error_item);
} else {
item.Image = this.folder_image; item.Image = this.folder_image;
}
item.Image.Size = new SizeF (16, 16); item.Image.Size = new SizeF (16, 16);
this.folder_tasks [i] = OpenFolderDelegate (folder_name); this.folder_tasks [i] = OpenFolderDelegate (folder_name);
@ -291,10 +300,19 @@ namespace SparkleShare {
NSMenuItem item = new NSMenuItem (); NSMenuItem item = new NSMenuItem ();
item.Title = folder_name; item.Title = folder_name;
if (Program.Controller.UnsyncedFolders.Contains (folder_name)) if (!string.IsNullOrEmpty (Controller.OverflowFolderErrors [i])) {
item.Image = this.caution_image; item.Image = this.caution_image;
else item.Submenu = new NSMenu ();
NSMenuItem error_item = new NSMenuItem () {
Title = Controller.OverflowFolderErrors [i]
};
item.Submenu.AddItem (error_item);
} else {
item.Image = this.folder_image; item.Image = this.folder_image;
}
item.Image.Size = new SizeF (16, 16); item.Image.Size = new SizeF (16, 16);
this.overflow_tasks [i] = OpenFolderDelegate (folder_name); this.overflow_tasks [i] = OpenFolderDelegate (folder_name);

View file

@ -16,9 +16,7 @@
using System; using System;
using System.Timers; using System.Threading;
using Threading = System.Threading;
using SparkleLib; using SparkleLib;
@ -47,38 +45,21 @@ namespace SparkleShare {
public event UpdateQuitItemEventHandler UpdateQuitItemEvent = delegate { }; public event UpdateQuitItemEventHandler UpdateQuitItemEvent = delegate { };
public delegate void UpdateQuitItemEventHandler (bool quit_item_enabled); public delegate void UpdateQuitItemEventHandler (bool quit_item_enabled);
public event UpdateOpenRecentEventsItemEventHandler UpdateOpenRecentEventsItemEvent = delegate { }; public event UpdateRecentEventsItemEventHandler UpdateRecentEventsItemEvent = delegate { };
public delegate void UpdateOpenRecentEventsItemEventHandler (bool open_recent_events_item_enabled); public delegate void UpdateRecentEventsItemEventHandler (bool recent_events_item_enabled);
public IconState CurrentState = IconState.Idle; public IconState CurrentState = IconState.Idle;
public string StateText = "Welcome to SparkleShare!"; public string StateText = "Welcome to SparkleShare!";
public readonly int MenuOverflowThreshold = 9; public readonly int MenuOverflowThreshold = 9;
public readonly int MinSubmenuOverflowCount = 3; public readonly int MinSubmenuOverflowCount = 3;
public string [] Folders;
public string [] Folders { public string [] FolderErrors;
get {
int overflow_count = (Program.Controller.Folders.Count - MenuOverflowThreshold); public string [] OverflowFolders;
public string [] OverflowFolderErrors;
if (overflow_count >= MinSubmenuOverflowCount)
return Program.Controller.Folders.GetRange (0, MenuOverflowThreshold).ToArray ();
else
return Program.Controller.Folders.ToArray ();
}
}
public string [] OverflowFolders {
get {
int overflow_count = (Program.Controller.Folders.Count - MenuOverflowThreshold);
if (overflow_count >= MinSubmenuOverflowCount)
return Program.Controller.Folders.GetRange (MenuOverflowThreshold, overflow_count).ToArray ();
else
return new string [0];
}
}
public string FolderSize { public string FolderSize {
get { get {
@ -112,7 +93,7 @@ namespace SparkleShare {
} }
} }
public bool OpenRecentEventsItemEnabled { public bool RecentEventsItemEnabled {
get { get {
return (Program.Controller.RepositoriesLoaded && Program.Controller.Folders.Count > 0); return (Program.Controller.RepositoriesLoaded && Program.Controller.Folders.Count > 0);
} }
@ -121,6 +102,8 @@ namespace SparkleShare {
public SparkleStatusIconController () public SparkleStatusIconController ()
{ {
UpdateFolders ();
Program.Controller.FolderListChanged += delegate { Program.Controller.FolderListChanged += delegate {
if (CurrentState != IconState.Error) { if (CurrentState != IconState.Error) {
CurrentState = IconState.Idle; CurrentState = IconState.Idle;
@ -131,12 +114,16 @@ namespace SparkleShare {
StateText = "Files up to date " + FolderSize; StateText = "Files up to date " + FolderSize;
} }
UpdateFolders ();
UpdateStatusItemEvent (StateText); UpdateStatusItemEvent (StateText);
UpdateOpenRecentEventsItemEvent (OpenRecentEventsItemEnabled); UpdateRecentEventsItemEvent (RecentEventsItemEnabled);
UpdateMenuEvent (CurrentState); UpdateMenuEvent (CurrentState);
}; };
Program.Controller.OnIdle += delegate { Program.Controller.OnIdle += delegate {
UpdateFolders ();
if (CurrentState != IconState.Error) { if (CurrentState != IconState.Error) {
CurrentState = IconState.Idle; CurrentState = IconState.Idle;
@ -148,7 +135,6 @@ namespace SparkleShare {
UpdateQuitItemEvent (QuitItemEnabled); UpdateQuitItemEvent (QuitItemEnabled);
UpdateStatusItemEvent (StateText); UpdateStatusItemEvent (StateText);
UpdateIconEvent (CurrentState); UpdateIconEvent (CurrentState);
UpdateMenuEvent (CurrentState); UpdateMenuEvent (CurrentState);
}; };
@ -191,10 +177,12 @@ namespace SparkleShare {
CurrentState = IconState.Error; CurrentState = IconState.Error;
StateText = "Failed to send some changes"; StateText = "Failed to send some changes";
UpdateFolders ();
UpdateQuitItemEvent (QuitItemEnabled); UpdateQuitItemEvent (QuitItemEnabled);
UpdateStatusItemEvent (StateText); UpdateStatusItemEvent (StateText);
UpdateIconEvent (CurrentState); UpdateIconEvent (CurrentState);
UpdateMenuEvent (CurrentState);
}; };
} }
@ -217,9 +205,9 @@ namespace SparkleShare {
} }
public void OpenRecentEventsClicked () public void RecentEventsClicked ()
{ {
new Threading.Thread (() => Program.Controller.ShowEventLogWindow ()).Start (); new Thread (() => Program.Controller.ShowEventLogWindow ()).Start ();
} }
@ -233,5 +221,53 @@ namespace SparkleShare {
{ {
Program.Controller.Quit (); Program.Controller.Quit ();
} }
private void UpdateFolders ()
{
int overflow_count = (Program.Controller.Folders.Count - MenuOverflowThreshold);
if (overflow_count >= MinSubmenuOverflowCount) {
Folders = Program.Controller.Folders.GetRange (0, MenuOverflowThreshold).ToArray ();
OverflowFolders = Program.Controller.Folders.GetRange (MenuOverflowThreshold, overflow_count).ToArray ();
} else {
Folders = Program.Controller.Folders.ToArray ();
OverflowFolders = new string [0];
}
string [] errors = new string [Folders.Length];
string [] overflow_errors = new string [OverflowFolders.Length];
int i = 0;
foreach (SparkleRepoBase repo in Program.Controller.Repositories) {
string error_message;
if (repo.Error == ErrorStatus.HostUnreachable) {
error_message = "Host unreachable";
} else if (repo.Error == ErrorStatus.HostIdentityChanged) {
error_message = "Host identity changed";
} else if (repo.Error == ErrorStatus.AuthenticationFailed) {
error_message = "Authentication failed";
} else if (repo.Error == ErrorStatus.DiskSpaceExcedeed) {
error_message = "Host identity changed";
} else {
error_message = "";
}
if (i > Folders.Length - 1)
overflow_errors [i] = error_message;
else
errors [i] = error_message;
i++;
}
FolderErrors = errors;
OverflowFolderErrors = overflow_errors;
}
} }
} }

View file

@ -47,7 +47,7 @@ namespace SparkleShare {
Height = 440; Height = 440;
ResizeMode = ResizeMode.NoResize; ResizeMode = ResizeMode.NoResize;
Background = new SolidColorBrush (Colors.WhiteSmoke); Background = new SolidColorBrush (Colors.WhiteSmoke);
Icon = SparkleUIHelpers.GetImageSource("sparkleshare-app", "ico"); Icon = SparkleUIHelpers.GetImageSource ("sparkleshare-app", "ico");
TaskbarItemInfo = new TaskbarItemInfo () { TaskbarItemInfo = new TaskbarItemInfo () {
Description = "SparkleShare" Description = "SparkleShare"

View file

@ -110,7 +110,7 @@ namespace SparkleShare {
}); });
}; };
Controller.UpdateOpenRecentEventsItemEvent += delegate (bool item_enabled) { Controller.UpdateRecentEventsItemEvent += delegate (bool item_enabled) {
Dispatcher.BeginInvoke ((Action) delegate { Dispatcher.BeginInvoke ((Action) delegate {
this.log_item.IsEnabled = item_enabled; this.log_item.IsEnabled = item_enabled;
this.log_item.UpdateLayout (); this.log_item.UpdateLayout ();
@ -155,11 +155,11 @@ namespace SparkleShare {
this.log_item = new SparkleMenuItem () { this.log_item = new SparkleMenuItem () {
Header = "Recent changes…", Header = "Recent changes…",
IsEnabled = Controller.OpenRecentEventsItemEnabled IsEnabled = Controller.RecentEventsItemEnabled
}; };
this.log_item.Click += delegate { this.log_item.Click += delegate {
Controller.OpenRecentEventsClicked (); Controller.RecentEventsClicked ();
}; };
SparkleMenuItem notify_item = new SparkleMenuItem () { SparkleMenuItem notify_item = new SparkleMenuItem () {
@ -207,6 +207,7 @@ namespace SparkleShare {
this.context_menu.Items.Add (folder_item); this.context_menu.Items.Add (folder_item);
if (Controller.Folders.Length > 0) { if (Controller.Folders.Length > 0) {
int i = 0;
foreach (string folder_name in Controller.Folders) { foreach (string folder_name in Controller.Folders) {
SparkleMenuItem subfolder_item = new SparkleMenuItem () { SparkleMenuItem subfolder_item = new SparkleMenuItem () {
Header = folder_name Header = folder_name
@ -220,26 +221,35 @@ namespace SparkleShare {
Height = 16 Height = 16
}; };
if (Program.Controller.UnsyncedFolders.Contains (folder_name)) { if (!string.IsNullOrEmpty (Controller.FolderErrors [i])) {
subfolder_item.Icon = new Image () { subfolder_item.Icon = new Image () {
Source = (BitmapSource) Imaging.CreateBitmapSourceFromHIcon ( Source = (BitmapSource) Imaging.CreateBitmapSourceFromHIcon (
System.Drawing.SystemIcons.Exclamation.Handle, System.Drawing.SystemIcons.Exclamation.Handle, Int32Rect.Empty,
Int32Rect.Empty, BitmapSizeOptions.FromWidthAndHeight (16,16)
BitmapSizeOptions.FromWidthAndHeight (16,16) )
) };
};
SparkleMenuItem error_item = new SparkleMenuItem () {
Header = Controller.FolderErrors [i],
IsEnabled = false
};
subfolder_item.Items.Add (error_item);
} else { } else {
subfolder_item.Icon = subfolder_image; subfolder_item.Icon = subfolder_image;
} }
this.context_menu.Items.Add (subfolder_item); this.context_menu.Items.Add (subfolder_item);
i++;
} }
SparkleMenuItem more_item = new SparkleMenuItem () { SparkleMenuItem more_item = new SparkleMenuItem () {
Header = "More projects" Header = "More projects"
}; };
i = 0;
foreach (string folder_name in Controller.OverflowFolders) { foreach (string folder_name in Controller.OverflowFolders) {
SparkleMenuItem subfolder_item = new SparkleMenuItem () { SparkleMenuItem subfolder_item = new SparkleMenuItem () {
Header = folder_name Header = folder_name
@ -253,20 +263,28 @@ namespace SparkleShare {
Height = 16 Height = 16
}; };
if (Program.Controller.UnsyncedFolders.Contains (folder_name)) { if (!string.IsNullOrEmpty (Controller.OverflowFolderErrors [i])) {
subfolder_item.Icon = new Image () { subfolder_item.Icon = new Image () {
Source = (BitmapSource) Imaging.CreateBitmapSourceFromHIcon ( Source = (BitmapSource) Imaging.CreateBitmapSourceFromHIcon (
System.Drawing.SystemIcons.Exclamation.Handle, System.Drawing.SystemIcons.Exclamation.Handle, Int32Rect.Empty,
Int32Rect.Empty, BitmapSizeOptions.FromWidthAndHeight (16,16)
BitmapSizeOptions.FromWidthAndHeight (16,16) )
) };
};
SparkleMenuItem error_item = new SparkleMenuItem () {
Header = Controller.OverflowFolderErrors [i],
IsEnabled = false
};
subfolder_item.Items.Add (error_item);
} else { } else {
subfolder_item.Icon = subfolder_image; subfolder_item.Icon = subfolder_image;
} }
more_item.Items.Add (subfolder_item); more_item.Items.Add (subfolder_item);
i++;
} }
if (more_item.Items.Count > 0) { if (more_item.Items.Count > 0) {