Revision 759bd3c4

b/trunk/Pithos.Client.WPF/App.xaml.cs
49 49
using System.Net.Mail;
50 50
using System.Reflection;
51 51
using System.Text;
52
using System.Threading;
52 53
using System.Threading.Tasks;
53 54
using System.Windows;
54 55
using Caliburn.Micro;
......
92 93
                return;
93 94
            }
94 95
            
96
            //TODO: Possibly add a delay here?
97
            if (e.Args.Contains("startup"))
98
            {
99
                if (Settings.Default.StartupDelay>TimeSpan.Zero)
100
                    Thread.Sleep(Settings.Default.StartupDelay);
101
            }
102

  
95 103
            var splashScreen = new SplashScreen("images/logo.png");
96 104
            splashScreen.Show(true);
97 105
            
b/trunk/Pithos.Client.WPF/AppBootstrapper.cs
67 67
	{
68 68
		CompositionContainer container;
69 69

  
70
	    public AppBootstrapper()
71
	    {
72
            LogManager.GetLog = type => new log4netLogger(type);
73
	        UpgradeSettings();
74

  
75
	    }
76

  
77
	    private void UpgradeSettings()
78
	    {
79
            if (Settings.Default.MustUpgrade)
80
            {
81
                Settings.Default.Upgrade();
82
                Settings.Default.MustUpgrade = false;
83
                Settings.Default.Save();
84
            }
85
	    }
86

  
87
	    /// <summary>
70
		public AppBootstrapper()
71
		{
72
			LogManager.GetLog = type => new log4netLogger(type);
73
			UpgradeSettings();
74

  
75
		}
76

  
77
		private void UpgradeSettings()
78
		{
79
			if (Settings.Default.MustUpgrade)
80
			{
81
				Settings.Default.Upgrade();
82
				Settings.Default.MustUpgrade = false;
83
				Settings.Default.Save();
84
			}
85
		}
86

  
87
		/// <summary>
88 88
		/// By default, we are configured to use MEF
89 89
		/// </summary>
90 90
		protected override void Configure() {
91
		    var catalog = new AggregateCatalog(
92
		        AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()
93
		        );
91
			var catalog = new AggregateCatalog(
92
				AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()
93
				);
94 94

  
95
            Type[] types = { typeof(PithosMonitor), typeof(CloudFilesClient) };
96
            foreach (var type in types)
97
            {
98
                catalog.Catalogs.Add(new AssemblyCatalog(type.Assembly));
99
            }
95
			Type[] types = { typeof(PithosMonitor), typeof(CloudFilesClient) };
96
			foreach (var type in types)
97
			{
98
				catalog.Catalogs.Add(new AssemblyCatalog(type.Assembly));
99
			}
100 100

  
101 101
			container = new CompositionContainer(catalog,true);
102 102

  
......
105 105
			batch.AddExportedValue<IWindowManager>(new WindowManager());
106 106
			batch.AddExportedValue<IEventAggregator>(new EventAggregator());
107 107
			batch.AddExportedValue(container);
108
		    batch.AddExportedValue(catalog);
108
			batch.AddExportedValue(catalog);
109 109

  
110 110

  
111 111
			container.Compose(batch);
112

  
113
            ConventionManager.AddElementConvention<MenuItem>(ItemsControl.ItemsSourceProperty, "DataContext", "Click");
114
	        ConventionManager.AddElementConvention<IntegerUpDown>(IntegerUpDown.ValueProperty, "Value", "ValueChanged");
112
		    
113
			ConventionManager.AddElementConvention<MenuItem>(ItemsControl.ItemsSourceProperty, "DataContext", "Click");
114
			ConventionManager.AddElementConvention<IntegerUpDown>(IntegerUpDown.ValueProperty, "Value", "ValueChanged");
115
		    ConventionManager.AddElementConvention<BusyIndicator>(BusyIndicator.IsBusyProperty, "IsBusy", "DataContextChanged");
115 116
		}
116 117

  
117 118
		protected override object GetInstance(Type serviceType, string key)
b/trunk/Pithos.Client.WPF/Configuration/PithosSettings.cs
191 191
            }
192 192
        }
193 193

  
194
        public TimeSpan StartupDelay
195
        {
196
            get { return _settings.StartupDelay; }
197
            set
198
            {
199
                if (value < TimeSpan.Zero)
200
                    throw new ArgumentOutOfRangeException();
201
                _settings.StartupDelay = value;
202
            }
203
        }
204

  
205

  
194 206
        public bool StartOnSystemStartup
195 207
        {
196 208
            get { return _settings.StartOnSystemStartup; }
b/trunk/Pithos.Client.WPF/Preferences/PreferencesView.xaml
194 194
                    <extToolkit:IntegerUpDown x:Name="Settings_PollingInterval" HorizontalAlignment="Left" Width="100" Margin="5,0" Watermark="Enter seconds" Minimum="10" />                    
195 195
                    <TextBlock Text="Hashing Parallelism" Margin="5"/>
196 196
                    <extToolkit:IntegerUpDown x:Name="Settings_HashingParallelism" HorizontalAlignment="Left" Width="100" Margin="5,0" Watermark="Enter number of tasks" Minimum="1" />                    
197
                    <TextBlock Text="Startup Delay (minutes)" Margin="5"/>
198
                    <extToolkit:IntegerUpDown x:Name="StartupDelay" HorizontalAlignment="Left" Width="100" Margin="5,0" Watermark="Enter number of tasks" Minimum="0" />                    
197 199
                </StackPanel>
198 200
            </TabItem>
199 201
        </TabControl>
b/trunk/Pithos.Client.WPF/Preferences/PreferencesViewModel.cs
162 162
        }
