Increased the number of retries before abandoning StartMonitor
[pithos-ms-client] / trunk / Pithos.Client.WPF / Shell / ShellViewModel.cs
index 8ef5a6c..897d7d7 100644 (file)
@@ -47,9 +47,11 @@ using System.Net;
 using System.Reflection;
 using System.Runtime.InteropServices;
 using System.ServiceModel;
+using System.Threading;
 using System.Threading.Tasks;
 using System.Windows;
 using System.Windows.Controls.Primitives;
+using System.Windows.Input;
 using AppLimit.NetSparkle;
 using Caliburn.Micro;
 using Hardcodet.Wpf.TaskbarNotification;
@@ -71,7 +73,27 @@ using StatusService = Pithos.Client.WPF.Services.StatusService;
 namespace Pithos.Client.WPF {
        using System.ComponentModel.Composition;
 
-       
+       public class ToggleStatusCommand:ICommand
+       {
+           private readonly ShellViewModel _model;
+           public ToggleStatusCommand(ShellViewModel model)
+           {
+               _model = model;
+           }
+           public void Execute(object parameter)
+           {
+               _model.CurrentSyncStatus();
+           }
+
+           public bool CanExecute(object parameter)
+           {
+               return true;
+           }
+
+           public event EventHandler CanExecuteChanged;
+       }
+
+
        ///<summary>
        /// The "shell" of the Pithos application displays the taskbar  icon, menu and notifications.
        /// The shell also hosts the status service called by shell extensions to retrieve file info
@@ -84,14 +106,11 @@ namespace Pithos.Client.WPF {
        /// * ShowFilePropertiesEvent: Raised when a shell command requests the display of the file/container properties dialog
        ///</remarks>           
        //TODO: CODE SMELL Why does the shell handle the SelectiveSynchChanges?
-    [Export(typeof(IShell)), Export(typeof(ShellViewModel))]
+    [Export(typeof(IShell)), Export(typeof(ShellViewModel)),Export(typeof(IStatusNotification))]
        public class ShellViewModel : Screen, IStatusNotification, IShell,
                IHandle<Notification>, IHandle<SelectiveSynchChanges>, IHandle<ShowFilePropertiesEvent>
        {
-
-               //The Status Checker provides the current synch state
-               //TODO: Could we remove the status checker and use events in its place?
-               private readonly IStatusChecker _statusChecker;
+               
                private readonly IEventAggregator _events;
 
                public PithosSettings Settings { get; private set; }
@@ -122,8 +141,17 @@ namespace Pithos.Client.WPF {
                //Logging in the Pithos client is provided by log4net
         private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
 
-           private readonly PollAgent _pollAgent;
+        [Import]
+           private PollAgent _pollAgent;
 
+        [Import]
+           private NetworkAgent _networkAgent;
+
+           [Import]
+           public Selectives Selectives { get; set; }
+
+
+           public ToggleStatusCommand ToggleMiniStatusCommand { get; set; }
 
            private MiniStatusViewModel _miniStatus;
 
@@ -150,20 +178,22 @@ namespace Pithos.Client.WPF {
                /// The PithosSettings class encapsulates the app's settings to abstract their storage mechanism (App settings, a database or registry)
                ///</remarks>
                [ImportingConstructor]          
-               public ShellViewModel(IWindowManager windowManager, IEventAggregator events, IStatusChecker statusChecker, PithosSettings settings,PollAgent pollAgent)
+               public ShellViewModel(IWindowManager windowManager, IEventAggregator events, PithosSettings settings/*,PollAgent pollAgent,NetworkAgent networkAgent*/)
                {
                        try
                        {
 
                                _windowManager = windowManager;
                                //CHECK: Caliburn doesn't need explicit command construction
-                               //OpenPithosFolderCommand = new PithosCommand(OpenPithosFolder);
-                               _statusChecker = statusChecker;
+                               //CurrentSyncStatusCommand = new PithosCommand(OpenPithosFolder);
                                //The event subst
                                _events = events;
                                _events.Subscribe(this);
 
+/*
                            _pollAgent = pollAgent;
+                           _networkAgent = networkAgent;
+*/
                                Settings = settings;
 
                                Proxy.SetFromSettings(settings);
@@ -179,6 +209,8 @@ namespace Pithos.Client.WPF {
                                                                                                   };
 
                 SetVersionMessage();
+
+                ToggleMiniStatusCommand=new ToggleStatusCommand(this);
                        }
                        catch (Exception exc)
                        {
@@ -195,13 +227,30 @@ namespace Pithos.Client.WPF {
                VersionMessage = String.Format("Pithos+ {0}", fileVersion.FileVersion);
            }
 
-        public void OnStatusAction()
+        public void CurrentSyncStatus()
         {
-            if (Accounts.Count==0)
+            if (Accounts.Count == 0)
             {
                 ShowPreferences("AccountTab");
             }
+            else
+            {
+                if (!_statusVisible)
+                {
+                    _windowManager.ShowWindow(MiniStatus);
+                    _statusVisible = true;
+                }
+                else
+                {
+                    if (MiniStatus.IsActive)
+                        MiniStatus.TryClose();
+                    _statusVisible = false;
+                }
+
+                NotifyOfPropertyChange(() => MiniStatusCaption);
+            }
         }
+
            protected override void OnActivate()
                {
                        base.OnActivate();
@@ -268,7 +317,7 @@ namespace Pithos.Client.WPF {
                 }
                     
                                var accounts = Settings.Accounts.Select(MonitorAccount);
-                               await TaskEx.WhenAll(accounts);
+                await TaskEx.WhenAll(accounts).ConfigureAwait(false);
                                _statusService = StatusService.Start();
 
                        }
@@ -300,6 +349,10 @@ namespace Pithos.Client.WPF {
                                PithosMonitor monitor;
                                var accountName = account.AccountName;
 
+                           MigrateFolders(account);
+
+                           Selectives.SetIsSelectiveEnabled(account.AccountKey, account.SelectiveSyncEnabled);
+
                                if (Monitors.TryGetValue(account.AccountKey, out monitor))
                                {
                                        //If the account is active
@@ -349,8 +402,21 @@ namespace Pithos.Client.WPF {
                        });
                }
 
+           private void MigrateFolders(AccountSettings account)
+           {
+               var oldOthersFolder=Path.Combine(account.RootPath, FolderConstants.OldOthersFolder);
+               var newOthersFolder = Path.Combine(account.RootPath, FolderConstants.OthersFolder);
+               var oldFolder = new DirectoryInfo(oldOthersFolder);
+               var newFolder = new DirectoryInfo(newOthersFolder);
+
+            if (oldFolder.Exists && !newFolder.Exists)
+            {
+                oldFolder.MoveTo(newOthersFolder);
+            }
+           }
+
 
-               protected override void OnViewLoaded(object view)
+           protected override void OnViewLoaded(object view)
                {
                        UpdateStatus();
                        var window = (Window)view;            
@@ -383,6 +449,22 @@ namespace Pithos.Client.WPF {
                }
            }
 
+        public string TooltipMiniStatus
+        {
+            get
+            {
+                return String.Format("{0}\r\n{1}", "Status Window", "Enable / Disable the status window");
+            }
+        }
+
+        /*public string ToggleStatusWindowMessage
+        {
+            get
+            {
+                return String.Format("{0}" + Environment.NewLine + "{1} Toggle Mini Status");
+            }
+        }*/
+
            private readonly ObservableConcurrentCollection<AccountInfo> _accounts = new ObservableConcurrentCollection<AccountInfo>();
                public ObservableConcurrentCollection<AccountInfo> Accounts
                {
@@ -439,6 +521,11 @@ namespace Pithos.Client.WPF {
 
                #region Commands
 
+        public void CancelCurrentOperation()
+        {
+            _networkAgent.CancelCurrentOperation();
+        }
+
         public void ShowPreferences()
         {
             ShowPreferences(null);
@@ -447,9 +534,14 @@ namespace Pithos.Client.WPF {
                public void ShowPreferences(string currentTab)
                {
                        //Settings.Reload();
-                   var preferences = new PreferencesViewModel(_windowManager, _events, this, Settings,currentTab);
-                   _windowManager.ShowDialog(preferences);
-                       
+            
+                   var preferences = IoC.Get<PreferencesViewModel>();//??new PreferencesViewModel(_windowManager, _events, this, Settings,currentTab);
+            if (!String.IsNullOrWhiteSpace(currentTab))
+                preferences.SelectedTab = currentTab;
+            if (!preferences.IsActive)
+                       _windowManager.ShowWindow(preferences);
+            var view = (Window)preferences.GetView();
+            view.NullSafe(v=>v.Activate());
                }
 
                public void AboutPithos()
@@ -505,27 +597,13 @@ namespace Pithos.Client.WPF {
                }
            }
 
-           public void ShowMiniStatus()
-        {            
-            if (!_statusVisible)
-                _windowManager.ShowWindow(MiniStatus);
-            else
-            {           
-                if (MiniStatus.IsActive)
-                    MiniStatus.TryClose();
-            }
-            _statusVisible=!_statusVisible;
-
-               NotifyOfPropertyChange(()=>MiniStatusCaption);
-        }
-
            public bool HasConflicts
            {
             get { return true; }
            }
         public void ShowConflicts()
         {
-            _windowManager.ShowWindow(new ConflictsViewModel());
+            _windowManager.ShowWindow(IoC.Get<ConflictsViewModel>());            
         }
 
            /// <summary>
@@ -638,21 +716,32 @@ namespace Pithos.Client.WPF {
                        return newInfo;
                }
 
+           private bool _isPaused;
+           public bool IsPaused
+           {
+               get { return _isPaused; }
+               set
+               {
+                   _isPaused = value;
+                PauseSyncCaption = IsPaused ? "Resume syncing" : "Pause syncing";
+                var iconKey = IsPaused ? "TraySyncPaused" : "TrayInSynch";
+                StatusIcon = String.Format(@"../Images/{0}.ico", iconKey);
 
-               public void ToggleSynching()
+                NotifyOfPropertyChange(() => IsPaused);
+               }
+           }
+
+           public void ToggleSynching()
                {
-                       bool isPaused=false;
-                       foreach (var pair in Monitors)
+                       IsPaused=!IsPaused;
+                       foreach (var monitor in Monitors.Values)
                        {
-                               var monitor = pair.Value;
-                               monitor.Pause = !monitor.Pause;
-                               isPaused = monitor.Pause;
+                           monitor.Pause = IsPaused ;
                        }
-                        
+            _pollAgent.Pause = IsPaused;
+            _networkAgent.Pause = IsPaused;
+
 
-                       PauseSyncCaption = isPaused ? "Resume syncing" : "Pause syncing";
-                       var iconKey = isPaused? "TraySyncPaused" : "TrayInSynch";
-                       StatusIcon = String.Format(@"../Images/{0}.ico", iconKey);
                }
 
         public void ExitPithos()
@@ -668,12 +757,13 @@ namespace Pithos.Client.WPF {
                 var view = GetView() as Window;
                 if (view != null)
                     view.Close();
-                else
-                    Application.Current.Shutdown();
             }
             catch (Exception exc)
             {
-                Log.Info("Exception while exiting", exc);
+                Log.Info("Exception while exiting", exc);                
+            }
+            finally
+            {
                 Application.Current.Shutdown();
             }
         }
@@ -774,7 +864,7 @@ namespace Pithos.Client.WPF {
                                                                var message = String.Format("API Key Expired for {0}. Starting Renewal",
                                                                                                                        monitor.UserName);
                                                                Log.Error(message, exc);
-                                                       var account = Settings.Accounts.Find(acc => acc.AccountName == monitor.UserName);                                
+                                var account = Settings.Accounts.Find(acc => acc.AccountKey == new Uri(new Uri(monitor.AuthenticationUrl), monitor.UserName));                                
                                                        account.IsExpired = true;
                                 Notify(new ExpirationNotification(account));
                                                                //TryAuthorize(monitor.UserName, retries).Wait();
@@ -813,7 +903,7 @@ namespace Pithos.Client.WPF {
 
                private bool AbandonRetry(PithosMonitor monitor, int retries)
                {
-                       if (retries > 1)
+                       if (retries > 3)
                        {
                                var message = String.Format("Monitoring of account {0} has failed too many times. Will not retry",
                                                                                        monitor.UserName);
@@ -898,7 +988,7 @@ namespace Pithos.Client.WPF {
 
                public void Notify(Notification notification)
                {
-                       _events.Publish(notification);
+            TaskEx.Run(()=> _events.Publish(notification));
                }
 
 
@@ -956,14 +1046,24 @@ namespace Pithos.Client.WPF {
                #region Event Handlers
                
                public void Handle(SelectiveSynchChanges message)
-               {            
-                       PithosMonitor monitor;
-                       if (Monitors.TryGetValue(message.Account.AccountKey, out monitor))
-                       {
-                               monitor.SetSelectivePaths(message.Uris,message.Added,message.Removed);
+               {
+                   TaskEx.Run(() =>
+                   {
+                       PithosMonitor monitor;
+                       if (Monitors.TryGetValue(message.Account.AccountKey, out monitor))
+                       {
+                    Selectives.SetIsSelectiveEnabled(message.Account.AccountKey, message.Enabled);
+                           monitor.SetSelectivePaths(message.Uris, message.Added, message.Removed);
+                       }
+
+                       var account = Accounts.FirstOrDefault(acc => acc.AccountKey == message.Account.AccountKey);
+                       if (account != null)
+                       {
+                           var added=monitor.UrisToFilePaths(message.Added);
+                    _pollAgent.SynchNow(added);
+                       }
+                   });
 
-                       }
-                       
                }
 
 
@@ -1011,7 +1111,7 @@ namespace Pithos.Client.WPF {
                    {
                        StatusMessage = String.Format("{0} {1:p2} of {2} - {3}",                                                      
                                               progress.Action,
-                                                     progress.Block/(double)progress.TotalBlocks,
+                                                     (progress.Block + progress.BlockPercentage/100.0)/(double)progress.TotalBlocks,
                                                      progress.FileSize.ToByteSize(),
                                                      progress.FileName);
                        return;