Revision 7b0a5fec

b/trunk/Pithos.Client.WPF/FileProperties/FilePropertiesView.xaml
1
<UserControl x:Class="Pithos.Client.WPF.FilePropertiesView"
1
<Window x:Class="Pithos.Client.WPF.FilePropertiesView"
2 2
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 3
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 4
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
5 5
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
6 6
             mc:Ignorable="d" 
7
             d:DesignHeight="300" d:DesignWidth="300">
7
             d:DesignHeight="300" d:DesignWidth="300"
8
        Background="#FFD4D0C8" Height="481">
9
    <Window.Resources>
10
        <ResourceDictionary>
11
            <ResourceDictionary.MergedDictionaries>
12
                <ResourceDictionary Source="..\PithosStyles.xaml" />
13
            </ResourceDictionary.MergedDictionaries>
14
        </ResourceDictionary>       
15
    </Window.Resources>
8 16
    <Grid>
9
            
17
        <Grid.RowDefinitions>
18
            <RowDefinition Height="Auto"/>
19
            <RowDefinition Height="Auto"/>
20
            <RowDefinition Height="*"/>
21
            <RowDefinition Height="Auto"/>
22
        </Grid.RowDefinitions>
23

  
24
        <Grid Grid.Row="0">
25
            <Grid.ColumnDefinitions>
26
                <ColumnDefinition Width="Auto"/>
27
                <ColumnDefinition Width="*"/>
28
                <ColumnDefinition Width="Auto"/>
29
            </Grid.ColumnDefinitions>
30
            <Image x:Name="FileIcon" Width="48" Height="48" Margin="5" Grid.Column="0" Stretch="None"/>
31
            <StackPanel Margin="5" Grid.Column="1">
32
                <TextBlock x:Name="FileName" Grid.Row="0" Text="File Name" FontSize="16" FontWeight="Bold"/>
33
                <StackPanel Orientation="Horizontal" Grid.Row="1">
34
                    <TextBlock Text="Container: " />
35
                    <TextBlock x:Name="Container" Text="Container" />
36
                </StackPanel>
37
            </StackPanel>
38
            <TextBlock x:Name="ShortSize" Text="345 KB" FontWeight="Bold" FontSize="14" Grid.Column="2" />
39
        </Grid>
40
        <GroupBox Header="General" Grid.Row="1">
41
            <Grid>
42
                <Grid.Resources>
43
                    <Style x:Key="NameColumnStyle" TargetType="TextBlock">
44
                        <Setter Property="HorizontalAlignment" Value="Right"/>
45
                        <Setter Property="Margin" Value="5,2"/>
46
                    </Style>
47
                    <Style x:Key="ValueColumnStyle" TargetType="TextBlock">
48
                        <Setter Property="HorizontalAlignment" Value="Left"/>
49
                        <Setter Property="Margin" Value="5,2"/>
50
                    </Style>
51
                </Grid.Resources>
52
                <Grid.ColumnDefinitions>
53
                    <ColumnDefinition Width="Auto" />
54
                    <ColumnDefinition Width="*"/>
55
                </Grid.ColumnDefinitions>
56
                <Grid.RowDefinitions>
57
                    <RowDefinition/>
58
                    <RowDefinition/>
59
                    <RowDefinition/>
60
                    <RowDefinition/>
61
                    <RowDefinition/>
62
                    <RowDefinition/>
63
                </Grid.RowDefinitions>
64
                <TextBlock Text="Kind :" Grid.Row="0" Grid.Column="0" Style="{StaticResource ResourceKey=NameColumnStyle}"/>
65
                <TextBlock Text="Size :" Grid.Row="1" Grid.Column="0" Style="{StaticResource ResourceKey=NameColumnStyle}"/>
66
                <TextBlock Text="Where :" Grid.Row="2" Grid.Column="0" Style="{StaticResource ResourceKey=NameColumnStyle}"/>
67
                <TextBlock Text="Modified :" Grid.Row="3" Grid.Column="0" Style="{StaticResource ResourceKey=NameColumnStyle}"/>
68
                <TextBlock Text="Modified By :" Grid.Row="4" Grid.Column="0" Style="{StaticResource ResourceKey=NameColumnStyle}"/>