163 163
        #endregion
164 164

  
165

  
166
        public int StartupDelay
167
        {
168
            get { return (int) Settings.StartupDelay.TotalMinutes; }
169
            set
170
            {
171
                if (value<0)
172
                    throw new ArgumentOutOfRangeException("value","The Startup Delay must be greater or equal to 0");
173
                Settings.StartupDelay = TimeSpan.FromMinutes(value);
174
                NotifyOfPropertyChange(()=>StartupDelay);
175
            }
176
        }
165 177
       
166 178
        #region Commands
167 179
        
......
173 185
        public void SelectiveSyncFolders()
174 186
        {
175 187
            var monitor = Shell.Monitors[CurrentAccount.AccountName];
176
            var folders=monitor.GetRootFolders().ToList();
188
            
177 189

  
178
            var model = new SelectiveSynchViewModel(folders,_events,CurrentAccount);
190
            var model = new SelectiveSynchViewModel(monitor,_events,CurrentAccount);
179 191
            if (_windowManager.ShowDialog(model) == true)
180 192
            {
181 193
                
b/trunk/Pithos.Client.WPF/Properties/AssemblyInfo.cs
93 93
// You can specify all the values or you can default the Build and Revision Numbers 
94 94
// by using the '*' as shown below:
95 95
// [assembly: AssemblyVersion("1.0.*")]
96
[assembly: AssemblyVersion("0.1.0.0")]
97
[assembly: AssemblyFileVersionAttribute("0.1.20220.2042")]
96
[assembly: AssemblyVersion("0.7.0.0")]
97
[assembly: AssemblyFileVersionAttribute("0.7.20221.2042")]
b/trunk/Pithos.Client.WPF/Properties/Settings.Designer.cs
306 306
                this["HashingParallelism"] = value;
307 307
            }
308 308
        }
309
        
310
        [global::System.Configuration.UserScopedSettingAttribute()]
311
        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
312
        [global::System.Configuration.DefaultSettingValueAttribute("00:01:00")]
313
        public global::System.TimeSpan StartupDelay {
314
            get {
315
                return ((global::System.TimeSpan)(this["StartupDelay"]));
316
            }
317
            set {
318
                this["StartupDelay"] = value;
319
            }
320
        }
309 321
    }
310 322
}
b/trunk/Pithos.Client.WPF/Properties/Settings.settings
77 77
    <Setting Name="HashingParallelism" Type="System.Byte" Scope="User">
78 78
      <Value Profile="(Default)">1</Value>
79 79
    </Setting>
80
    <Setting Name="StartupDelay" Type="System.TimeSpan" Scope="User">
81
      <Value Profile="(Default)">00:01:00</Value>
82
    </Setting>
80 83
  </Settings>
