--- /dev/null
+using System;
+using System.Globalization;
+using System.Windows;
+using System.Windows.Data;
+
+namespace Pithos.Client.WPF.Converters
+{
+ /// <summary>
+ /// Returns Visible if the value is not null, Collapsed otherwise
+ /// </summary>
+ public class NullToVisibilityConverter:IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ bool invert = (parameter != null);
+ if (value==null)
+ return invert?Visibility.Visible:Visibility.Collapsed;
+ return invert?Visibility.Collapsed:Visibility.Visible;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
\ No newline at end of file
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="Converters\EmptyToVisibilityConverter.cs" />
+ <Compile Include="Converters\NullToVisibilityConverter.cs" />
<Compile Include="FileProperties\ContainerPolicy.cs" />
<Compile Include="FileProperties\NewContainerView.xaml.cs">
<DependentUpon>NewContainerView.xaml</DependentUpon>
<DependentUpon>AddAccountView.xaml</DependentUpon>
</Compile>
<Compile Include="Preferences\AddAccountViewModel.cs" />
+ <Compile Include="Preferences\FileExistsRule.cs" />
<Compile Include="Shell\AboutView.xaml.cs">
<DependentUpon>AboutView.xaml</DependentUpon>
</Compile>
<ItemGroup>
<Resource Include="Images\SmallLogo.png" />
</ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\logo.png" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Window x:Class="Pithos.Client.WPF.Preferences.AddAccountView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:cal="http://www.caliburnproject.org"
xmlns:extToolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit/extended"
- Title="AddAccountView" Height="300" Width="467">
- <extToolkit:Wizard FinishButtonClosesWindow="True">
+ Title="AddAccountView" Height="300" Width="467" xmlns:my="clr-namespace:Microsoft.Windows.Controls.Core.Converters;assembly=WPFToolkit.Extended"
+ xmlns:Preferences="clr-namespace:Pithos.Client.WPF.Preferences">
+ <Window.Resources>
+ <my:InverseBoolConverter x:Key="InverseBool" />
+ <BooleanToVisibilityConverter x:Key="BoolToVisible" />
+ </Window.Resources>
+ <extToolkit:Wizard FinishButtonClosesWindow="True" Name="AccountWizard" PageChanged="AccountWizard_PageChanged">
<extToolkit:WizardPage x:Name="IntroPage"
Title="Add new Pithos Account"
Description="This Wizard will walk you through adding a new Pithos account and retrieving an authentication token" />
<extToolkit:WizardPage x:Name="ChooseMethodPage" PageType="Interior"
Title="How do you want to add the account?"
- Description="You can add an account either by logging in the Pithos Web Site or by entering your username and password manually"
- NextPage="{Binding ElementName=ManualAccountPage}"
- PreviousPage="{Binding ElementName=IntroPage}">
+ Description="You can add an account either by logging in the Pithos Web Site or by entering your username and password manually"
+ CanSelectNextPage="False">
<StackPanel >
- <RadioButton x:Name="Automatic" Content="By logging to Pithos" IsChecked="True"/>
- <RadioButton x:Name="Manually" Content="Manually"/>
+ <RadioButton x:Name="Automatic" Content="By logging to Pithos" Checked="Automatic_Checked" Margin="5"/>
+ <RadioButton x:Name="Manually" Content="Manually" Checked="Manually_Checked" Margin="5"/>
</StackPanel>
</extToolkit:WizardPage>
<extToolkit:WizardPage x:Name="ManualAccountPage" PageType="Interior"
Title="Add an account manually"
Description="This is the second page in the process"
- NextPage="{Binding ElementName=AccountPathPage}"
+ NextPage="{Binding ElementName=AccountPathPage}"
+ CanSelectNextPage="{Binding HasCredentials}"
>
<Grid>
<Grid.ColumnDefinitions>
</Grid>
</extToolkit:WizardPage>
<extToolkit:WizardPage x:Name="AutoAccountPage" PageType="Interior"
- Title="Add an account manually"
- Description="This is the second page in the process"
- NextPage="{Binding ElementName=AutoConfirmedPage}"
- />
- <extToolkit:WizardPage x:Name="AutoConfirmedPage" PageType="Interior"
- Title="Token Received"
- Description="The authentication token was received"
- NextPage="{Binding ElementName=AccountPathPage}"
+ Title="Add an account automatically"
+ Description="By clicking on the button below you will be taken to the Pithos web site where you can login with your username and password."
+ NextPage="{Binding ElementName=AutoConfirmedPage}"
+ CanSelectNextPage="{Binding IsConfirmed}"
+ cal:Message.Attach="[Event GotFocus] = [Action RetrieveCredentials()]"
>
- <Grid>
- <Grid.RowDefinitions>
- <RowDefinition />
- <RowDefinition />
- </Grid.RowDefinitions>
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="Auto"/>
- <ColumnDefinition/>
- </Grid.ColumnDefinitions>
- <TextBlock Text="Account" Grid.Row="0" Grid.Column="0"/>
- <TextBlock Text="Token" Grid.Row="1" Grid.Column="0"/>
- <TextBlock x:Name="FinalAccountName" Grid.Row="0" Grid.Column="1"/>
- <TextBlock x:Name="FinalToken" Grid.Row="1" Grid.Column="1"/>
- </Grid>
+ <extToolkit:BusyIndicator IsBusy="{Binding IsRetrieving}">
+ <extToolkit:BusyIndicator.BusyContent>
+ <TextBlock TextWrapping="Wrap">
+ <TextBlock HorizontalAlignment="Center">Waiting for credentials. </TextBlock>
+ <TextBlock HorizontalAlignment="Center" TextWrapping="Wrap">Please enter your credentials in the Pithos logon page</TextBlock>
+ </TextBlock>
+ </extToolkit:BusyIndicator.BusyContent>
+ <extToolkit:BusyIndicator.Content>
+ <StackPanel VerticalAlignment="Center" >
+ <Button Margin="5" Name="RetrieveCredentials" Content="Retrieve Credentials" Width="150"/>
+
+ <TextBlock Text="Credentials Retrieved Succesfully" Visibility="{Binding Converter={StaticResource BoolToVisible}, Path=HasCredentials}" Margin="10" HorizontalAlignment="Center"/>
+ </StackPanel>
+ </extToolkit:BusyIndicator.Content>
+ </extToolkit:BusyIndicator>
</extToolkit:WizardPage>
<extToolkit:WizardPage x:Name="AccountPathPage" PageType="Interior"
Title="Select Account Path"
Description="Please select the roor path for your account"
NextPage="{Binding ElementName=LastPage}"
+ CanSelectNextPage="{Binding HasAccountPath}"
>
<StackPanel>
- <TextBlock Text="Path:"/>
- <StackPanel Orientation="Horizontal">
- <TextBox x:Name="AccountPath" Width="150" />
- <Button x:Name="SelectAccount" Content="Select ..."/>
- </StackPanel>
+ <Label Content="Path:" Target="{Binding ElementName=AccountPath}"/>
+ <Grid HorizontalAlignment="Stretch">
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition />
+ <ColumnDefinition Width="Auto" />
+ </Grid.ColumnDefinitions>
+ <TextBox x:Name="AccountPath" HorizontalAlignment="Stretch" Grid.Column="0" >
+ <TextBox.Text>
+ <Binding Path="AccountPath" Mode="TwoWay">
+ <Binding.ValidationRules>
+ <Preferences:DirectoryExistsRule/>
+ </Binding.ValidationRules>
+ </Binding>
+ </TextBox.Text>
+ <Validation.ErrorTemplate>
+ <ControlTemplate>
+ <StackPanel>
+ <AdornedElementPlaceholder />
+ <TextBlock Foreground="Red" >Invalid Path</TextBlock>
+ </StackPanel>
+ </ControlTemplate>
+ </Validation.ErrorTemplate>
+ </TextBox>
+ <Button x:Name="SelectAccount" Content="Select ..." HorizontalAlignment="Right" Grid.Column="1"/>
+ </Grid>
</StackPanel>
</extToolkit:WizardPage>
<extToolkit:WizardPage x:Name="LastPage" PageType="Interior"
Title="Finish"
Description="Press finish to create the account"
CanFinish="True">
- <CheckBox x:Name="IsActive" Content="Start using the account immediatelly"/>
+ <Grid>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition />
+ </Grid.RowDefinitions>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="Auto"/>
+ <ColumnDefinition />
+ </Grid.ColumnDefinitions>
+ <TextBlock Text="Account Name:" Grid.Column="0" Grid.Row="0" Margin="5,2"/>
+ <TextBlock Text="{Binding AccountName}" Grid.Column="1" Grid.Row="0" Margin="5,2"/>
+ <TextBlock Text="Token:" Grid.Column="0" Grid.Row="1" Margin="5,2"/>
+ <TextBlock Text="{Binding Token}" Grid.Column="1" Grid.Row="1" Margin="5,2"/>
+ <TextBlock Text="Account Path:" Grid.Column="0" Grid.Row="2" Margin="5,2"/>
+ <TextBlock Text="{Binding AccountPath}" Grid.Column="1" Grid.Row="2" Margin="5,2"/>
+
+ <CheckBox x:Name="IsAccountActive" Content="Start using the account immediatelly" Grid.ColumnSpan="2" Grid.Row="3" Margin="5"/>
+ </Grid>
</extToolkit:WizardPage>
</extToolkit:Wizard>
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
+using Microsoft.Windows.Controls;
namespace Pithos.Client.WPF.Preferences
{
{
public AddAccountView()
{
- InitializeComponent();
+ InitializeComponent();
+ }
+
+ private void Automatic_Checked(object sender, RoutedEventArgs e)
+ {
+ ChooseMethodPage.NextPage = AutoAccountPage;
+ ChooseMethodPage.CanSelectNextPage = true;
+ }
+
+ private void Manually_Checked(object sender, RoutedEventArgs e)
+ {
+ ChooseMethodPage.NextPage = ManualAccountPage;
+ ChooseMethodPage.CanSelectNextPage = true;
+ }
+
+
+ Stack<WizardPage> _history=new Stack<WizardPage>();
+
+ private void AccountWizard_PageChanged(object sender, RoutedEventArgs e)
+ {
+ WizardPage lastPage=null;
+ if (_history.Count>1 && _history.ElementAt(1) == AccountWizard.CurrentPage)
+ {
+ _history.Pop();
+ _history.Pop();
+ }
+ if (_history.Count > 0)
+ lastPage = _history.Peek();
+
+ if (lastPage != null)
+ AccountWizard.CurrentPage.PreviousPage = lastPage;
+
+ _history.Push(AccountWizard.CurrentPage);
+
}
}
}
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.ComponentModel.Composition;
+using System.IO;
using System.Linq;
using System.Text;
-using Caliburn.Micro;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Forms;
+using Pithos.Client.WPF.Properties;
+using Pithos.Core;
+using MessageBox = System.Windows.MessageBox;
+using Screen = Caliburn.Micro.Screen;
namespace Pithos.Client.WPF.Preferences
{
{
_accountName = value;
NotifyOfPropertyChange(()=>AccountName);
+ NotifyOfPropertyChange(() => HasCredentials);
}
}
{
_token = value;
NotifyOfPropertyChange(()=>Token);
+ NotifyOfPropertyChange(() => HasCredentials);
}
}
set
{
_accountPath = value;
- NotifyOfPropertyChange(()=>AccountPath);
+ NotifyOfPropertyChange(() => AccountPath);
+ NotifyOfPropertyChange(() => HasAccountPath);
}
}
+
+
+ public bool HasAccountPath
+ {
+ get { return !String.IsNullOrWhiteSpace(AccountPath); }
+ }
+
+ public bool HasCredentials
+ {
+ get { return !(String.IsNullOrWhiteSpace(AccountName) || String.IsNullOrWhiteSpace(Token) ) ; }
+ }
+
+
+ private bool _isConfirmed;
+
+ public bool IsConfirmed
+ {
+ get { return _isConfirmed; }
+ set
+ {
+ _isConfirmed = value;
+ NotifyOfPropertyChange(() => IsConfirmed);
+ }
+ }
+
+
+ private bool _isAccountActive;
+
+ public bool IsAccountActive
+ {
+ get { return _isAccountActive; }
+ set
+ {
+ _isAccountActive = value;
+ NotifyOfPropertyChange(() => IsAccountActive);
+ }
+ }
+
+ public void SelectAccount()
+ {
+ using (var dlg = new FolderBrowserDialog())
+ {
+ //Ask the user to select a folder
+ //Note: We need a parent window here, which we retrieve with GetView
+ var view = (Window)GetView();
+ if (DialogResult.OK != dlg.ShowDialog(new Wpf32Window(view)))
+ return;
+
+ AccountPath= dlg.SelectedPath;
+ }
+ }
+
+
+ private bool _isRetrieving;
+ public bool IsRetrieving
+ {
+ get { return _isRetrieving; }
+ set
+ {
+ _isRetrieving = value;
+ NotifyOfPropertyChange(() => IsRetrieving);
+ }
+ }
+
+ public async void RetrieveCredentials()
+ {
+ IsRetrieving = true;
+ IsConfirmed = false;
+
+ try
+ {
+ var credentials = await PithosAccount.RetrieveCredentialsAsync(Settings.Default.PithosLoginUrl);
+ AccountName = credentials.UserName;
+ Token = credentials.Password;
+
+ IsConfirmed = true;
+ }
+ catch (Exception exc)
+ {
+ IsConfirmed = false;
+ MessageBox.Show(exc.ToString(), "Error");
+ throw;
+ }
+ IsRetrieving = false;
+
+ }
+
+
}
}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Windows.Controls;
+
+namespace Pithos.Client.WPF.Preferences
+{
+ public class DirectoryExistsRule : ValidationRule
+ {
+ public override ValidationResult Validate(object value, CultureInfo cultureInfo)
+ {
+
+ if (!(value is string))
+ return new ValidationResult(false,"Value is not a path");
+
+ if (Directory.Exists(value as string))
+ return ValidationResult.ValidResult;
+
+ return new ValidationResult(false,String.Format("Path {0} does not exist or is not a directory",value));
+
+ }
+ }
+
+
+}
AccountName = wizard.AccountName,
ApiKey=wizard.Token,
RootPath=wizard.AccountPath,
- IsActive=wizard.IsActive,
+ IsActive=wizard.IsAccountActive,
UsePithos=true
};
Settings.Accounts.Add(newAccount);
<Run>Visit the </Run>
<Hyperlink NavigateUri="http://code.grnet.gr/projects/pithos-ms-client" >Development Web Site</Hyperlink>
</TextBlock>
- <Button x:Name="Close" Content="OK" Grid.Row="4" HorizontalAlignment="Center" Width="75" Margin="5" />
+ <Button x:Name="CloseAbout" Content="OK" Grid.Row="4" HorizontalAlignment="Center" Width="75" Margin="5" />
</Grid>
</Window>
Bits = Environment.Is64BitProcess ? "64 bit" : "32 bit";
}
- public void Close()
+ public void CloseAbout()
{
this.TryClose();
}
</ContextMenu>
</tb:TaskbarIcon.ContextMenu>
</tb:TaskbarIcon>
+ <Image Source="/Pithos.Client.WPF;component/Images/logo.png"/>
</Grid>
</Window>
namespace Pithos.Client.WPF {
using System.ComponentModel.Composition;
- [Export(typeof(IShell))]
+
///<summary>
/// The "shell" of the Pithos application displays the taskbar icon, menu and notifications.
/// The shell also hosts the status service called by shell extensions to retrieve file info
/// * ShowFilePropertiesEvent: Raised when a shell command requests the display of the file/container properties dialog
///</remarks>
//TODO: CODE SMELL Why does the shell handle the SelectiveSynchChanges?
+ [Export(typeof(IShell))]
public class ShellViewModel : Screen, IStatusNotification, IShell,
IHandle<Notification>, IHandle<SelectiveSynchChanges>, IHandle<ShowFilePropertiesEvent>
{
using System.IO;
using System.Linq;
using System.Text;
-using System.Text.RegularExpressions;
using Newtonsoft.Json;
namespace Pithos.Interfaces
public string Manifest { get; set; }
- private bool _isPublic;
public bool IsPublic
{
get { return !String.IsNullOrWhiteSpace(PublicUrl); }
private string GetString(string name)
{
- var value=String.Empty;
+ string value;
_extensions.TryGetValue(name, out value);
return value ;
}
public string GetPermissionString()
{
+ if (Permissions==null)
+ throw new InvalidOperationException();
+ Contract.EndContractBlock();
+
var permissionBuilder = new StringBuilder();
var groupings = Permissions.GroupBy(pair => pair.Value, pair => pair.Key);
foreach (var grouping in groupings)
// </copyright>
// -----------------------------------------------------------------------
-using System.Diagnostics;
-using System.IO;
using System.ServiceModel;
-using Microsoft.Win32;
using Pithos.ShellExtensions.PithosService;
namespace Pithos.ShellExtensions
{
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
-
/// <summary>
- /// TODO: Update summary.
+ /// Returns the status service clients
/// </summary>
public static class PithosHost
{
- public static void EnsureHost()
- {
- return;
- if (Process.GetProcessesByName("Pithos.Client.WPF").Length == 0 &&
- Process.GetProcessesByName("Pithos.Client.WPF.vshost").Length == 0)
- {
- var fileName = (string)Registry.LocalMachine.GetValue(@"Software\Pithos\AppPath");
- var workingDirectory = Path.GetDirectoryName(fileName);
- var info = new ProcessStartInfo {FileName = fileName, WorkingDirectory = workingDirectory};
- Process.Start(info);
- }
- }
-
+ /// <summary>
+ /// Provides a client for retrieving file status from the Pithos App
+ /// </summary>
+ /// <returns></returns>
public static StatusServiceClient GetStatusClient()
{
- EnsureHost();
-
var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
var remoteAddress = new EndpointAddress("net.pipe://localhost/pithos/statuscache");
return new StatusServiceClient(binding, remoteAddress);
}
+ /// <summary>
+ /// Provides a client for retrieving settings from the Pithos App
+ /// </summary>
+ /// <returns></returns>
public static SettingsServiceClient GetSettingsClient()
{
- EnsureHost();
-
var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
var remoteAddress = new EndpointAddress("net.pipe://localhost/pithos/settings");
return new SettingsServiceClient(binding, remoteAddress);
}
+
+ /// <summary>
+ /// Provides a client for sending commands to the Pithos Client
+ /// </summary>
+ /// <returns></returns>
public static CommandsServiceClient GetCommandsClient()
{
- EnsureHost();
-
var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
var remoteAddress = new EndpointAddress("net.pipe://localhost/pithos/commands");