69
                <TextBlock Text="Version :" Grid.Row="5" Grid.Column="0" Style="{StaticResource ResourceKey=NameColumnStyle}"/>
70
                <TextBlock x:Name="Kind" Text="application/pdf" Grid.Row="0" Grid.Column="1" Style="{StaticResource ResourceKey=ValueColumnStyle}"/>
71
                <TextBlock x:Name="Size" Text="345 KB (345,332 bytes)" Grid.Row="1" Grid.Column="1" Style="{StaticResource ResourceKey=ValueColumnStyle}"/>
72
                <TextBlock x:Name="Where" Text="pithos/somefile.pdf" Grid.Row="2" Grid.Column="1" Style="{StaticResource ResourceKey=ValueColumnStyle}"/>
73
                <TextBlock x:Name="Modified" Text="28/10/2011 11:34 AM" Grid.Row="3" Grid.Column="1" Style="{StaticResource ResourceKey=ValueColumnStyle}"/>
74
                <TextBlock x:Name="ModifiedBy" Text="SomeUser" Grid.Row="4" Grid.Column="1" Style="{StaticResource ResourceKey=ValueColumnStyle}"/>
75
                <TextBlock x:Name="Version" Text="2345456" Grid.Row="5" Grid.Column="1" Style="{StaticResource ResourceKey=ValueColumnStyle}"/>
76
            </Grid>
77
        </GroupBox>
78
        <GroupBox Header="Metadata" Grid.Row="2" >
79
            <ListView x:Name="GeneralProperties">
80
                <ListView.View>
81
                    <GridView>
82
                        <GridViewColumn  >
83
                            <GridViewColumn.CellTemplate>
84
                                <DataTemplate>
85
                                    <Button Content="-" Width="20"/>
86
                                </DataTemplate>
87
                            </GridViewColumn.CellTemplate>
88
                        </GridViewColumn>
89
                        <GridViewColumn Header="Name"/>
90
                        <GridViewColumn Header="Value" />                
91
                </GridView>
92
            </ListView.View>
93
                <ListViewItem Content="Moo">                                        
94
                </ListViewItem>
95
            </ListView>
96
        </GroupBox>
97
        <StackPanel Orientation="Horizontal" Grid.Row="3" HorizontalAlignment="Right">
98
            <Button Name="SaveChanges" Content="OK" Margin="5,5,10,5" Style="{StaticResource ButtonStyle}"/>
99
            <Button Name="RejectChanges" Content="Cancel" Margin="5,5,10,5" Style="{StaticResource ButtonStyle}"/>
100
            <Button Name="ApplyChanges" Content="Apply" Style="{StaticResource ButtonStyle}" />
101
        </StackPanel>
102

  
10 103
    </Grid>
11
</UserControl>
104
</Window>
b/trunk/Pithos.Client.WPF/FileProperties/FilePropertiesView.xaml.cs
17 17
    /// <summary>
18 18
    /// Interaction logic for FilePropertiesView.xaml
19 19
    /// </summary>
20
    public partial class FilePropertiesView : UserControl
20
    public partial class FilePropertiesView : Window