81 84
</SettingsFile>
b/trunk/Pithos.Client.WPF/SelectiveSynch/DirectoryRecord.cs
47 47
using System.Linq;
48 48
using System.Text;
49 49
using Caliburn.Micro;
50
using Pithos.Core.Agents;
51
using Pithos.Interfaces;
50 52

  
51 53
namespace Pithos.Client.WPF.SelectiveSynch
52 54
{
53 55
    public class DirectoryRecord : PropertyChangedBase,IEnumerable<DirectoryRecord>
54 56
    {
55
        public DirectoryInfo Info { get; set; }
57
        private ObjectInfo _objectInfo;
58
        public ObjectInfo ObjectInfo
59
        {
60
            get { return _objectInfo; }
61
            set
62
            {                
63
                _objectInfo = value;
64
                Uri = value.Uri;
65
            }
66
        }
56 67

  
68
        public Uri Uri { get; set; }
69
        //public DirectoryInfo LocalInfo { get; set; }
57 70

  
58 71
        DirectoryRecord _parent;
59 72

  
60 73
        public bool Added { get; set; }
61 74
        public bool Removed { get; set; }
62 75

  
63
        private bool? _isChecked;
76
        private bool? _isChecked=true;
64 77
        #region IsChecked
65 78

  
66 79
        /// <summary>
......
88 101
            Removed = !(_isChecked??true);
89 102

  
90 103
            if (updateChildren && _isChecked.HasValue)
91
                this.Directories.ForEach(c => c.SetIsChecked(_isChecked, true, false));
104
                this.Directories.Apply(c => c.SetIsChecked(_isChecked, true, false));
92 105

  
93 106
            if (updateParent && _parent != null)
94 107
                _parent.VerifyCheckState();
......
99 112
        void VerifyCheckState()
100 113
        {
101 114
            bool? state = null;
102
            for (int i = 0; i < this.Directories.Count; ++i)
115
            for (var i = 0; i < this.Directories.Count(); ++i)
103 116
            {
104
                bool? current = this.Directories[i].IsChecked;
117
                bool? current = this.Directories.ElementAt(i).IsChecked;
105 118
                if (i == 0)
106 119
                {
107 120
                    state = current;
......
120 133

  
121 134
        public bool IsInitiallySelected { get; private set; }
122 135

  
123
        readonly Lazy<List<DirectoryRecord>> _directories = new Lazy<List<DirectoryRecord>>();
136
        /*readonly Lazy<List<DirectoryRecord>> _directories = new Lazy<List<DirectoryRecord>>();
124 137

  
125 138
        public List<DirectoryRecord> Directories
126 139
        {
......
128 141
            {
129 142
                return _directories.Value;
130 143
            }
144
        }*/
145

  
146
        private IEnumerable<DirectoryRecord> _directories=new List<DirectoryRecord>();
147
        public IEnumerable<DirectoryRecord> Directories
148
        {
149
            get { return _directories; }
150
            set { _directories = value; }
131 151
        }
132 152

  
133
        public DirectoryRecord(string ignorePath)
153
        public DirectoryRecord()
134 154
        {
135
            _directories = new Lazy<List<DirectoryRecord>>(() => 
155
            
156
/*
157
             _directories = new Lazy<List<DirectoryRecord>>(() => 
158
                new List<DirectoryRecord>());
159
*/
160
/*
161
             _directories = new Lazy<List<DirectoryRecord>>(() => 
136 162
                (from directory in Info.EnumerateDirectories("*", SearchOption.TopDirectoryOnly)
137 163
                where !directory.FullName.StartsWith(ignorePath)
138 164
                select new DirectoryRecord(ignorePath) { Info = directory }).ToList());
165
*/
139 166
        }
140 167

  
168
        private string _displayName;
169
        public string DisplayName
170
        {
171
            get
172
            {
173
                if (ObjectInfo != null)
174
                    return ObjectInfo.Name;
175
                return _displayName;
176
            }
177
            set { _displayName = value; }
178
        }
179

  
180
        public DirectoryRecord(string rootPath,ObjectInfo info)
181
        {
182
            var relativePath = info.RelativeUrlToFilePath(info.Account);
183
            //LocalInfo = new DirectoryInfo(Path.Combine(rootPath, relativePath));
184
            ObjectInfo = info;
185
        }
141 186

  
142 187

  
143 188
/*
b/trunk/Pithos.Client.WPF/SelectiveSynch/SelectiveSynchChanges.cs
49 49
{
50 50
    public class SelectiveSynchChanges
51 51
    {
52
        public Uri[] Uris { get; set; }
52 53
        public AccountSettings Account { get; set; }
53
        public string[] Added { get; set; }
54
        public string[] Removed { get; set; }
54
        public Uri[] Added { get; set; }
55
        public Uri[] Removed { get; set; }
55 56
    }
56 57
}
b/trunk/Pithos.Client.WPF/SelectiveSynch/SelectiveSynchView.xaml
1 1
<Window x:Class="Pithos.Client.WPF.SelectiveSynch.SelectiveSynchView"
2 2
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 3
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4
        xmlns:local="clr-namespace:Pithos.Client.WPF.SelectiveSynch" Title="Selective Synch" Height="300" Width="300" >
5
    <Window.Resources>        
6
        
7
        <Style x:Key="TreeItemStyle" TargetType="TreeViewItem">
8
            <Setter Property="IsExpanded" Value="True" />
9
            <Setter Property="IsSelected" Value="{Binding IsInitiallySelected, Mode=OneTime}" />
10
            <Setter Property="KeyboardNavigation.AcceptsReturn" Value="True" />
11
            <Setter Property="local:VirtualToggleButton.IsVirtualToggleButton" Value="True" />
12
            <Setter Property="local:VirtualToggleButton.IsChecked" Value="{Binding IsChecked}" />
13
        </Style>
14

  
15
        <HierarchicalDataTemplate x:Key="CheckboxStyle" DataType="{x:Type local:DirectoryRecord}"
4
        xmlns:local="clr-namespace:Pithos.Client.WPF.SelectiveSynch"
5
        xmlns:extToolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit/extended"
6
        xmlns:Converters="clr-namespace:Pithos.Client.WPF.Converters" 
7
        Title="Selective Synch" Height="300" Width="300" 
8
        ShowInTaskbar="true"
9
        WindowStartupLocation="CenterScreen"
10
        Icon="/Pithos.Client.WPF;component/Images/PithosTaskbar.png"
11
        Background="{StaticResource {x:Static SystemColors.ControlBrushKey}}">
12
    <Window.Resources>
13
        <ResourceDictionary>
14
            <ResourceDictionary.MergedDictionaries>
15
                <ResourceDictionary Source="..\PithosStyles.xaml" />
16
            </ResourceDictionary.MergedDictionaries>
17
            <Converters:NullToVisibilityConverter x:Key="NullToVisible" />
18
            <Style x:Key="TreeItemStyle" TargetType="TreeViewItem">
19
                <Setter Property="IsExpanded" Value="True" />
20
                <Setter Property="IsSelected" Value="{Binding IsInitiallySelected, Mode=OneTime}" />
21
                <Setter Property="KeyboardNavigation.AcceptsReturn" Value="True" />
22
                <Setter Property="local:VirtualToggleButton.IsVirtualToggleButton" Value="True" />
23
                <Setter Property="local:VirtualToggleButton.IsChecked" Value="{Binding IsChecked}" />
24
            </Style>
25
            <HierarchicalDataTemplate x:Key="CheckboxStyle" DataType="{x:Type local:DirectoryRecord}"
16 26
                                    ItemsSource="{Binding Directories}" >
17
            <StackPanel Orientation="Horizontal">
18
                <CheckBox
27
                <StackPanel Orientation="Horizontal">
28
                    <CheckBox
19 29
            Focusable="False" 
20 30
            IsChecked="{Binding IsChecked}" 
21 31
            VerticalAlignment="Center"
22 32
            />
23
                <ContentPresenter 
24
            Content="{Binding Info.Name, Mode=OneTime}" 
33
                    <ContentPresenter 
34
            Content="{Binding DisplayName, Mode=OneTime}" 
25 35
            Margin="2,0"
26 36
            />
27
            </StackPanel>
28
        </HierarchicalDataTemplate>
37
                </StackPanel>
38
            </HierarchicalDataTemplate>
39

  
40
        </ResourceDictionary>
41

  
29 42

  
30 43
    </Window.Resources>
31 44
    <Grid>
......
33 46
            <RowDefinition Height="*"/>
34 47
            <RowDefinition Height="Auto"/>
35 48
        </Grid.RowDefinitions>
36
        <TreeView Grid.Row="0" Name="PithosDirectory" 
49
        <extToolkit:BusyIndicator Name="IsBusy" Grid.Row="0" BusyContent="Retrieving folders ..." DisplayAfter="0">
50
            <TreeView  Name="RootNodes" 
37 51
                  ItemContainerStyle="{StaticResource TreeItemStyle}" 
38 52
                  ItemTemplate="{StaticResource CheckboxStyle}">
39
        </TreeView>
53
            </TreeView>
54
        </extToolkit:BusyIndicator>
40 55
        <StackPanel Grid.Row="1">
41 56
            <StackPanel Orientation="Horizontal" Grid.Row="1" HorizontalAlignment="Right">
42
                <Button Name="SaveChanges" Content="OK" Margin="5,5,10,5" />
43
                <Button Name="RejectChanges" Content="Cancel" Margin="5,5,10,5" />                
57
                <Button Name="SaveChanges" Content="OK" Margin="5,5,10,5"  Style="{StaticResource ButtonStyle}"/>
58
                <Button Name="RejectChanges" Content="Cancel" Margin="5,5,10,5"  Style="{StaticResource ButtonStyle}"/>                
44 59
            </StackPanel>
45 60
        </StackPanel>
46 61
    </Grid>
b/trunk/Pithos.Client.WPF/SelectiveSynch/SelectiveSynchView.xaml.cs
60 60
    public partial class SelectiveSynchView : Window
61 61
    {
62 62
        public SelectiveSynchView()
63
        {
63
        {            
64 64
            InitializeComponent();
65 65
        }
66 66
    }
b/trunk/Pithos.Client.WPF/SelectiveSynch/SelectiveSynchViewModel.cs
46 46
using System.IO;
47 47
using System.Linq;
48 48
using System.Text;
49
using System.Threading.Tasks;
49 50
using Caliburn.Micro;
50 51
using Pithos.Client.WPF.Properties;
52
using Pithos.Core;
53
using Pithos.Core.Agents;
51 54
using Pithos.Interfaces;
52 55
using Pithos.Network;
53 56

  
......
55 58
{
56 59
    class SelectiveSynchViewModel:Screen
57 60
    {
61
        private const string DirectoryType = "application/directory";
58 62
        private IEventAggregator _events ;
59 63

  
60
        private string _rootPath;
61
        private string _cachePath;
62
        public string RootPath
63
        {
64
            get { return _rootPath; }
65
            set
66
            {
67
                _rootPath = value;
68
                _cachePath = Path.Combine(_rootPath, FolderConstants.CacheFolder);
69
                _pithosDirectory = new ObservableCollection<DirectoryRecord>{
70
                        new DirectoryRecord(_cachePath) {Info = new DirectoryInfo(value)}};
71
                NotifyOfPropertyChange(() => RootPath);
72
                NotifyOfPropertyChange(()=>PithosDirectory);
73
            }
74
        }
75

  
76 64
        private string _title;
77 65
        public string Title
78 66
        {
......
86 74

  
87 75
        public AccountSettings Account { get; set; }
88 76

  
89
        private ObservableCollection<DirectoryRecord> _pithosDirectory;
90
        public ObservableCollection<DirectoryRecord> PithosDirectory
77
        private readonly ObservableCollection<DirectoryRecord> _rootNodes=new ObservableCollection<DirectoryRecord>();
78
        public ObservableCollection<DirectoryRecord> RootNodes
91 79
        {
92
            get { return _pithosDirectory; }
80
            get { return _rootNodes; }
93 81
        }
94 82

  
95
        private ObservableCollection<DirectoryInfo> _checks;
96
        public ObservableCollection<DirectoryInfo> Checks
83
        private ObservableCollection<ObjectInfo> _checks;
84
        private PithosMonitor _monitor;
85
        private bool _isBusy=true;
86

  
87
        public ObservableCollection<ObjectInfo> Checks
97 88
        {
98 89
            get { return _checks; }
99 90
        }
100 91

  
101 92
        public void GetChecks()
102 93
        {
103
            var root = PithosDirectory[0];            
104
            _checks = new ObservableCollection<DirectoryInfo>(
94
            var root = RootNodes[0];            
95
            _checks = new ObservableCollection<ObjectInfo>(
105 96
                from record in root
106 97
                where record.IsChecked==true
107
                select record.Info);
98
                select record.ObjectInfo);
108 99
            NotifyOfPropertyChange(() => Checks);
109 100
        }
110 101

  
111
        public SelectiveSynchViewModel(IEnumerable<string> folders, IEventAggregator events, AccountSettings account)
102
        public SelectiveSynchViewModel(PithosMonitor monitor, IEventAggregator events, AccountSettings account)
112 103
        {
113 104
            Account = account;
114 105
            AccountName = account.AccountName;
115 106
            Title = account.AccountName;
116
            RootPath = account.RootPath;
107
            _monitor = monitor;
108
            _events = events;
109
            TaskEx.Run(LoadRootNode);
110
        }
111

  
112
        private void LoadRootNode()
113
        {
114
            var client = _monitor.CloudClient;
115

  
116
            var dirs = from container in client.ListContainers(_monitor.UserName)
117
                       select new DirectoryRecord
118
                                  {
119
                                      DisplayName = container.Name,
120
                                      Directories = (from dir in client.ListObjects(_monitor.UserName, container.Name, "")
121
                                                     where dir.Content_Type == DirectoryType
122
                                                     select new DirectoryRecord { DisplayName = dir.Name, ObjectInfo = dir }).ToList()
123
                                  };
124
            var ownFolders = dirs.ToList();
125

  
126
            var accounts = client.ListSharingAccounts();
127

  
128
            var accountNodes=from account in client.ListSharingAccounts()
129
                             select new DirectoryRecord
130
                             {
131
                                DisplayName=account.name,
132
                                Directories=(from container in client.ListContainers(account.name)
133
                                            select new DirectoryRecord
134
                                                        {
135
                                                            DisplayName=container.Name,
136
                                                            Directories=(from folder in client.ListObjects(account.name,container.Name,"")
137
                                                                        where folder.Content_Type==DirectoryType
138
                                                                        select new DirectoryRecord{DisplayName=folder.Name,ObjectInfo=folder}).ToList()
139
                                                        }).ToList()
140
                             };                                                          
141

  
142
            var othersNode = new DirectoryRecord
143
                                 {
144
                                     DisplayName = "Others",
145
                                     Directories=accountNodes.ToList()
146
                                 };
147

  
148
            
149
            var rootItem = new DirectoryRecord
150
                               {
151
                                   DisplayName = AccountName ,
152
                                   Directories = ownFolders.ToList()
153
                               };
154
            
155

  
156
            SetInitialSelections(Account);
157
            
158
            Execute.OnUIThread(()=>
159
                                   {
160
                                       this.RootNodes.Add(rootItem);
161
                                       this.RootNodes.Add(othersNode);
162
                                       IsBusy = false;
163
                                   });
164
        }
117 165

  
118
            SetInitialSelections(account);
166
        public bool IsBusy
167
        {
168
            get {
169
                return _isBusy;
170
            }
171
            set {
172
                _isBusy = value;
173
                NotifyOfPropertyChange(()=>IsBusy);
174
            }
119 175
        }
120 176

  
121 177
        private void SetInitialSelections(AccountSettings account)
122 178
        {
123 179
            var selections = account.SelectiveFolders;
180

  
124 181
            if (selections.Count == 0)
125 182
                return;
126
            var root = PithosDirectory[0];
127
            var selects= from record in root
128
                             where selections.Contains(record.Info.FullName)
129
                             select record;
130
            selects.Apply(record=>record.IsChecked=true);            
183
            
184
            var selects = from rootRecord in RootNodes
185
                          from record in rootRecord
186
                          where record.ObjectInfo!=null &&  selections.Contains(record.ObjectInfo.Name)
187
                          select record;
188

  
189
            selects.Apply(record=>record.IsChecked=true);
131 190
        }
132 191

  
133 192
        protected string AccountName { get; set; }
......
137 196
            var selections = GetSelectedFolderNames();
138 197

  
139 198
            SaveSettings(selections);
140
            var root = PithosDirectory[0];
141 199
            
142
            var added= (from record in root
143
                         where record.Added
144
                         select record.Info.FullName.ToLower()).ToArray();
145
            var removed= (from record in root
146
                         where record.Removed
147
                         select record.Info.FullName.ToLower()).ToArray();            
148

  
149
            _events.Publish(new SelectiveSynchChanges{Account=Account,Added=added,Removed=removed});
200
            //RootNodes is an ObservableCollection, it can't be enumerated iterativelly
201
            
202
            var added= (from root in RootNodes
203
                        from record in root
204
                         where record.Added && record.Uri != null
205
                         select record.Uri).ToArray();
206
            var removed = (from root in RootNodes
207
                            from record in root
208
                          where record.Removed && record.Uri != null
209
                         select record.Uri).ToArray();
210
            var uris = (from root in RootNodes
211
                        from record in root
212
                        where record.IsChecked==true && record.Uri != null
213
                        select record.Uri).ToArray();
214
            _events.Publish(new SelectiveSynchChanges{Account=Account,Uris=uris,Added=added,Removed=removed});
150 215
            
151 216

  
152 217
            
......
164 229

  
165 230
        private string[] GetSelectedFolderNames()
166 231
        {
167
            var root = PithosDirectory[0];
168
            var selections = from record in root
169
                         where record.IsChecked == true
170
                         select record.Info.FullName;
232

  
233
            var selections = from node in RootNodes
234
                             from childNode in node
235
                             where childNode.ObjectInfo != null
236
                                   && childNode.IsChecked == true
237
                             select node.ObjectInfo.Uri.ToString();
171 238
            return selections.ToArray();
172 239
        }
173 240

  
b/trunk/Pithos.Client.WPF/Shell/ShellViewModel.cs
796 796
			PithosMonitor monitor;
797 797
			if (_monitors.TryGetValue(accountName, out monitor))
798 798
			{
799
				monitor.AddSelectivePaths(message.Added);
800
				monitor.RemoveSelectivePaths(message.Removed);
799
				monitor.SetSelectivePaths(message.Uris,message.Added,message.Removed);
801 800

  
802 801
			}
803 802
			
b/trunk/Pithos.Client.WPF/app.config
84 84
      <setting name="HashingParallelism" serializeAs="String">
85 85
        <value>1</value>
86 86
      </setting>
87
      <setting name="StartupDelay" serializeAs="String">
88
        <value>00:01:00</value>
89
      </setting>
87 90
    </Pithos.Client.WPF.Properties.Settings>
88 91
  </userSettings>
89 92
  <connectionStrings>
b/trunk/Pithos.Core.Test/MockSettings.cs
38 38
        public bool ExtensionsActivated { get; set; }
39 39

  
40 40
        public int PollingInterval { get; set; }
41
        public TimeSpan StartupDelay { get; set; }
41 42

  
42 43
        public byte HashingParallelism { get; set; }
43 44

  
b/trunk/Pithos.Core/Agents/CollectionExtensions.cs
40 40
 */
41 41
#endregion
42 42
using System.Collections.Concurrent;
43
using Pithos.Interfaces;
43 44

  
44 45
namespace Pithos.Core.Agents
45 46
{
......
81 82

  
82 83
            queue.AddFromEnumerable(temp);
83 84
        }
85

  
86

  
87
        public static IEnumerable<ObjectInfo> FilterBelow(this IEnumerable<ObjectInfo> infos,List<Uri> filterUris  )
88
        {
89
            if (filterUris == null)
90
                return infos;
91
            if (filterUris.Count == 0)
92
                return infos;
93
            var filteredUris = from info in infos
94
                                  where !filterUris.Any(s => info.Uri.ToString()
95
                                      .StartsWith(s.ToString()))
96
                                  select info;
97
            return filteredUris;
98
        }
84 99
    }
85 100
}
b/trunk/Pithos.Core/Agents/PollAgent.cs
189 189

  
190 190
                try
191 191
                {
192
                    //Wait for any deletions to finish
192 193
                    await NetworkAgent.GetDeleteAwaiter();
193 194
                    //Get the poll time now. We may miss some deletions but it's better to keep a file that was deleted
194 195
                    //than delete a file that was created while we were executing the poll                    
......
242 243

  
243 244
                        var differencer = _differencer.PostSnapshot(accountInfo, cleanRemotes);
244 245

  
245
                        ProcessDeletedFiles(accountInfo, differencer.Deleted, pollTime);
246
                        ProcessDeletedFiles(accountInfo, differencer.Deleted.FilterBelow(SelectiveUris), pollTime);
247

  
248
                        // @@@ NEED To add previous state here as well, To compare with previous hash
249

  
250
                        
246 251

  
247 252
                        //Create a list of actions from the remote files
248
                        var allActions = ChangesToActions(accountInfo, differencer.Changed)
253
                        var allActions = ChangesToActions(accountInfo, differencer.Changed.FilterBelow(SelectiveUris))
249 254
                                        .Union(
250
                                        CreatesToActions(accountInfo, differencer.Created));
255
                                        CreatesToActions(accountInfo, differencer.Created.FilterBelow(SelectiveUris)));
251 256

  
252 257
                        //And remove those that are already being processed by the agent
253 258
                        var distinctActions = allActions
......
275 280
        }
276 281

  
277 282
        AccountsDifferencer _differencer = new AccountsDifferencer();
283
        private List<Uri> _selectiveUris=new List<Uri>();
278 284

  
279 285
        /// <summary>
280 286
        /// Deletes local files that are not found in the list of cloud files
......
451 457
                Directory.CreateDirectory(path);
452 458
            }
453 459
        }
460

  
461
        public void SetSyncUris(string[] uris)
462
        {
463
            var selectiveUris = uris.Select(uri => new Uri(uri));
464
            SelectiveUris=selectiveUris.ToList();
465
        }
466

  
467
        protected List<Uri> SelectiveUris
468
        {
469
            get { return _selectiveUris;}
470
            set { _selectiveUris = value; }
471
        }
454 472
    }
