Revision aba9e6d9
b/trunk/Pithos.Client.WPF/AppBootstrapper.cs | ||
---|---|---|
3 | 3 |
using System.Windows.Navigation; |
4 | 4 |
using Caliburn.Micro; |
5 | 5 |
using Caliburn.Micro.Logging; |
6 |
using Pithos.Client.WPF.Properties; |
|
6 | 7 |
using Pithos.Core; |
7 | 8 |
using Pithos.Network; |
8 | 9 |
using log4net.Appender; |
... | ... | |
27 | 28 |
public AppBootstrapper() |
28 | 29 |
{ |
29 | 30 |
LogManager.GetLog = type => new log4netLogger(type); |
31 |
UpgradeSettings(); |
|
30 | 32 |
} |
31 | 33 |
|
32 |
/// <summary> |
|
34 |
private void UpgradeSettings() |
|
35 |
{ |
|
36 |
if (Settings.Default.MustUpgrade) |
|
37 |
{ |
|
38 |
Settings.Default.Upgrade(); |
|
39 |
Settings.Default.MustUpgrade = false; |
|
40 |
Settings.Default.Save(); |
|
41 |
} |
|
42 |
} |
|
43 |
|
|
44 |
/// <summary> |
|
33 | 45 |
/// By default, we are configured to use MEF |
34 | 46 |
/// </summary> |
35 | 47 |
protected override void Configure() { |
b/trunk/Pithos.Client.WPF/Converters/EmptyToVisibilityConverter.cs | ||
---|---|---|
9 | 9 |
namespace Pithos.Client.WPF.Converters |
10 | 10 |
{ |
11 | 11 |
/// <summary> |
12 |
/// Returns Visible if a string value contains data, Hidden otherwise
|
|
12 |
/// Returns Visible if a string value contains data, Collapsed otherwise
|
|
13 | 13 |
/// </summary> |
14 | 14 |
public class EmptyToVisibilityConverter:IValueConverter |
15 | 15 |
{ |
... | ... | |
18 | 18 |
var stringValue = value as string; |
19 | 19 |
|
20 | 20 |
if (String.IsNullOrWhiteSpace(stringValue)) |
21 |
return Visibility.Hidden;
|
|
21 |
return Visibility.Collapsed;
|
|
22 | 22 |
return Visibility.Visible; |
23 | 23 |
} |
24 | 24 |
|
b/trunk/Pithos.Client.WPF/FileProperties/FilePropertiesView.xaml | ||
---|---|---|
4 | 4 |
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
5 | 5 |
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:cal="http://www.caliburnproject.org" |
6 | 6 |
mc:Ignorable="d" |
7 |
d:DesignHeight="300" d:DesignWidth="300" MaxWidth="500" |
|
8 |
Height="481" Icon="/Pithos.Client.WPF;component/Images/PithosTaskbar.png" |
|
9 |
Background="{StaticResource {x:Static SystemColors.ControlBrushKey}}"> |
|
7 |
d:DesignHeight="300" d:DesignWidth="300" MaxWidth="900" |
|
8 |
Height="681" Icon="/Pithos.Client.WPF;component/Images/PithosTaskbar.png" |
|
9 |
Background="{StaticResource {x:Static SystemColors.ControlBrushKey}}" |
|
10 |
> |
|
10 | 11 |
<Window.Resources> |
11 | 12 |
<ResourceDictionary> |
12 | 13 |
<ResourceDictionary.MergedDictionaries> |
13 | 14 |
<ResourceDictionary Source="..\PithosStyles.xaml" /> |
14 | 15 |
</ResourceDictionary.MergedDictionaries> |
16 |
<BooleanToVisibilityConverter x:Key="BoolToVisible" /> |
|
15 | 17 |
</ResourceDictionary> |
16 | 18 |
</Window.Resources> |
17 | 19 |
<Grid> |
... | ... | |
20 | 22 |
<RowDefinition Height="Auto"/> |
21 | 23 |
<RowDefinition Height="*"/> |
22 | 24 |
<RowDefinition Height="*"/> |
25 |
<RowDefinition Height="*"/> |
|
23 | 26 |
<RowDefinition Height="Auto"/> |
24 | 27 |
</Grid.RowDefinitions> |
25 | 28 |
|
... | ... | |
78 | 81 |
</Grid> |
79 | 82 |
</GroupBox> |
80 | 83 |
<GroupBox Header="Metadata" Grid.Row="2" > |
81 |
<DataGrid ItemsSource="{Binding Tags}" |
|
84 |
<DataGrid ItemsSource="{Binding Tags}" x:Name="Tags"
|
|
82 | 85 |
AutoGenerateColumns="False" CanUserAddRows="True" > |
83 | 86 |
<DataGrid.Columns> |
84 | 87 |
<DataGridTemplateColumn > |
85 | 88 |
<DataGridTemplateColumn.CellTemplate> |
86 | 89 |
<DataTemplate> |
87 |
<Button Content=" - " |
|
88 |
cal:Message.Attach="RemoveTag($dataContext)" /> |
|
90 |
<Button Content=" - " Command="DataGrid.DeleteCommand"/> |
|
89 | 91 |
</DataTemplate> |
90 | 92 |
</DataGridTemplateColumn.CellTemplate> |
91 | 93 |
</DataGridTemplateColumn> |
92 |
<DataGridTextColumn Binding="{Binding Name}" Header="Name" />
|
|
94 |
<DataGridTextColumn Binding="{Binding Name}" Header="Key" />
|
|
93 | 95 |
<DataGridTextColumn Binding="{Binding Value}" Header="Value" /> |
94 | 96 |
</DataGrid.Columns> |
95 | 97 |
</DataGrid> |
96 | 98 |
</GroupBox> |
97 |
<GroupBox Header="Permissions" Grid.Row="3" > |
|
99 |
<GroupBox Header="Public & Permissions" Grid.Row="3" > |
|
100 |
<StackPanel> |
|
101 |
<TextBlock Margin="5" Visibility="{Binding Path=IsPublic,FallbackValue=false, Converter={StaticResource BoolToVisible}}"> |
|
102 |
<Run Text="Public URL:" /> |
|
103 |
<Run Text="{Binding PublicUrl,FallbackValue='http://someurl'}" /> |
|
104 |
</TextBlock> |
|
105 |
|
|
106 |
<CheckBox x:Name="IsPublic" Content="Public" Margin="65,5,5,5"/> |
|
98 | 107 |
<DataGrid ItemsSource="{Binding Permissions}" |
99 | 108 |
AutoGenerateColumns="False" CanUserAddRows="True"> |
100 | 109 |
<DataGrid.Columns> |
... | ... | |
111 | 120 |
<DataGridCheckBoxColumn Binding="{Binding Write}" Header="Write"/> |
112 | 121 |
</DataGrid.Columns> |
113 | 122 |
</DataGrid> |
123 |
</StackPanel> |
|
124 |
</GroupBox> |
|
125 |
<GroupBox Header="General" Grid.Row="4"> |
|
126 |
<Grid> |
|
127 |
<Grid.Resources> |
|
128 |
<Style x:Key="NameColumnStyle" TargetType="TextBlock"> |
|
129 |
<Setter Property="HorizontalAlignment" Value="Right"/> |
|
130 |
<Setter Property="Margin" Value="5,2"/> |
|
131 |
</Style> |
|
132 |
<Style x:Key="ValueColumnStyle" TargetType="TextBox"> |
|
133 |
<Setter Property="HorizontalAlignment" Value="Stretch"/> |
|
134 |
<Setter Property="VerticalAlignment" Value="Top"/> |
|
135 |
<Setter Property="Margin" Value="5,2"/> |
|
136 |
</Style> |
|
137 |
</Grid.Resources> |
|
138 |
<Grid.ColumnDefinitions> |
|
139 |
<ColumnDefinition Width="Auto" /> |
|
140 |
<ColumnDefinition Width="*"/> |
|
141 |
</Grid.ColumnDefinitions> |
|
142 |
<Grid.RowDefinitions> |
|
143 |
<RowDefinition Height="Auto"/> |
|
144 |
<RowDefinition Height="Auto"/> |
|
145 |
<RowDefinition Height="Auto"/> |
|
146 |
</Grid.RowDefinitions> |
|
147 |
<TextBlock Text="Content Encoding :" Grid.Row="0" Grid.Column="0" Style="{StaticResource ResourceKey=NameColumnStyle}"/> |
|
148 |
<TextBlock Text="Content Disposition :" Grid.Row="1" Grid.Column="0" Style="{StaticResource ResourceKey=NameColumnStyle}"/> |
|
149 |
<TextBlock Text="Manifest :" Grid.Row="2" Grid.Column="0" Style="{StaticResource ResourceKey=NameColumnStyle}"/> |
|
150 |
<TextBox x:Name="ContentEncoding" Text="text/utf8" Grid.Row="0" Grid.Column="1" Style="{StaticResource ResourceKey=ValueColumnStyle}"/> |
|
151 |
<TextBox x:Name="ContentDisposition" Grid.Row="1" Grid.Column="1" Style="{StaticResource ResourceKey=ValueColumnStyle}"/> |
|
152 |
<TextBox x:Name="Manifest" Grid.Row="2" Grid.Column="1" Style="{StaticResource ResourceKey=ValueColumnStyle}"/> |
|
153 |
</Grid> |
|
114 | 154 |
</GroupBox> |
115 |
<StackPanel Orientation="Horizontal" Grid.Row="4" HorizontalAlignment="Right">
|
|
116 |
<Button Name="SaveChanges" Content="OK" Margin="5,5,10,5" Style="{StaticResource ButtonStyle}"/> |
|
117 |
<Button Name="RejectChanges" Content="Cancel" Margin="5,5,10,5" Style="{StaticResource ButtonStyle}"/> |
|
155 |
<StackPanel Orientation="Horizontal" Grid.Row="5" HorizontalAlignment="Right">
|
|
156 |
<Button Name="SaveChanges" Content="OK" Margin="5,5,10,5" Style="{StaticResource ButtonStyle}" IsDefault="False" />
|
|
157 |
<Button Name="RejectChanges" Content="Cancel" Margin="5,5,10,5" Style="{StaticResource ButtonStyle}" IsCancel="True" />
|
|
118 | 158 |
<Button Name="ApplyChanges" Content="Apply" Style="{StaticResource ButtonStyle}" /> |
119 | 159 |
</StackPanel> |
120 | 160 |
|
b/trunk/Pithos.Client.WPF/FileProperties/FilePropertiesViewModel.cs | ||
---|---|---|
7 | 7 |
using System.Collections; |
8 | 8 |
using System.Collections.Concurrent; |
9 | 9 |
using System.Collections.ObjectModel; |
10 |
using System.Collections.Specialized; |
|
10 | 11 |
using System.ComponentModel.Composition; |
11 | 12 |
using System.Diagnostics; |
12 | 13 |
using System.Diagnostics.Contracts; |
... | ... | |
16 | 17 |
using System.Windows.Media.Imaging; |
17 | 18 |
using Caliburn.Micro; |
18 | 19 |
using Pithos.Client.WPF.FileProperties; |
20 |
using Pithos.Client.WPF.Properties; |
|
19 | 21 |
using Pithos.Interfaces; |
22 |
using Pithos.Network; |
|
20 | 23 |
|
21 | 24 |
namespace Pithos.Client.WPF |
22 | 25 |
{ |
... | ... | |
42 | 45 |
} |
43 | 46 |
} |
44 | 47 |
|
48 |
|
|
49 |
private bool _isPublic; |
|
50 |
public bool IsPublic |
|
51 |
{ |
|
52 |
get { return _isPublic; } |
|
53 |
set |
|
54 |
{ |
|
55 |
_isPublic = value; |
|
56 |
NotifyOfPropertyChange(()=>IsPublic); |
|
57 |
} |
|
58 |
} |
|
59 |
|
|
60 |
private string _contentDisposition; |
|
61 |
public string ContentDisposition |
|
62 |
{ |
|
63 |
get { return _contentDisposition; } |
|
64 |
set |
|
65 |
{ |
|
66 |
_contentDisposition = value; |
|
67 |
NotifyOfPropertyChange(() => ContentDisposition); |
|
68 |
} |
|
69 |
} |
|
70 |
|
|
71 |
private string _contentEncoding; |
|
72 |
public string ContentEncoding |
|
73 |
{ |
|
74 |
get { return _contentEncoding; } |
|
75 |
set |
|
76 |
{ |
|
77 |
_contentEncoding = value; |
|
78 |
NotifyOfPropertyChange(() => ContentEncoding); |
|
79 |
} |
|
80 |
} |
|
81 |
|
|
82 |
|
|
83 |
private string _manifest; |
|
84 |
public string Manifest |
|
85 |
{ |
|
86 |
get { return _manifest; } |
|
87 |
set |
|
88 |
{ |
|
89 |
_manifest = value; |
|
90 |
NotifyOfPropertyChange(() => Manifest); |
|
91 |
} |
|
92 |
} |
|
93 |
|
|
45 | 94 |
public string Kind { get; set; } |
46 | 95 |
public string Size { get; set; } |
47 | 96 |
public string ShortSize { get; set; } |
... | ... | |
51 | 100 |
public long Version { get; set; } |
52 | 101 |
protected string LocalFileName { get; set; } |
53 | 102 |
public BitmapSource FileIcon { get; set; } |
103 |
public string PublicUrl { get; set; } |
|
54 | 104 |
|
55 | 105 |
public string FileName { get; set; } |
56 | 106 |
public string Container { get; set; } |
57 | 107 |
|
108 |
public bool TagsChanged { get; private set; } |
|
109 |
public bool PermissionsChanged { get; private set; } |
|
110 |
|
|
58 | 111 |
public FilePropertiesViewModel(ShellViewModel shell,ObjectInfo pithosFile,string localFileName) |
59 | 112 |
{ |
60 | 113 |
if (shell==null) |
... | ... | |
65 | 118 |
throw new ArgumentNullException("localFileName"); |
66 | 119 |
Contract.EndContractBlock(); |
67 | 120 |
|
121 |
|
|
122 |
_tags = new ObservableCollection<Tag>(); |
|
123 |
_tags.CollectionChanged += (sender, evt) => { TagsChanged = true; }; |
|
124 |
_permissions = new ObservableCollection<Permission>(); |
|
125 |
_permissions.CollectionChanged += (sender, evt) => { PermissionsChanged = true; }; |
|
126 |
|
|
68 | 127 |
Shell = shell; |
69 | 128 |
LocalFileName = localFileName; |
70 | 129 |
PithosFile = pithosFile; |
71 | 130 |
Title = String.Format("{0} Properties", pithosFile.Name); |
72 | 131 |
} |
73 | 132 |
|
133 |
|
|
74 | 134 |
|
75 | 135 |
protected ShellViewModel Shell { get; set; } |
76 | 136 |
|
... | ... | |
103 | 163 |
ModifiedBy = value.ModifiedBy; |
104 | 164 |
Version = value.Version??0; |
105 | 165 |
|
166 |
ContentDisposition = value.ContendDisposition; |
|
167 |
ContentEncoding = value.ContentEncoding; |
|
168 |
Manifest = value.Manifest; |
|
169 |
IsPublic = value.IsPublic; |
|
170 |
|
|
171 |
PublicUrl = String.Format("{0}/v1{1}", Settings.Default.PithosSite ,value.PublicUrl); |
|
172 |
|
|
106 | 173 |
using (var icon = Icon.ExtractAssociatedIcon(LocalFileName)) |
107 | 174 |
{ |
108 | 175 |
FileIcon = Imaging.CreateBitmapSourceFromHIcon(icon.Handle, Int32Rect.Empty, |
... | ... | |
113 | 180 |
} |
114 | 181 |
|
115 | 182 |
|
116 |
|
|
117 |
private readonly ObservableCollection<Tag> _tags = new ObservableCollection<Tag>(); |
|
183 |
private readonly ObservableCollection<Tag> _tags ; |
|
118 | 184 |
public ObservableCollection<Tag> Tags |
119 | 185 |
{ |
120 |
get { return _tags; }
|
|
186 |
get { return _tags;} |
|
121 | 187 |
} |
122 | 188 |
|
123 |
private readonly ObservableCollection<Permission> _permissions = new ObservableCollection<Permission>(); |
|
189 |
private readonly ObservableCollection<Permission> _permissions ; |
|
190 |
|
|
191 |
|
|
124 | 192 |
public ObservableCollection<Permission> Permissions |
125 | 193 |
{ |
126 | 194 |
get { return _permissions; } |
... | ... | |
154 | 222 |
|
155 | 223 |
private void DoSave() |
156 | 224 |
{ |
225 |
if (TagsChanged) |
|
226 |
{ |
|
227 |
PithosFile.Tags = this.Tags.ToDictionary(tag => tag.Name, tag => tag.Value); |
|
228 |
} |
|
157 | 229 |
|
230 |
if (PermissionsChanged) |
|
231 |
{ |
|
232 |
PithosFile.Permissions = this.Permissions.ToDictionary(perm => perm.UserName, perm => perm.Value); |
|
233 |
} |
|
234 |
|
|
235 |
PithosFile.ContendDisposition = ContentDisposition; |
|
236 |
PithosFile.ContentEncoding = ContentEncoding; |
|
237 |
PithosFile.Manifest = Manifest; |
|
238 |
PithosFile.IsPublic = IsPublic; |
|
239 |
|
|
240 |
var monitor = Shell.Monitors[PithosFile.Account]; |
|
241 |
monitor.CloudClient.UpdateMetadata(PithosFile); |
|
242 |
|
|
243 |
|
|
244 |
TagsChanged = false; |
|
245 |
PermissionsChanged = false; |
|
158 | 246 |
} |
159 | 247 |
|
160 | 248 |
|
b/trunk/Pithos.Client.WPF/FileProperties/Permission.cs | ||
---|---|---|
47 | 47 |
UserName = userName; |
48 | 48 |
Read = (string.Compare(permission, "read", true) == 0); |
49 | 49 |
Write= (string.Compare(permission, "write", true) == 0); |
50 |
Value = permission; |
|
50 | 51 |
} |
51 | 52 |
|
53 |
public string Value { get; private set; } |
|
54 |
|
|
52 | 55 |
public Permission() |
53 | 56 |
{ |
54 | 57 |
|
b/trunk/Pithos.Client.WPF/Preferences/PreferencesViewModel.cs | ||
---|---|---|
138 | 138 |
|
139 | 139 |
#region Commands |
140 | 140 |
|
141 |
public bool CanSelectiveSyncFolders |
|
142 |
{ |
|
143 |
get { return CurrentAccount != null; } |
|
144 |
} |
|
145 |
|
|
141 | 146 |
public void SelectiveSyncFolders() |
142 | 147 |
{ |
143 | 148 |
var monitor = Shell.Monitors[CurrentAccount.AccountName]; |
... | ... | |
285 | 290 |
|
286 | 291 |
Settings.ExtensionsActivated = value; |
287 | 292 |
|
288 |
//if (value) |
|
289 |
// _extensionController.RegisterExtensions(); |
|
290 |
//else |
|
291 |
//{ |
|
292 |
// _extensionController.UnregisterExtensions(); |
|
293 |
//} |
|
293 |
/* |
|
294 |
if (value) |
|
295 |
_extensionController.RegisterExtensions(); |
|
296 |
else |
|
297 |
{ |
|
298 |
_extensionController.UnregisterExtensions(); |
|
299 |
} |
|
300 |
*/ |
|
294 | 301 |
NotifyOfPropertyChange(() => ExtensionsActivated); |
295 | 302 |
} |
296 | 303 |
} |
... | ... | |
332 | 339 |
_currentAccount = value; |
333 | 340 |
NotifyOfPropertyChange(()=>CurrentAccount); |
334 | 341 |
NotifyOfPropertyChange(() => CanRemoveAccount); |
342 |
NotifyOfPropertyChange(() => CanSelectiveSyncFolders); |
|
343 |
NotifyOfPropertyChange(() => CanMoveAccountFolder); |
|
335 | 344 |
} |
336 | 345 |
} |
337 | 346 |
|
... | ... | |
348 | 357 |
*/ |
349 | 358 |
|
350 | 359 |
|
351 |
|
|
360 |
public bool CanMoveAccountFolder |
|
361 |
{ |
|
362 |
get { return CurrentAccount != null; } |
|
363 |
} |
|
352 | 364 |
|
353 | 365 |
public void MoveAccountFolder() |
354 | 366 |
{ |
b/trunk/Pithos.Client.WPF/Properties/Settings.Designer.cs | ||
---|---|---|
261 | 261 |
this["Accounts"] = value; |
262 | 262 |
} |
263 | 263 |
} |
264 |
|
|
265 |
[global::System.Configuration.UserScopedSettingAttribute()] |
|
266 |
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] |
|
267 |
[global::System.Configuration.DefaultSettingValueAttribute("True")] |
|
268 |
public bool MustUpgrade { |
|
269 |
get { |
|
270 |
return ((bool)(this["MustUpgrade"])); |
|
271 |
} |
|
272 |
set { |
|
273 |
this["MustUpgrade"] = value; |
|
274 |
} |
|
275 |
} |
|
264 | 276 |
} |
265 | 277 |
} |
b/trunk/Pithos.Client.WPF/Properties/Settings.settings | ||
---|---|---|
66 | 66 |
<Value Profile="(Default)"><?xml version="1.0" encoding="utf-16"?> |
67 | 67 |
<ArrayOfAccountSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /></Value> |
68 | 68 |
</Setting> |
69 |
<Setting Name="MustUpgrade" Type="System.Boolean" Scope="User"> |
|
70 |
<Value Profile="(Default)">True</Value> |
|
71 |
</Setting> |
|
69 | 72 |
</Settings> |
70 | 73 |
</SettingsFile> |
b/trunk/Pithos.Client.WPF/Services/StatusService.cs | ||
---|---|---|
18 | 18 |
/// <summary> |
19 | 19 |
/// TODO: Update summary. |
20 | 20 |
/// </summary> |
21 |
[ServiceBehavior(UseSynchronizationContext=false, IncludeExceptionDetailInFaults = true)] |
|
21 |
[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Reentrant, UseSynchronizationContext=false, IncludeExceptionDetailInFaults = true)]
|
|
22 | 22 |
[Export] |
23 | 23 |
public class StatusService : IStatusService,ISettingsService, ICommandsService |
24 | 24 |
{ |
b/trunk/Pithos.Client.WPF/Shell/FeedbackViewModel.cs | ||
---|---|---|
4 | 4 |
// </copyright> |
5 | 5 |
// ----------------------------------------------------------------------- |
6 | 6 |
|
7 |
using System.Collections.Specialized; |
|
7 | 8 |
using System.ComponentModel.Composition; |
8 | 9 |
using System.Diagnostics; |
9 | 10 |
using System.Diagnostics.Contracts; |
... | ... | |
95 | 96 |
TryClose(); |
96 | 97 |
} |
97 | 98 |
|
98 |
private async void PostForm(string formUrl, string token,Dictionary<string, string> fields)
|
|
99 |
private void PostForm(string formUrl, string token,Dictionary<string, string> fields) |
|
99 | 100 |
{ |
100 | 101 |
|
101 | 102 |
if (String.IsNullOrWhiteSpace(formUrl)) |
... | ... | |
106 | 107 |
throw new ArgumentNullException("fields"); |
107 | 108 |
Contract.EndContractBlock(); |
108 | 109 |
|
109 |
var request = WebRequest.Create(formUrl); |
|
110 |
request.Method = "POST"; |
|
111 |
request.Headers.Add("X-Auth-Token",token); |
|
112 | 110 |
|
111 |
var client = new WebClient(); |
|
112 |
client.Headers.Add("X-Auth-Token", token); |
|
113 | 113 |
|
114 |
var builder = new StringBuilder(); |
|
115 |
foreach (var field in fields) |
|
116 |
{ |
|
117 |
builder.AppendFormat("{0}={1}&", field.Key, Uri.EscapeDataString(field.Value)); |
|
118 |
} |
|
119 |
|
|
120 |
var postData = builder.ToString().TrimEnd('&'); |
|
121 |
var byteArray = Encoding.UTF8.GetBytes(postData); |
|
122 |
|
|
123 |
request.ContentType = "application/x-www-form-urlencoded"; |
|
124 |
request.ContentLength = byteArray.Length; |
|
125 |
using (var stream = request.GetRequestStream()) |
|
114 |
var values=new NameValueCollection(); |
|
115 |
fields.Apply(field => values.Add(field.Key, Uri.EscapeDataString(field.Value))); |
|
116 |
try |
|
126 | 117 |
{ |
127 |
stream.Write(byteArray, 0, byteArray.Length);
|
|
118 |
client.UploadValues(formUrl, values);
|
|
128 | 119 |
} |
129 |
|
|
130 |
|
|
131 |
// Get the response. |
|
132 |
var response = await request.GetResponseAsync(); |
|
133 |
|
|
134 |
|
|
135 |
var webResponse = ((HttpWebResponse)response); |
|
136 |
var result=webResponse.StatusCode; |
|
137 |
if (result != HttpStatusCode.OK) |
|
120 |
catch (WebException exc) |
|
138 | 121 |
{ |
139 |
// Get the stream containing content returned by the server. |
|
140 |
using (var responseStream = webResponse.GetResponseStream()) |
|
141 |
using (var reader = new StreamReader(responseStream)) |
|
142 |
{ |
|
143 |
var responseFromServer = reader.ReadToEnd(); |
|
144 |
Log.WarnFormat("Unexpected status returned from feedback form: {0} - {1}\r\n{2}",result,webResponse.StatusDescription, responseFromServer); |
|
145 |
} |
|
122 |
Log.WarnFormat("Unexpected status returned from feedback form: {0} - {1}", exc.Status,exc.Message); |
|
146 | 123 |
} |
147 |
response.Close(); |
|
148 | 124 |
} |
149 | 125 |
} |
150 | 126 |
} |
b/trunk/Pithos.Client.WPF/Shell/ShellViewModel.cs | ||
---|---|---|
335 | 335 |
var account = pair.Key; |
336 | 336 |
var accountMonitor = pair.Value; |
337 | 337 |
|
338 |
if (accountMonitor == null) |
|
339 |
return; |
|
340 |
|
|
338 | 341 |
ObjectInfo info = accountMonitor.GetObjectInfo(filePath); |
339 | 342 |
|
340 | 343 |
|
b/trunk/Pithos.Client.WPF/app.config | ||
---|---|---|
78 | 78 |
xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> |
79 | 79 |
</value> |
80 | 80 |
</setting> |
81 |
<setting name="MustUpgrade" serializeAs="String"> |
|
82 |
<value>True</value> |
|
83 |
</setting> |
|
81 | 84 |
</Pithos.Client.WPF.Properties.Settings> |
82 | 85 |
</userSettings> |
83 | 86 |
<connectionStrings> |
b/trunk/Pithos.Core/Agents/Agent.cs | ||
---|---|---|
29 | 29 |
_messages.Add(message); |
30 | 30 |
} |
31 | 31 |
|
32 |
/// <summary> |
|
33 |
/// Receives a message asynchronously, optionally with a timeout. Receive throws a TimeoutException if the timeout expires |
|
34 |
/// </summary> |
|
35 |
/// <param name="timeout">Optional timeout in milliseconds. If provided, Receive fails with a TimeoutException if no message is available in the specified time</param> |
|
36 |
/// <returns>A Task that will return the message asynchronously</returns> |
|
32 | 37 |
public Task<TMessage> Receive(int timeout = -1) |
33 | 38 |
{ |
34 | 39 |
return Task<TMessage>.Factory.StartNew(() => |
... | ... | |
40 | 45 |
}); |
41 | 46 |
} |
42 | 47 |
|
48 |
|
|
49 |
/// <summary> |
|
50 |
/// Receives a message asynchronously, optionally with a timeout. TryReceive returns an empty task if the timeout expires |
|
51 |
/// </summary> |
|
52 |
/// <param name="timeout">Optional timeout in milliseconds. If provided, Receive returns an empty task</param> |
|
53 |
/// <returns>A Task that will return the message asynchronously</returns> |
|
43 | 54 |
public Task<TMessage> TryReceive(int timeout = -1) |
44 | 55 |
{ |
45 | 56 |
return Task<TMessage>.Factory.StartNew(() => |
... | ... | |
52 | 63 |
|
53 | 64 |
|
54 | 65 |
|
55 |
|
|
66 |
/// <summary> |
|
67 |
/// Start the agent |
|
68 |
/// </summary> |
|
56 | 69 |
public void Start() |
57 | 70 |
{ |
58 | 71 |
Task.Factory.StartNew(() => _process(this), CancellationToken); |
59 | 72 |
} |
60 | 73 |
|
61 | 74 |
|
62 |
|
|
75 |
/// <summary> |
|
76 |
/// Create and start a new agent for the specified type of message |
|
77 |
/// </summary> |
|
78 |
/// <param name="action">The message processing action</param> |
|
79 |
/// <returns>A started Agent</returns> |
|
63 | 80 |
public static Agent<TMessage> Start(Action<Agent<TMessage>> action) |
64 | 81 |
{ |
65 | 82 |
var agent = new Agent<TMessage>(action); |
... | ... | |
67 | 84 |
return agent; |
68 | 85 |
} |
69 | 86 |
|
87 |
/// <summary> |
|
88 |
/// Stops the agent |
|
89 |
/// </summary> |
|
70 | 90 |
public void Stop() |
71 | 91 |
{ |
92 |
//Stop the message queue |
|
72 | 93 |
_messages.CompleteAdding(); |
94 |
//And signal the cancellation |
|
73 | 95 |
_cancelSource.Cancel(); |
74 | 96 |
} |
75 | 97 |
|
98 |
/// <summary> |
|
99 |
/// Execute an action asynchronously, using the agent's cancellation source |
|
100 |
/// </summary> |
|
101 |
/// <param name="action">The action to execute</param> |
|
76 | 102 |
public void DoAsync(Action action) |
77 | 103 |
{ |
78 | 104 |
Contract.Requires(action!=null); |
... | ... | |
106 | 132 |
return _messages; |
107 | 133 |
} |
108 | 134 |
|
135 |
|
|
109 | 136 |
public Task LoopAsync(Task process, Action loop,Action<Exception> onError=null) |
110 | 137 |
{ |
111 | 138 |
Contract.Requires(process!=null); |
b/trunk/Pithos.Interfaces/ObjectInfo.cs | ||
---|---|---|
4 | 4 |
using System.Dynamic; |
5 | 5 |
using System.Globalization; |
6 | 6 |
using System.IO; |
7 |
using System.Linq; |
|
8 |
using System.Text; |
|
7 | 9 |
using System.Text.RegularExpressions; |
8 | 10 |
using Newtonsoft.Json; |
9 | 11 |
|
... | ... | |
79 | 81 |
|
80 | 82 |
public string Container { get; set; } |
81 | 83 |
|
84 |
public string ContendDisposition { get; set; } |
|
85 |
|
|
86 |
public string ContentEncoding { get; set; } |
|
87 |
|
|
88 |
public string Manifest { get; set; } |
|
89 |
|
|
90 |
private bool _isPublic; |
|
91 |
public bool IsPublic |
|
92 |
{ |
|
93 |
get { return !String.IsNullOrWhiteSpace(PublicUrl); } |
|
94 |
set |
|
95 |
{ |
|
96 |
if (!value) |
|
97 |
PublicUrl = "false"; |
|
98 |
else if (String.IsNullOrWhiteSpace(PublicUrl)) |
|
99 |
PublicUrl="true"; |
|
100 |
} |
|
101 |
} |
|
102 |
|
|
103 |
public string PublicUrl { get; set; } |
|
104 |
|
|
82 | 105 |
public ObjectInfo() |
83 | 106 |
{} |
84 | 107 |
|
... | ... | |
180 | 203 |
return false; |
181 | 204 |
} |
182 | 205 |
|
206 |
public string GetPermissionString() |
|
207 |
{ |
|
208 |
var permissionBuilder = new StringBuilder(); |
|
209 |
var groupings = Permissions.GroupBy(pair => pair.Value); |
|
210 |
foreach (var grouping in groupings) |
|
211 |
{ |
|
212 |
permissionBuilder.AppendFormat("{0}={1}", grouping.Key, String.Join(",", grouping)); |
|
213 |
} |
|
214 |
var permissions = permissionBuilder.ToString(); |
|
215 |
return permissions; |
|
216 |
} |
|
183 | 217 |
} |
184 | 218 |
} |
b/trunk/Pithos.Network/CloudFilesClient.cs | ||
---|---|---|
5 | 5 |
|
6 | 6 |
using System; |
7 | 7 |
using System.Collections.Generic; |
8 |
using System.Collections.Specialized; |
|
8 | 9 |
using System.ComponentModel.Composition; |
9 | 10 |
using System.Diagnostics.Contracts; |
10 | 11 |
using System.IO; |
... | ... | |
399 | 400 |
} |
400 | 401 |
} |
401 | 402 |
|
403 |
public void UpdateMetadata(ObjectInfo objectInfo) |
|
404 |
{ |
|
405 |
if (objectInfo == null) |
|
406 |
throw new ArgumentNullException("objectInfo"); |
|
407 |
Contract.EndContractBlock(); |
|
408 |
|
|
409 |
using (log4net.ThreadContext.Stacks["Objects"].Push("UpdateMetadata")) |
|
410 |
{ |
|
411 |
if (Log.IsDebugEnabled) Log.DebugFormat("START"); |
|
412 |
|
|
413 |
|
|
414 |
using(var client=new RestClient(_baseClient)) |
|
415 |
{ |
|
416 |
|
|
417 |
client.BaseAddress = GetAccountUrl(objectInfo.Account); |
|
418 |
|
|
419 |
client.Parameters.Clear(); |
|
420 |
|
|
421 |
|
|
422 |
//Set Tags |
|
423 |
foreach (var tag in objectInfo.Tags) |
|
424 |
{ |
|
425 |
var headerTag = String.Format("X-Object-Meta-{0}", tag.Key); |
|
426 |
client.Headers.Add(headerTag, tag.Value); |
|
427 |
} |
|
428 |
|
|
429 |
//Set Permissions |
|
430 |
|
|
431 |
var permissions=objectInfo.GetPermissionString(); |
|
432 |
client.SetNonEmptyHeaderValue("X-Object-Sharing",permissions); |
|
433 |
|
|
434 |
client.SetNonEmptyHeaderValue("Content-Disposition",objectInfo.ContendDisposition); |
|
435 |
client.SetNonEmptyHeaderValue("Content-Encoding",objectInfo.ContentEncoding); |
|
436 |
client.SetNonEmptyHeaderValue("X-Object-Manifest",objectInfo.Manifest); |
|
437 |
client.SetNonEmptyHeaderValue("X-Object-Public", objectInfo.PublicUrl); |
|
438 |
|
|
439 |
|
|
440 |
var uriBuilder = client.GetAddressBuilder(objectInfo.Container, objectInfo.Name); |
|
441 |
var uri = uriBuilder.Uri; |
|
442 |
|
|
443 |
var content = client.UploadValues(uri,new NameValueCollection()); |
|
444 |
|
|
445 |
|
|
446 |
client.AssertStatusOK("UpdateMetadata failed"); |
|
447 |
//If the status is NOT ACCEPTED or OK we have a problem |
|
448 |
if (!(client.StatusCode == HttpStatusCode.Accepted || client.StatusCode == HttpStatusCode.OK)) |
|
449 |
{ |
|
450 |
Log.Error("Failed to update metadata"); |
|
451 |
throw new Exception("Failed to update metadata"); |
|
452 |
} |
|
453 |
|
|
454 |
if (Log.IsDebugEnabled) Log.DebugFormat("END"); |
|
455 |
} |
|
456 |
} |
|
457 |
|
|
458 |
} |
|
459 |
|
|
402 | 460 |
|
403 | 461 |
public IList<ObjectInfo> ListObjects(string account, string container, DateTime? since = null) |
404 | 462 |
{ |
... | ... | |
575 | 633 |
var tags = (from key in keys |
576 | 634 |
where key.StartsWith("X-Object-Meta-") |
577 | 635 |
let name = key.Substring(14) |
578 |
select new {Name = name, Value = client.ResponseHeaders[name]})
|
|
636 |
select new {Name = name, Value = client.ResponseHeaders[key]})
|
|
579 | 637 |
.ToDictionary(t => t.Name, t => t.Value); |
580 | 638 |
var extensions = (from key in keys |
581 | 639 |
where key.StartsWith("X-Object-") && !key.StartsWith("X-Object-Meta-") |
582 | 640 |
select new {Name = key, Value = client.ResponseHeaders[key]}) |
583 | 641 |
.ToDictionary(t => t.Name, t => t.Value); |
642 |
|
|
643 |
|
|
584 | 644 |
var info = new ObjectInfo |
585 | 645 |
{ |
586 | 646 |
Account = account, |
... | ... | |
591 | 651 |
Bytes = Convert.ToInt64(client.GetHeaderValue("Content-Length")), |
592 | 652 |
Tags = tags, |
593 | 653 |
Last_Modified = client.LastModified, |
594 |
Extensions = extensions |
|
654 |
Extensions = extensions, |
|
655 |
ContentEncoding=client.GetHeaderValue("Content-Encoding",true), |
|
656 |
ContendDisposition = client.GetHeaderValue("Content-Disposition",true), |
|
657 |
Manifest=client.GetHeaderValue("X-Object-Manifest",true), |
|
658 |
PublicUrl=client.GetHeaderValue("X-Object-Public",true) |
|
595 | 659 |
}; |
596 | 660 |
return info; |
597 | 661 |
case HttpStatusCode.NotFound: |
b/trunk/Pithos.Network/ICloudClient.cs | ||
---|---|---|
59 | 59 |
#endregion |
60 | 60 |
|
61 | 61 |
AccountInfo GetAccountPolicies(AccountInfo accountInfo); |
62 |
|
|
63 |
void UpdateMetadata(ObjectInfo objectInfo); |
|
62 | 64 |
} |
63 | 65 |
|
64 | 66 |
|
... | ... | |
124 | 126 |
return default(AccountInfo); |
125 | 127 |
} |
126 | 128 |
|
129 |
public void UpdateMetadata(ObjectInfo objectInfo) |
|
130 |
{ |
|
131 |
Contract.Requires(objectInfo!=null); |
|
132 |
|
|
133 |
return ; |
|
134 |
} |
|
135 |
|
|
127 | 136 |
|
128 | 137 |
public IList<ObjectInfo> ListObjects(string account, string container, DateTime? since = null) |
129 | 138 |
{ |
b/trunk/Pithos.Network/RestClient.cs | ||
---|---|---|
220 | 220 |
RetryWithoutContent(address, retries, "DELETE"); |
221 | 221 |
} |
222 | 222 |
|
223 |
public string GetHeaderValue(string headerName) |
|
223 |
public string GetHeaderValue(string headerName,bool optional=false)
|
|
224 | 224 |
{ |
225 | 225 |
if (this.ResponseHeaders==null) |
226 | 226 |
throw new InvalidOperationException("ResponseHeaders are null"); |
227 | 227 |
Contract.EndContractBlock(); |
228 | 228 |
|
229 | 229 |
var values=this.ResponseHeaders.GetValues(headerName); |
230 |
if (values == null) |
|
231 |
throw new WebException(String.Format("The {0} header is missing", headerName)); |
|
232 |
else |
|
230 |
if (values != null) |
|
233 | 231 |
return values[0]; |
232 |
|
|
233 |
if (optional) |
|
234 |
return null; |
|
235 |
//A required header was not found |
|
236 |
throw new WebException(String.Format("The {0} header is missing", headerName)); |
|
237 |
} |
|
238 |
|
|
239 |
public void SetNonEmptyHeaderValue(string headerName, string value) |
|
240 |
{ |
|
241 |
if (String.IsNullOrWhiteSpace(value)) |
|
242 |
return; |
|
243 |
Headers.Add(headerName,value); |
|
234 | 244 |
} |
235 | 245 |
|
236 | 246 |
private void RetryWithoutContent(string address, int retries, string method) |
b/trunk/Pithos.ShellExtensions/FileContext.cs | ||
---|---|---|
34 | 34 |
{ |
35 | 35 |
|
36 | 36 |
var accountPath=(from account in Settings.Accounts |
37 |
where CurrentFile.StartsWith(account.RootPath, StringComparison.InvariantCultureIgnoreCase) |
|
37 |
where !String.IsNullOrWhiteSpace(account.RootPath) && CurrentFile.StartsWith(account.RootPath, StringComparison.InvariantCultureIgnoreCase)
|
|
38 | 38 |
select account.RootPath).FirstOrDefault(); |
39 | 39 |
Debug.WriteLine(String.Format("Account path is {0}\r\n Current Path is {1}", accountPath, CurrentFile), LogCategories.Shell); |
40 | 40 |
return !String.IsNullOrWhiteSpace(accountPath); |
b/trunk/Pithos.ShellExtensions/Menus/DisplayFlags.cs | ||
---|---|---|
15 | 15 |
/// <summary> |
16 | 16 |
/// Don't display the item at all |
17 | 17 |
/// </summary> |
18 |
None, |
|
18 |
None=0,
|
|
19 | 19 |
|
20 | 20 |
/// <summary> |
21 | 21 |
/// Display the item only on folders |
22 | 22 |
/// </summary> |
23 |
Folder, |
|
23 |
Folder=1,
|
|
24 | 24 |
|
25 | 25 |
/// <summary> |
26 | 26 |
/// Display the item only on files |
27 | 27 |
/// </summary> |
28 |
File, |
|
28 |
File=2,
|
|
29 | 29 |
|
30 | 30 |
/// <summary> |
31 | 31 |
/// Display the item both on container folders |
32 | 32 |
/// </summary> |
33 |
Container, |
|
33 |
Container=4,
|
|
34 | 34 |
/// <summary> |
35 | 35 |
/// Display the item both on folders and files |
36 | 36 |
/// </summary> |
37 |
All |
|
37 |
All=7
|
|
38 | 38 |
} |
39 | 39 |
} |
b/trunk/Pithos.ShellExtensions/ShellExtLib.cs | ||
---|---|---|
163 | 163 |
// HKCR\<File Type> key which contains the ProgID to which the file type |
164 | 164 |
// is linked. |
165 | 165 |
if (fileType.StartsWith(".")) |
166 |
{ |
|
166 |
{
|
|
167 | 167 |
using (RegistryKey key = Registry.ClassesRoot.OpenSubKey(fileType)) |
168 | 168 |
{ |
169 | 169 |
if (key != null) |
Also available in: Unified diff