21 21
    {
22 22
        public FilePropertiesView()
23 23
        {
b/trunk/Pithos.Client.WPF/FileProperties/FilePropertiesViewModel.cs
4 4
// </copyright>
5 5
// -----------------------------------------------------------------------
6 6

  
7
using System.Collections;
7 8
using System.Collections.Concurrent;
8 9
using System.Collections.ObjectModel;
9 10
using System.ComponentModel.Composition;
11
using System.Diagnostics;
12
using System.Diagnostics.Contracts;
13
using System.Drawing;
14
using System.Windows;
15
using System.Windows.Interop;
16
using System.Windows.Media.Imaging;
10 17
using Caliburn.Micro;
11 18
using Pithos.Interfaces;
12 19

  
......
23 30
    [Export(typeof(FilePropertiesViewModel))]
24 31
    public class FilePropertiesViewModel : Screen, IShell
25 32
    {
33
        private string _title;
34
        public string Title
35
        {
36
            get { return _title; }
37
            set
38
            {
39
                _title = value;
40
                NotifyOfPropertyChange(()=>Title);
41
            }
42
        }
43

  
44
        public string Kind { get; set; }
45
        public string Size { get; set; }
46
        public string ShortSize { get; set; }
47
        public string Where { get; set; }
48
        public DateTime Modified { get; set; }
49
        public string ModifiedBy { get; set; }
50
        public long Version { get; set; }
51
        protected string LocalFileName { get; set; }
52
        public BitmapSource FileIcon { get; set; }
26 53

  
27
        public FilePropertiesViewModel(ShellViewModel shell,ObjectInfo pithosFile)
54
        public string FileName { get; set; }
55
        public string Container { get; set; }
56

  
57
        public FilePropertiesViewModel(ShellViewModel shell,ObjectInfo pithosFile,string localFileName)
28 58
        {
59
            if (shell==null)
60
                throw new ArgumentNullException("shell");
61
            if (pithosFile==null)
62
                throw new ArgumentNullException("pithosFile");
63
            if (String.IsNullOrWhiteSpace(localFileName))
64
                throw new ArgumentNullException("localFileName");
65
            Contract.EndContractBlock();
66

  
29 67
            Shell = shell;
68
            LocalFileName = localFileName;
30 69
            PithosFile = pithosFile;
70
            Title = String.Format("{0} Properties", pithosFile.Name);
31 71
        }
32 72

  
73

  
33 74
        protected ShellViewModel Shell { get; set; }
34 75

  
35 76
        private ObjectInfo _pithosFile;
......
40 81
            {
41 82
                _pithosFile = value;
42 83
                
84
                if (Permissions!=null)
85
                    ((IDictionary<string,string>)Permissions).Clear();                
86
                value.Permissions.Apply(perm=>Permissions.Add(perm.Key,perm.Value));
87
                Kind=value.Content_Type;
88
                ShortSize = ByteSize(value.Bytes);
89
                Size = String.Format("{0} ({1:N0} bytes)", ShortSize, value.Bytes);
90
                Where = Uri.UnescapeDataString(value.Name);
91
                FileName = Uri.UnescapeDataString(value.Name.Split('/').Last());
92
                Container = value.Container;
93
                Modified = value.Last_Modified;
94
                ModifiedBy = value.ModifiedBy;
95
                Version = value.Version??0;
96

  
97
                using (var icon = Icon.ExtractAssociatedIcon(LocalFileName))
98
                {
99
                    FileIcon = Imaging.CreateBitmapSourceFromHIcon(icon.Handle, Int32Rect.Empty,
100
                                                                   BitmapSizeOptions.FromEmptyOptions());
101
                }
43 102
                NotifyOfPropertyChange(()=>PithosFile);
44 103
            }
45 104
        }
105
        
106

  
46 107

  
47 108
        private ObservableConcurrentDictionary<string, string> _permissions;
48 109
        public ObservableConcurrentDictionary<string, string> Permissions
......
57 118

  
58 119
        public void Refresh()
59 120
        {
60
            PithosFile=Shell.RetrieveObjectInfo(PithosFile);
121
            PithosFile=Shell.RefreshObjectInfo(PithosFile);
61 122
        }
62 123

  
63 124
        public override void CanClose(Action<bool> callback)
......
68 129
        public void SaveChanges()
69 130
        {
70 131
            DoSave();
71
            TryClose(true);
132
            TryClose();
72 133
        }
73 134

  
74 135
        public void RejectChanges()
75 136
        {
76
            TryClose(false);
137
            TryClose();
77 138
        }
78 139

  
79 140
        public void ApplyChanges()
......
86 147
            
87 148
        }
88 149

  
150
        static string[] sizeSuffixes = { 
151
        "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
152

  
153
        public string ByteSize(long size)
154
        {
155
            
156
            const string formatTemplate = "{0}{1:0.#} {2}";
157

  
158
            if (size == 0)
159
            {
160
                return string.Format(formatTemplate, null, 0, sizeSuffixes[0]);
161
            }
162

  
163
            var absSize = Math.Abs((double)size);
164
            var fpPower = Math.Log(absSize, 1000);
165
            var intPower = (int)fpPower;
166
            var iUnit = intPower >= sizeSuffixes.Length
167
                ? sizeSuffixes.Length - 1
168
                : intPower;
169
            var normSize = absSize / Math.Pow(1000, iUnit);
170

  
171
            return string.Format(
172
                formatTemplate,
173
                size < 0 ? "-" : null, normSize, sizeSuffixes[iUnit]);
174
        } 
175

  
176

  
89 177
    }
90 178
}
b/trunk/Pithos.Client.WPF/ShellView.xaml
70 70
                    <Separator  />