455 473
}
b/trunk/Pithos.Core/FileState.cs
44 44
using System.Threading.Tasks;
45 45
using Castle.ActiveRecord;
46 46
using Castle.ActiveRecord.Framework;
47
using Castle.ActiveRecord.Queries;
48
using NHibernate.Criterion;
47 49
using Pithos.Core.Agents;
48 50
using Pithos.Interfaces;
49 51
using Pithos.Network;
......
417 419
                        throw;
418 420
                }
419 421
        }
422

  
423
        public static void RemovePaths(IEnumerable<string> removed)
424
        {
425
            
426
            var disjunction = new Disjunction();
427

  
428
            foreach (var path in removed)
429
            {
430
                disjunction.Add(Restrictions.On<FileState>(s => s.FilePath).IsLike(path, MatchMode.Start));
431
            }
432

  
433
            
434
            
435
            var query=QueryOver.Of<FileState>().Where(disjunction);
436
            var aq = new ProjectionQuery<FileState,Guid>(query.DetachedCriteria,
437
                        Projections.ProjectionList().Add(Projections.Id()));
438
            var ids=aq.Execute();
439
            FileState.DeleteAll(ids);
440
                
441
        }
420 442
    }
421 443

  
422 444
    [ActiveRecord("Tags")]
b/trunk/Pithos.Core/PithosMonitor.cs
238 238
            