71 71
                    <MenuItem  Header="Preferences ..." x:Name="ShowPreferences" cal:Message.Attach="ShowPreferences"  />
72 72
                    <Separator  />
73
                    <MenuItem  Header="Properties ..." x:Name="ShowFileProperties" cal:Message.Attach="ShowFileProperties"  />
74
                    <Separator  />
73 75
                    <MenuItem  Header="Exit" Name="ExitPithos" cal:Message.Attach="ExitPithos" />
74 76
                </ContextMenu>
75 77
            </tb:TaskbarIcon.ContextMenu>
b/trunk/Pithos.Client.WPF/ShellViewModel.cs
27 27
    using System.ComponentModel.Composition;
28 28

  
29 29
    [Export(typeof(IShell))]
30
    public class ShellViewModel : ViewAware, IStatusNotification, IShell, 
30
    public class ShellViewModel : Screen, IStatusNotification, IShell, 
31 31
        IHandle<Notification>, IHandle<SelectiveSynchChanges>
32 32
    {
33 33
       
......
65 65

  
66 66
                StatusMessage = "In Synch";
67 67

  
68
                foreach (var account in settings.Accounts)
69
                {
70

  
71
                    MonitorAccount(account);
72
                }
73

  
74
                StartStatusService();
75 68
            }
76 69
            catch (Exception exc)
77 70
            {
......
79 72
                throw;
80 73
            }
81 74
        }
82
        
83 75

  
84
        
76
        protected override void OnActivate()
77
        {
78
            base.OnActivate();
79
            foreach (var account in Settings.Accounts)
80
            {
81

  
82
                MonitorAccount(account);
83
            }
84

  
85
            StartStatusService();
86
        }
87

  
85 88
        public void MonitorAccount(AccountSettings account)
86 89
        {
87 90
            Task.Factory.StartNew(() =>
......
105 108
                    return;
106 109
                }
107 110

  
108
                //PithosMonitor uses MEF so we need to resolve it
111
                //Create a new monitor/ Can't use MEF here, it would return a single instance for all monitors
109 112
                monitor = new PithosMonitor
110
                            {
111
                                UserName = accountName,
112
                                ApiKey = account.ApiKey,
113
                                UsePithos = account.UsePithos,
114
                                StatusNotification = this,
115
                                RootPath = account.RootPath
116
                            };
113
                              {
114
                                  UserName = accountName,
115
                                  ApiKey = account.ApiKey,
116
                                  UsePithos = account.UsePithos,
117
                                  StatusNotification = this,
118
                                  RootPath = account.RootPath
119
                              };
120
                //PithosMonitor uses MEF so we need to resolve it
117 121
                IoC.BuildUp(monitor);
118 122

  
119 123
                var appSettings = Properties.Settings.Default;
......
221 225
            Process.Start(account.AccountPath);
222 226
        }
223 227

  
224
        public void GoToSite()
225
        {
226
            
227
        }
228

  
228
        
229 229
        public void GoToSite(AccountInfo account)