239 239
            StatusKeeper.StartProcessing(_cancellationSource.Token);
240 240
            IndexLocalFiles();
241
            //Extract the URIs from the string collection
242
            var settings = Settings.Accounts.First(s => s.AccountName == _accountInfo.UserName);
243
            var selectiveUrls=new string[settings.SelectiveFolders.Count];
244
            settings.SelectiveFolders.CopyTo(selectiveUrls,0);
245

  
246
            SetSelectivePaths(selectiveUrls,null,null);
247
            
241 248
            StartWatcherAgent();
242 249

  
243 250
            StartNetworkAgent();
......
468 475
            StatusKeeper.ChangeRoots(oldPath, newPath);
469 476
        }
470 477

  
471
        public void AddSelectivePaths(string[] added)
478
        public void SetSelectivePaths(string[] uris,string[] added, string[] removed)
472 479
        {
473
           /* FileAgent.SelectivePaths.AddRange(added);
474
            NetworkAgent.SyncPaths(added);*/
480
            //Convert the uris to paths
481
            var selectivePaths = (from string selectiveUrl in uris
482
                                    select new Uri(selectiveUrl)
483
                                    .MakeRelativeUri(_accountInfo.StorageUri)
484
                                    .RelativeUriToFilePath());
485

  
486
            FileAgent.SelectivePaths=selectivePaths.ToList();
487
            PollAgent.SetSyncUris(uris);
488
            RemoveSelectivePaths(removed);
489

  
475 490
        }
476 491

  
477
        public void RemoveSelectivePaths(string[] removed)
492
        /// <summary>
493
        /// Delete the folders that were removed from synchronization
494
        /// </summary>
495
        /// <param name="removed"></param>
496
        private void RemoveSelectivePaths(IEnumerable<string> removed)
478 497
        {
479
            FileAgent.SelectivePaths.RemoveAll(removed.Contains);
498
            if (removed == null)
499
                return;
500

  
480 501
            foreach (var removedPath in removed.Where(Directory.Exists))
481 502
            {
482 503
                Directory.Delete(removedPath,true);
483 504
            }
484
        }
485 505

  
486
        public IEnumerable<ObjectInfo> GetRootFolders()
487
        {
488
            var dirs = from container in CloudClient.ListContainers(UserName)
489
                       from dir in CloudClient.ListObjects(UserName, container.Name, "")
490
                       where dir.Content_Type=="application/directory"                       
491
                       select dir;
492
            return dirs;
506
            //Ensure we remove any file state below the deleted folders
507
            FileState.RemovePaths(removed);
493 508
        }
494 509

  
495 510
        public ObjectInfo GetObjectInfo(string filePath)
b/trunk/Pithos.Interfaces/IPithosSettings.cs
76 76
        bool ExtensionsActivated { get; set; }