230 230
        {
231 231
            var site = String.Format("{0}/ui/?token={1}&user={2}",
......
234 234
            Process.Start(site);
235 235
        }
236 236

  
237
        public void ShowFileProperties()
238
        {
239
            var account = Settings.Accounts.First(acc => acc.IsActive);            
240
            var dir = new DirectoryInfo(account.RootPath + @"\pithos");
241
            var files=dir.GetFiles();
242
            var r=new Random();
243
            var idx=r.Next(0, files.Length);
244
            ShowFileProperties(files[idx].FullName);            
245
        }
246

  
247
        public void ShowFileProperties(string filePath)
248
        {
249
            if (String.IsNullOrWhiteSpace(filePath))
250
                throw new ArgumentNullException("filePath");
251
            if (!File.Exists(filePath))
252
                throw new ArgumentException(String.Format("Non existent file {0}",filePath),"filePath");
253
            Contract.EndContractBlock();
254

  
255
            var pair=(from monitor in  Monitors
256
                               where filePath.StartsWith(monitor.Value.RootPath, StringComparison.InvariantCultureIgnoreCase)
257
                                   select monitor).FirstOrDefault();
258
            var account = pair.Key;
259
            var accountMonitor = pair.Value;
260

  
261
            ObjectInfo info = accountMonitor.GetObjectInfo(filePath);
262

  
263
            
264

  
265
            var fileProperties = new FilePropertiesViewModel(this, info,filePath);
266
            _windowManager.ShowWindow(fileProperties);
267
        }
268

  
269
        public ObjectInfo RefreshObjectInfo(ObjectInfo currentInfo)
270
        {
271
            if (currentInfo==null)
272
                throw new ArgumentNullException("currentInfo");
273
            Contract.EndContractBlock();
274

  
275
            var monitor = Monitors[currentInfo.Account];
276
            var newInfo=monitor.CloudClient.GetObjectInfo(currentInfo.Account, currentInfo.Container, currentInfo.Name);
277
            return newInfo;
278
        }
237 279

  
238 280
        public void ToggleSynching()
239 281
        {
b/trunk/Pithos.Core.Test/EnumerableExtensionsTest.cs
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Text;
5
using NUnit.Framework;
6

  
7
namespace Pithos.Core.Test
8
{
9
    [TestFixture]
10
    public class EnumerableExtensionsTest
11
    {
12
        [Test]
13
        public void TestSplice()
14
        {
15
            string[] twoElems= {"one","two"};
16
            var result=twoElems.Splice(1);
17
            Assert.AreEqual(1,result.Count());
18
            
19
            result=twoElems.Splice(0);
20
            Assert.AreEqual(2,result.Count());
21
        }
22

  
23
        [Test]
24
        public void TestSpliceEmpty()
25
        {
26
            string[] empty= {};
27
            var result=empty.Splice(1);
28
            Assert.AreEqual(0,result.Count());
29
            
30
            result=empty.Splice(0);
31
            Assert.AreEqual(0,result.Count());
32
        }
33
    }
34
}
b/trunk/Pithos.Core.Test/Pithos.Core.Test.csproj
123 123
    <Reference Include="System.Xml" />
124 124
  </ItemGroup>
125 125
  <ItemGroup>
126
    <Compile Include="EnumerableExtensionsTest.cs" />
126 127
    <Compile Include="NetworkAgentTest.cs" />
127 128
    <Compile Include="PithosWorkflowTest.cs" />
128 129
    <Compile Include="Properties\AssemblyInfo.cs" />
b/trunk/Pithos.Core/Agents/NetworkAgent.cs
832 832
                var parts=relativePath.Split('\\');
833 833
                var accountName = parts[1];
834 834
                var oldName = accountInfo.UserName;
835
                   var absoluteUri = accountInfo.StorageUri.AbsoluteUri;
835
                var absoluteUri = accountInfo.StorageUri.AbsoluteUri;
836 836
                var nameIndex=absoluteUri.IndexOf(oldName);
837 837
                var root=absoluteUri.Substring(0, nameIndex);
838 838

  
b/trunk/Pithos.Core/EnumerableExtensions.cs
1
using System;
2
using System.Collections.Generic;
3
using System.Diagnostics.Contracts;
4
using System.Linq;
5
using System.Text;
6

  
7
namespace Pithos.Core
8
{
9
    public static class EnumerableExtensions
10
    {
11
        public static IEnumerable<T> Splice<T>(this IList<T> array,int startIndex,int endIndex=-1)
12
        {
13
            if (array==null)
14
                throw new ArgumentNullException("array");
15
            if (startIndex<0)
16
                throw new ArgumentOutOfRangeException("startIndex");            
17
            Contract.EndContractBlock();
18

  
19
            if (startIndex>=array.Count)
20
                yield break;
21

  
22
            if (endIndex == -1)
23
                endIndex = array.Count;
24
            for (var i = startIndex; i < endIndex; i++)
25
                yield return array[i];
26
        }
27
    }
28
}
b/trunk/Pithos.Core/Pithos.Core.csproj
194 194
    <Compile Include="Agents\NetworkAgent.cs" />
195 195
    <Compile Include="Agents\WorkflowAgent.cs" />
196 196
    <Compile Include="DynamicDictionary.cs" />
197
    <Compile Include="EnumerableExtensions.cs" />
197 198
    <Compile Include="FileHashMap.cs" />
198 199
    <Compile Include="FileState.cs" />
199 200
    <Compile Include="IStatusService.cs" />
b/trunk/Pithos.Core/PithosMonitor.cs
412 412
                       select dir.Name;
413 413
            return dirs;
414 414
        }
415

  
416
        public ObjectInfo GetObjectInfo(string filePath)
417
        {
418
            if (String.IsNullOrWhiteSpace(filePath))
419
                throw new ArgumentNullException("filePath");
420
            Contract.EndContractBlock();
421

  
422
            var file=new FileInfo(filePath);
423
            string relativeUrl;//=file.AsRelativeUrlTo(this.RootPath);
424
            var relativePath = file.AsRelativeTo(RootPath);
425
            
426
            string accountName,container;
427
            
428
            var parts=relativePath.Split('\\');
429

  
430
            var accountInfo = _accountInfo;
431
            if (relativePath.StartsWith(FolderConstants.OthersFolder))
432
            {                
433
                accountName = parts[1];
434
                container = parts[2];
435
                relativeUrl = String.Join("/", parts.Splice(3));
436
                //Create the root URL for the target account
437
                var oldName = UserName;
438
                var absoluteUri =  _accountInfo.StorageUri.AbsoluteUri;
439
                var nameIndex=absoluteUri.IndexOf(oldName);
440
                var root=absoluteUri.Substring(0, nameIndex);
441

  
442
                accountInfo = new AccountInfo
443
                {
444
                    UserName = accountName,
445
                    AccountPath = Path.Combine(accountInfo.AccountPath, parts[0], parts[1]),
446
                    StorageUri = new Uri(root + accountName),
447
                    BlockHash=accountInfo.BlockHash,
448
                    BlockSize=accountInfo.BlockSize,
449
                    Token=accountInfo.Token
450
                };
451
            }
452
            else
453
            {
454
                accountName = this.UserName;
455
                container = parts[0];
456
                relativeUrl = String.Join("/", parts.Splice(1));
457
            }
458

  
459
            /*return new ObjectInfo
460
                       {
461
                           Account = accountName,
462
                           Container = container,
463
                           Name = relativeUrl,
464
                           Content_Type="application/pdf",
465
                           Bytes = 123456,
466
                           Hash = "8902372934sjhshjfsdjkf223894sdgh",
467
                           Last_Modified = DateTime.Today.AddDays(-1),
468
                           ModifiedBy = accountName,
469
                           Version = 12312455,
470
                           VersionTimestamp = DateTime.Today.AddDays(-1)
471
                       };*/
472

  
473
            var client = new CloudFilesClient(accountInfo);
474
            var objectInfo=client.GetObjectInfo(accountName, container, relativeUrl);
475
            return objectInfo;
476
        }
415 477
    }
416 478

  
417 479

  
b/trunk/Pithos.Network/CloudFilesClient.cs
537 537
                                    .ToDictionary(t => t.Name, t => t.Value);
538 538
                                var info = new ObjectInfo
539 539
                                               {
540
                                                   Account = account,
541
                                                   Container = container,
540 542
                                                   Name = objectName,
541 543
                                                   Hash = client.GetHeaderValue("ETag"),
542 544
                                                   Content_Type = client.GetHeaderValue("Content-Type"),
545
                                                   Bytes = Convert.ToInt64(client.GetHeaderValue("Content-Length")),
543 546
                                                   Tags = tags,
544 547
                                                   Last_Modified = client.LastModified,
545 548
                                                   Extensions = extensions

Also available in: Unified diff