77 77

  
78 78
        int PollingInterval { get; set; }
79
        TimeSpan StartupDelay { get; set; }
79 80
        byte HashingParallelism { get; set; }
80 81

  
81 82
        void Save();
b/trunk/Pithos.Interfaces/ObjectInfo.cs
127 127

  
128 128
        public Stream Stream { get; set; }
129 129

  
130

  
131
        public Uri StorageUri { get; set; }
132

  
130 133
        public string Account { get; set; }
131 134

  
132 135
        public string Container { get; set; }
133 136

  
137
        public Uri Uri
138
        {
139
            get
140
            {
141
                var relativeUrl=String.Format("{0}/{1}/{2}",Account, Container,Name);
142
                return new Uri(StorageUri,relativeUrl);
143
            }
144
        }
145

  
134 146
        public string ContendDisposition { get; set; }
135 147

  
136 148
        public string ContentEncoding { get; set; }
......
223 235
            Last_Modified = DateTime.MinValue
224 236
        };
225 237

  
238
        
239

  
226 240
        public string RelativeUrlToFilePath(string currentAccount)
227 241
        {
228 242
            if (Name==null)
b/trunk/Pithos.Interfaces/PithosSettingsData.cs
69 69
        public string ProxyDomain { get; set; }
70 70
        public bool ProxyAuthentication { get; set; }
71 71
        public bool ExtensionsActivated { get; set; }
72
        public TimeSpan StartupDelay { get; set; }
72 73
        public int PollingInterval { get; set; }
73 74
        public byte HashingParallelism { get; set; }
74 75

  
......
98 99
            ProxyAuthentication = other.ProxyAuthentication;
99 100
            ExtensionsActivated = other.ExtensionsActivated;
100 101
            PollingInterval = other.PollingInterval;
102
            StartupDelay = other.StartupDelay;
101 103
        }
102 104

  
103 105
        public virtual void Save()
b/trunk/Pithos.Network/CloudFilesClient.cs
613 613
                    {
614 614
                        info.Container = container;
615 615
                        info.Account = account;
616
                        info.StorageUri = this.StorageUrl;
616 617
                    }
617 618
                    if (Log.IsDebugEnabled) Log.DebugFormat("START");
618 619
                    return infos;
......
652 653
                    foreach (var info in infos)
653 654
                    {
654 655
                        info.Account = account;
656
                        if (info.Container == null)
657
                            info.Container = container;
658
                        info.StorageUri = this.StorageUrl;
655 659
                    }
656 660
                    if (Log.IsDebugEnabled) Log.DebugFormat("END");
657 661
                    return infos;
b/trunk/Pithos.Network/ICloudClient.cs
105 105
        void UpdateMetadata(ObjectInfo objectInfo);
106 106

  
107 107
        void UpdateMetadata(ContainerInfo Container);
108
        IList<ShareAccountInfo> ListSharingAccounts(DateTime? since=null);
108 109
    }
109 110

  
110 111

  
......
183 184
            return ;
184 185
        }
185 186

  
187
        public IList<ShareAccountInfo> ListSharingAccounts(DateTime? since = new DateTime?())
188
        {
189
            return default(IList<ShareAccountInfo>);
190
        }
191

  
186 192

  
187 193
        public IList<ObjectInfo> ListObjects(string account, string container, DateTime? since = null)
188 194
        {
b/trunk/Pithos.Setup.x64/Pithos.Setup.x64.vdproj
1249 1249
                {
1250 1250
                    "{9EF0B969-E518-4E46-987F-47570745A589}:_FE8EA18DF1CB49179367FE453762E9B5"
1251 1251
                    {
1252
                    "Name" = "8:GRNet"
1252
                    "Name" = "8:GRNET"
1253 1253
                    "AlwaysCreate" = "11:FALSE"
1254 1254
                    "Condition" = "8:"
1255 1255
                    "Transitive" = "11:FALSE"
......
1310 1310
        {
1311 1311
        "Name" = "8:Microsoft Visual Studio"
1312 1312
        "ProductName" = "8:Pithos"
1313
        "ProductCode" = "8:{0558EE1F-65D8-4046-BAF8-EA9325EA6DC1}"
1314
        "PackageCode" = "8:{16F5A9E8-D797-4CD0-AC72-FA6C6AAAAE62}"
1313
        "ProductCode" = "8:{97C4606C-02B7-4E94-900F-D2654110B39B}"
1314
        "PackageCode" = "8:{07D12433-2FB8-4BCF-839A-02AD31A2C208}"
1315 1315
        "UpgradeCode" = "8:{205365D1-28AA-4322-A46C-FCB37502C6EF}"
1316 1316
        "AspNetVersion" = "8:4.0.30319.0"
1317 1317
        "RestartWWWService" = "11:FALSE"
1318 1318
        "RemovePreviousVersions" = "11:TRUE"
1319 1319
        "DetectNewerInstalledVersion" = "11:TRUE"
1320 1320
        "InstallAllUsers" = "11:FALSE"
1321
        "ProductVersion" = "8:1.0.0"
1321
        "ProductVersion" = "8:0.7.0"
1322 1322
        "Manufacturer" = "8:GRNET"
1323 1323
        "ARPHELPTELEPHONE" = "8:"
1324 1324
        "ARPHELPLINK" = "8:http://code.grnet.gr/projects/pithos-ms-client"
b/trunk/Pithos.Setup.x86/Pithos.Setup.x86.vdproj
1260 1260
                {
1261 1261
                    "{9EF0B969-E518-4E46-987F-47570745A589}:_9ED8CC47C48243A0B5686A7CE582CDA3"
1262 1262
                    {
1263
                    "Name" = "8:GRNet"
1263
                    "Name" = "8:GRNET"
1264 1264
                    "AlwaysCreate" = "11:FALSE"
1265 1265
                    "Condition" = "8:"
1266 1266
                    "Transitive" = "11:FALSE"
......
1310 1310
        {
1311 1311
        "Name" = "8:Microsoft Visual Studio"
1312 1312
        "ProductName" = "8:Pithos"
1313
        "ProductCode" = "8:{0558EE1F-65D8-4046-BAF8-EA9325EA6DC1}"
1314
        "PackageCode" = "8:{AD4F4E20-3B8F-470F-95FC-E409BC75DA20}"
1313
        "ProductCode" = "8:{4CB9D42B-6B18-4E6F-9DCE-4D7E57E562C2}"
1314
        "PackageCode" = "8:{FDC63D9F-C81B-45F7-8C6E-16DB523137E2}"
1315 1315
        "UpgradeCode" = "8:{205365D1-28AA-4322-A46C-FCB37502C6EF}"
1316 1316
        "AspNetVersion" = "8:4.0.30319.0"
1317 1317
        "RestartWWWService" = "11:FALSE"
1318 1318
        "RemovePreviousVersions" = "11:TRUE"
1319 1319
        "DetectNewerInstalledVersion" = "11:TRUE"
1320 1320
        "InstallAllUsers" = "11:FALSE"
1321
        "ProductVersion" = "8:1.0.0"
1321
        "ProductVersion" = "8:0.7.0"
1322 1322
        "Manufacturer" = "8:GRNET"
1323 1323
        "ARPHELPTELEPHONE" = "8:"
1324 1324
        "ARPHELPLINK" = "8:http://code.grnet.gr/projects/pithos-ms-client"
b/trunk/Pithos.ShellExtensions.Test/TestPithosSettings.cs
56 56

  
57 57
        public byte HashingParallelism{get; set; }
58 58

  
59
        public TimeSpan StartupDelay { get; set; }
60

  
59 61
        public void Save()
60 62
        {
61 63
            
b/trunk/Pithos.ShellExtensions/ShellSettings.cs
172 172
            set { _settings.Value.PollingInterval = value; }
173 173
        }
174 174

  
175
        public TimeSpan StartupDelay
176
        {
177
            get { return _settings.Value.StartupDelay; }
178
            set { _settings.Value.StartupDelay = value; }
179
        }
180

  
175 181
        public byte HashingParallelism
176 182
        {
177 183
            get { return _settings.Value.HashingParallelism; }
b/trunk/Pithos.ShellExtensions/TestPithosSettings.cs
94 94
        public int PollingInterval { get; set; }
95 95

  
96 96
        public byte HashingParallelism { get; set; }
97

  
97
        public TimeSpan StartupDelay { get; set; }
98 98

  
99 99
        public bool ProxyAuthentication { get; set; }
100 100
        public void Save()

Also available in: Unified diff