28 Commits
0.8 ... 0.11

Author SHA1 Message Date
Ben
94146467a3 Removed async from a test that didn't need it 2015-07-31 21:43:33 +01:00
Ben
da9fad05a6 Changed maximum PlayAlertSound volume from 100 to 300 as per latest patch.
Updated version to 0.11
2015-07-31 19:52:19 +01:00
Ben
eb73767560 Merge branch 'master' of https://github.com/ben-wallis/Filtration.git 2015-07-31 19:45:57 +01:00
Ben
2954cfe259 Fixed async tests 2015-07-31 19:45:51 +01:00
Ben Wallis
3694e6fa0c Updated release to 0.10 2015-07-26 17:19:53 +01:00
Ben
37258e563a Added Divination Cards to base types 2015-07-26 17:12:51 +01:00
Ben
71e1f2bf78 Revert "Removed Stackable Currency from ItemClasses"
This reverts commit f3ed386845.
2015-07-26 17:03:12 +01:00
Ben
b2b412a73c Revert "Removed Thrusting One Hand Swords from Base Types"
This reverts commit e80295cb69.
2015-07-26 17:03:06 +01:00
Ben
ae948c83a5 Updated version number to 0.10 2015-07-26 17:02:54 +01:00
Ben
3727166a44 Added drag and drop to open script/theme functionality 2015-07-26 11:48:54 +01:00
Ben
32b0a0199f Implemented async saving and loading 2015-07-25 19:02:42 +01:00
Ben
e54730d693 Added Tooltips for keyboard shortcuts and added Ctrl+N shortcut 2015-07-25 15:46:38 +01:00
Ben
d11eefaeab Fixed crash when pasting blocks with block groups assigned 2015-07-24 18:41:13 +01:00
Ben
da5b2c73a0 Moved clipboard operations to ClipboardService 2015-07-24 16:52:31 +01:00
Ben
2ff1373c6b Merge branch 'master' of https://github.com/ben-wallis/Filtration.git 2015-07-24 14:47:52 +01:00
Ben
1882687601 Fixed BlockGroupBrowser indeterminate checkbox state bug 2015-07-24 14:47:47 +01:00
Ben Wallis
3ba25b8f07 Updated release to 0.9 2015-07-15 19:55:52 +01:00
Ben
e80295cb69 Removed Thrusting One Hand Swords from Base Types 2015-07-15 19:48:51 +01:00
Ben
f3ed386845 Removed Stackable Currency from ItemClasses 2015-07-15 19:48:33 +01:00
Ben
89e0c717e8 Bumped version to 0.9 2015-07-15 19:45:49 +01:00
Ben
8924637b98 Added hint text when no audio visual block items are added. 2015-07-15 19:41:31 +01:00
Ben
b0b912c676 Added save check on close 2015-07-15 19:36:42 +01:00
Ben
92ebc51e7b Switched file save encoding to UTF-8 2015-07-15 19:17:19 +01:00
Ben
95e7581a5b Fixed Delete Theme Component button being enabled for non-master themes 2015-07-15 19:12:19 +01:00
Ben
9cb854b584 Fixed Usages: 0 being visible when editing a non-master theme 2015-07-15 19:10:51 +01:00
Ben
61c2902f0c Merge branch 'master' of https://github.com/ben-wallis/Filtration.git 2015-07-15 19:02:34 +01:00
Ben
dc157713f3 Fixed Issue #8 - Crash when Filtration cannot perform the update check on startup 2015-07-15 19:02:29 +01:00
Ben Wallis
16fe837544 updated to 0.8 2015-07-13 15:17:53 +01:00
34 changed files with 548 additions and 209 deletions

View File

@@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Text;
namespace Filtration.Common.Services
{
@@ -20,7 +21,7 @@ namespace Filtration.Common.Services
public void WriteFileFromString(string filePath, string inputString)
{
File.WriteAllText(filePath, inputString);
File.WriteAllText(filePath, inputString, Encoding.UTF8);
}
public bool DirectoryExists(string directoryPath)

View File

@@ -1,9 +1,11 @@
namespace Filtration.Interface
using System.Threading.Tasks;
namespace Filtration.Interface
{
public interface IDocument
{
bool IsScript { get; }
bool IsTheme { get; }
void Close();
Task Close();
}
}

View File

@@ -1,9 +1,11 @@
namespace Filtration.Interface
using System.Threading.Tasks;
namespace Filtration.Interface
{
public interface IEditableDocument : IDocument
{
bool IsDirty { get; }
void Save();
void SaveAs();
Task SaveAsync();
Task SaveAsAsync();
}
}

View File

@@ -1,4 +1,6 @@
using System.IO;
using System.Threading.Tasks;
using Filtration.ObjectModel;
using Filtration.Repositories;
using Filtration.Services;
using Filtration.ViewModels;
@@ -11,14 +13,14 @@ namespace Filtration.Tests.Repositories
public class TestItemFilterScriptRepository
{
[Test]
public void LoadScriptFromFile_CallsPersistenceServiceUsingPathAndReturnsViewModel()
public async Task LoadScriptFromFile_CallsPersistenceServiceUsingPathAndReturnsViewModel()
{
// Arrange
var testInputPath = "C:\\TestPath.filter";
var mockPersistenceService = new Mock<IItemFilterPersistenceService>();
mockPersistenceService.Setup(p => p.LoadItemFilterScript(testInputPath)).Verifiable();
mockPersistenceService.Setup(p => p.LoadItemFilterScriptAsync(testInputPath)).ReturnsAsync(new ItemFilterScript()).Verifiable();
var mockItemFilterScriptViewModel = new Mock<IItemFilterScriptViewModel>();
@@ -28,7 +30,7 @@ namespace Filtration.Tests.Repositories
var repository = new ItemFilterScriptRepository(mockPersistenceService.Object, mockItemFilterScriptViewModelFactory.Object);
// Act
var result = repository.LoadScriptFromFile(testInputPath);
var result = await repository.LoadScriptFromFileAsync(testInputPath);
// Assert
mockPersistenceService.Verify();
@@ -42,7 +44,7 @@ namespace Filtration.Tests.Repositories
var testInputPath = "C:\\TestPath.filter";
var mockPersistenceService = new Mock<IItemFilterPersistenceService>();
mockPersistenceService.Setup(p => p.LoadItemFilterScript(testInputPath)).Throws<IOException>();
mockPersistenceService.Setup(p => p.LoadItemFilterScriptAsync(testInputPath)).Throws<IOException>();
var mockItemFilterScriptViewModelFactory = new Mock<IItemFilterScriptViewModelFactory>();
@@ -51,7 +53,7 @@ namespace Filtration.Tests.Repositories
// Act
// Assert
Assert.Throws<IOException>(() => repository.LoadScriptFromFile(testInputPath));
Assert.Throws<IOException>(async () => await repository.LoadScriptFromFileAsync(testInputPath));
}
[Test]

View File

@@ -1,4 +1,5 @@
using System.IO;
using System.Threading.Tasks;
using Filtration.Common.Services;
using Filtration.ObjectModel;
using Filtration.Services;
@@ -12,7 +13,7 @@ namespace Filtration.Tests.Services
public class TestItemFilterPersistenceService
{
[Test]
public void LoadItemFilterScript_CallsTranslatorAndFileSystemService()
public async Task LoadItemFilterScript_CallsTranslatorAndFileSystemService()
{
// Arrange
const string TestInputPath = "C:\\Test Path\\Script.Filter";
@@ -28,7 +29,7 @@ namespace Filtration.Tests.Services
var service = new ItemFilterPersistenceService(mockFileSystemService.Object, mockItemFilterScriptTranslator.Object);
// Act
var script = service.LoadItemFilterScript(TestInputPath);
var script = await service.LoadItemFilterScriptAsync(TestInputPath);
// Assert
mockFileSystemService.Verify();
@@ -37,7 +38,7 @@ namespace Filtration.Tests.Services
}
[Test]
public void SaveItemFilterScript_CallsTranslatorAndFileSystemService()
public async Task SaveItemFilterScript_CallsTranslatorAndFileSystemService()
{
// Arrange
var testFilePath = "C:\\Test\\File.txt";
@@ -53,7 +54,7 @@ namespace Filtration.Tests.Services
var service = new ItemFilterPersistenceService(mockFileSystemService.Object, mockItemFilterScriptTranslator.Object);
// Act
service.SaveItemFilterScript(testScript);
await service.SaveItemFilterScriptAsync(testScript);
// Assert
mockFileSystemService.Verify();

View File

@@ -1,6 +1,7 @@
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using AutoMapper;
using Filtration.ObjectModel;
using Filtration.ObjectModel.ThemeEditor;
@@ -13,9 +14,9 @@ namespace Filtration.ThemeEditor.Providers
{
IThemeEditorViewModel NewThemeForScript(ItemFilterScript script);
IThemeEditorViewModel MasterThemeForScript(ItemFilterScript script);
IThemeEditorViewModel LoadThemeFromFile(string filePath);
Theme LoadThemeModelFromFile(string filePath);
void SaveTheme(IThemeEditorViewModel themeEditorViewModel, string filePath);
Task<IThemeEditorViewModel> LoadThemeFromFile(string filePath);
Task<Theme> LoadThemeModelFromFile(string filePath);
Task SaveThemeAsync(IThemeEditorViewModel themeEditorViewModel, string filePath);
}
internal class ThemeProvider : IThemeProvider
@@ -54,23 +55,26 @@ namespace Filtration.ThemeEditor.Providers
return themeViewModel;
}
public IThemeEditorViewModel LoadThemeFromFile(string filePath)
public async Task<IThemeEditorViewModel> LoadThemeFromFile(string filePath)
{
var model = _themePersistenceService.LoadTheme(filePath);
var model = await _themePersistenceService.LoadThemeAsync(filePath);
var viewModel = Mapper.Map<IThemeEditorViewModel>(model);
viewModel.FilePath = filePath;
return viewModel;
}
public Theme LoadThemeModelFromFile(string filePath)
public async Task<Theme> LoadThemeModelFromFile(string filePath)
{
return _themePersistenceService.LoadTheme(filePath);
return await _themePersistenceService.LoadThemeAsync(filePath);
}
public void SaveTheme(IThemeEditorViewModel themeEditorViewModel, string filePath)
public async Task SaveThemeAsync(IThemeEditorViewModel themeEditorViewModel, string filePath)
{
var theme = Mapper.Map<Theme>(themeEditorViewModel);
_themePersistenceService.SaveTheme(theme, filePath);
await Task.Run(() =>
{
var theme = Mapper.Map<Theme>(themeEditorViewModel);
_themePersistenceService.SaveThemeAsync(theme, filePath);
});
}
}
}

View File

@@ -1,4 +1,5 @@
using System.IO;
using System.Threading.Tasks;
using System.Xml.Serialization;
using Filtration.ObjectModel.ThemeEditor;
@@ -6,35 +7,42 @@ namespace Filtration.ThemeEditor.Services
{
internal interface IThemePersistenceService
{
Theme LoadTheme(string filePath);
void SaveTheme(Theme theme, string filePath);
Task<Theme> LoadThemeAsync(string filePath);
Task SaveThemeAsync(Theme theme, string filePath);
}
internal class ThemePersistenceService : IThemePersistenceService
{
public Theme LoadTheme(string filePath)
public async Task<Theme> LoadThemeAsync(string filePath)
{
var xmlSerializer = new XmlSerializer(typeof(Theme));
Theme loadedTheme = null;
Theme loadedTheme;
using (Stream reader = new FileStream(filePath, FileMode.Open))
await Task.Run(() =>
{
loadedTheme = (Theme)xmlSerializer.Deserialize(reader);
}
loadedTheme.FilePath = filePath;
var xmlSerializer = new XmlSerializer(typeof (Theme));
using (Stream reader = new FileStream(filePath, FileMode.Open))
{
loadedTheme = (Theme) xmlSerializer.Deserialize(reader);
}
loadedTheme.FilePath = filePath;
});
return loadedTheme;
}
public void SaveTheme(Theme theme, string filePath)
public async Task SaveThemeAsync(Theme theme, string filePath)
{
var xmlSerializer = new XmlSerializer(typeof(Theme));
using (Stream writer = new FileStream(filePath, FileMode.Create))
await Task.Run(() =>
{
xmlSerializer.Serialize(writer, theme);
}
var xmlSerializer = new XmlSerializer(typeof (Theme));
using (Stream writer = new FileStream(filePath, FileMode.Create))
{
xmlSerializer.Serialize(writer, theme);
}
});
}
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media;
@@ -55,7 +56,7 @@ namespace Filtration.ThemeEditor.ViewModels
AddThemeComponentCommand = new RelayCommand<ThemeComponentType>(OnAddThemeComponentCommand, t => IsMasterTheme);
DeleteThemeComponentCommand = new RelayCommand<ThemeComponent>(OnDeleteThemeComponentCommand,
t => IsMasterTheme && SelectedThemeComponent != null);
CloseCommand = new RelayCommand(OnCloseCommand);
CloseCommand = new RelayCommand(async () => await OnCloseCommand());
var icon = new BitmapImage();
icon.BeginInit();
@@ -123,19 +124,19 @@ namespace Filtration.ThemeEditor.ViewModels
}
}
public void Save()
public async Task SaveAsync()
{
if (IsMasterTheme) return;
if (_filenameIsFake)
{
SaveAs();
await SaveAsAsync();
return;
}
try
{
_themeProvider.SaveTheme(this, FilePath);
await _themeProvider.SaveThemeAsync(this, FilePath);
//RemoveDirtyFlag();
}
catch (Exception e)
@@ -149,7 +150,7 @@ namespace Filtration.ThemeEditor.ViewModels
}
}
public void SaveAs()
public async Task SaveAsAsync()
{
if (IsMasterTheme) return;
@@ -167,7 +168,7 @@ namespace Filtration.ThemeEditor.ViewModels
try
{
FilePath = saveDialog.FileName;
_themeProvider.SaveTheme(this, FilePath);
await _themeProvider.SaveThemeAsync(this, FilePath);
_filenameIsFake = false;
Title = Filename;
//RemoveDirtyFlag();
@@ -185,14 +186,16 @@ namespace Filtration.ThemeEditor.ViewModels
}
}
public void OnCloseCommand()
public async Task OnCloseCommand()
{
Close();
await Close();
}
public void Close()
#pragma warning disable 1998
public async Task Close()
#pragma warning restore 1998
{
Messenger.Default.Send(new ThemeClosedMessage { ClosedViewModel = this });
Messenger.Default.Send(new ThemeClosedMessage {ClosedViewModel = this});
}
private void OnAddThemeComponentCommand(ThemeComponentType themeComponentType)

View File

@@ -21,30 +21,29 @@
</Grid.RowDefinitions>
<Grid.Resources>
<DataTemplate x:Key="EditableComponentNameTemplate">
<TextBox Text="{Binding ComponentName}" />
<StackPanel>
<TextBlock Text="{Binding UsageCount, StringFormat='Usages: {0}'}"
FontSize="10"
HorizontalAlignment="Right"
Visibility="{Binding Path=DataContext.EditEnabled, RelativeSource={RelativeSource AncestorType={x:Type views:ThemeEditorView}}, Converter={StaticResource BooleanVisibilityConverter}}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding UsageCount}" Value="0">
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
</Style.Triggers>
<Setter Property="Foreground" Value="SteelBlue" />
</Style>
</TextBlock.Style>
</TextBlock>
<TextBox Text="{Binding ComponentName}" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="ViewOnlyComponentNameTemplate">
<TextBlock Text="{Binding ComponentName}" ToolTip="{Binding ComponentName}" />
</DataTemplate>
</Grid.Resources>
<DockPanel LastChildFill="True">
<TextBlock DockPanel.Dock="Left"
Text="{Binding UsageCount, StringFormat='Usages: {0}'}"
FontSize="10"
HorizontalAlignment="Right"
Visibility="{Binding Path=DataContext.EditEnabled, RelativeSource={RelativeSource AncestorType={x:Type views:ThemeEditorView}}, Converter={StaticResource BooleanVisibilityConverter}}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding UsageCount}" Value="0">
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
</Style.Triggers>
<Setter Property="Foreground" Value="SteelBlue" />
</Style>
</TextBlock.Style>
</TextBlock>
</DockPanel>
<ContentControl Grid.Row="1" Content="{Binding}">
<ContentControl.Style>
<Style TargetType="ContentControl">
@@ -59,7 +58,6 @@
</Style>
</ContentControl.Style>
</ContentControl>
<xctk:ColorPicker Grid.Row="2" SelectedColor="{Binding Color}" />
</Grid>
</UserControl>

View File

@@ -94,6 +94,10 @@
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="WpfAnimatedGif, Version=1.4.13.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\WpfAnimatedGif.1.4.13\lib\net\WpfAnimatedGif.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="WPFToolkit, Version=3.5.40128.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\WPFToolkit.3.5.50211.1\lib\WPFToolkit.dll</HintPath>
@@ -145,6 +149,7 @@
<Compile Include="Models\UpdateData.cs" />
<Compile Include="Properties\Annotations.cs" />
<Compile Include="Repositories\ItemFilterScriptRepository.cs" />
<Compile Include="Services\ClipboardService.cs" />
<Compile Include="Services\HTTPService.cs" />
<Compile Include="Services\ItemFilterPersistenceService.cs" />
<Compile Include="Services\StaticDataService.cs" />
@@ -243,7 +248,6 @@
<Compile Include="Views\UpdateAvailableView.xaml.cs">
<DependentUpon>UpdateAvailableView.xaml</DependentUpon>
</Compile>
<Compile Include="WindsorInstallers\ModelsInstaller.cs" />
<Compile Include="WindsorInstallers\RepositoriesInstaller.cs" />
<Compile Include="WindsorInstallers\ServicesInstaller.cs" />
<Compile Include="WindsorInstallers\TranslatorsInstaller.cs" />
@@ -365,6 +369,7 @@
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<Resource Include="Resources\loading_spinner.gif" />
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>

View File

@@ -7,7 +7,7 @@ using System.Windows;
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Filtration")]
[assembly: AssemblyDescription("An item filter script manager for Path of Exile")]
[assembly: AssemblyDescription("An item filter script editor for Path of Exile")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("XVar Industries Inc.")]
[assembly: AssemblyProduct("Filtration")]
@@ -50,7 +50,7 @@ using System.Windows;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.8.*")]
[assembly: AssemblyVersion("0.11.*")]
[assembly: InternalsVisibleTo("Filtration.Tests")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

View File

@@ -1,4 +1,5 @@
using Filtration.ObjectModel;
using System.Threading.Tasks;
using Filtration.ObjectModel;
using Filtration.Services;
using Filtration.ViewModels;
@@ -6,7 +7,7 @@ namespace Filtration.Repositories
{
internal interface IItemFilterScriptRepository
{
IItemFilterScriptViewModel LoadScriptFromFile(string path);
Task<IItemFilterScriptViewModel> LoadScriptFromFileAsync(string path);
IItemFilterScriptViewModel NewScript();
string GetItemFilterScriptDirectory();
void SetItemFilterScriptDirectory(string path);
@@ -24,9 +25,9 @@ namespace Filtration.Repositories
_itemFilterScriptViewModelFactory = itemFilterScriptViewModelFactory;
}
public IItemFilterScriptViewModel LoadScriptFromFile(string path)
public async Task<IItemFilterScriptViewModel> LoadScriptFromFileAsync(string path)
{
var loadedScript = _itemFilterPersistenceService.LoadItemFilterScript(path);
var loadedScript = await _itemFilterPersistenceService.LoadItemFilterScriptAsync(path);
var newViewModel = _itemFilterScriptViewModelFactory.Create();
newViewModel.Initialise(loadedScript, false);

View File

@@ -1069,31 +1069,54 @@ Sage Wand
Serpent Wand
Spiraled Wand
Tornado Wand
Emperor's Luck
Abandoned Wealth
The Avenger
The Brittle Emperor
Hope
The Battle Born
Birth of the Three
The Brittle Emperor
The Carrion Crow
The Cataclysm
The Celestial Justicar
The Chains that Bind
Chaotic Disposition
Coveted Possession
The Dark Mage
The Doctor
The Drunken Aristocrat
Emperor's Luck
The Explorer
The Feast
The Fiend
The Gambler
The Gemcutter
Gemcutter's Promise
The Gladiator
The Hermit
The Hoarder
Hope
The Hunger
Humility
The Incantation
The Inventor
Jack in the Box
The King's Heart
Lantador's Lost Love
The Lover
Lucky Connections
The Metalsmith's Gift
The Pact
The Poet
The Queen
Rain of Chaos
The Road to Power
The Scarred Meadow
The Scholar
The Summoner
Vinia's Token
Three Faces in the Dark
The Hermit
Lantador's Lost Love
Birth of the Three
The Lover
Chaotic Disposition
Eternal Sword
The Sun
The Gemcutter
The Warden
Three Faces in the Dark
Time-Lost Relic
The Union
Vinia's Token
The Warden
The Watcher
The Wind

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View File

@@ -0,0 +1,43 @@
using System;
using System.Threading;
using System.Windows;
using NLog;
namespace Filtration.Services
{
internal interface IClipboardService
{
void SetClipboardText(string inputText);
string GetClipboardText();
}
internal class ClipboardService : IClipboardService
{
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
public void SetClipboardText(string inputText)
{
for (var i = 0; i < 10; i++)
{
try
{
Clipboard.SetText(inputText);
return;
}
catch (Exception e)
{
_logger.Error(e);
}
Thread.Sleep(10);
}
throw new Exception("Failed to copy to clipboard");
}
public string GetClipboardText()
{
return Clipboard.GetText();
}
}
}

View File

@@ -1,4 +1,5 @@
using System.IO;
using System.Threading.Tasks;
using Filtration.Common.Services;
using Filtration.ObjectModel;
using Filtration.Properties;
@@ -10,8 +11,8 @@ namespace Filtration.Services
{
void SetItemFilterScriptDirectory(string path);
string ItemFilterScriptDirectory { get; }
ItemFilterScript LoadItemFilterScript(string filePath);
void SaveItemFilterScript(ItemFilterScript script);
Task<ItemFilterScript> LoadItemFilterScriptAsync(string filePath);
Task SaveItemFilterScriptAsync(ItemFilterScript script);
string DefaultPathOfExileDirectory();
}
@@ -58,20 +59,30 @@ namespace Filtration.Services
Settings.Default.DefaultFilterDirectory = path;
}
public ItemFilterScript LoadItemFilterScript(string filePath)
public async Task<ItemFilterScript> LoadItemFilterScriptAsync(string filePath)
{
var script =
_itemFilterScriptTranslator.TranslateStringToItemFilterScript(
ItemFilterScript loadedScript = null;
await Task.Run(() =>
{
loadedScript = _itemFilterScriptTranslator.TranslateStringToItemFilterScript(
_fileSystemService.ReadFileAsString(filePath));
});
script.FilePath = filePath;
return script;
if (loadedScript != null)
{
loadedScript.FilePath = filePath;
}
return loadedScript;
}
public void SaveItemFilterScript(ItemFilterScript script)
public async Task SaveItemFilterScriptAsync(ItemFilterScript script)
{
_fileSystemService.WriteFileFromString(script.FilePath,
_itemFilterScriptTranslator.TranslateItemFilterScriptToString(script));
await Task.Run(() =>
{
_fileSystemService.WriteFileFromString(script.FilePath,
_itemFilterScriptTranslator.TranslateItemFilterScriptToString(script));
});
}
}
}

View File

@@ -7,7 +7,7 @@ namespace Filtration.Services
{
internal interface IUpdateCheckService
{
Task<UpdateData> GetUpdateData();
Task<UpdateData> GetUpdateDataAsync();
}
internal class UpdateCheckService : IUpdateCheckService
@@ -20,7 +20,7 @@ namespace Filtration.Services
_httpService = httpService;
}
public async Task<UpdateData> GetUpdateData()
public async Task<UpdateData> GetUpdateDataAsync()
{
var updateXml = await _httpService.GetContentAsync(UpdateDataUrl);
return (DeserializeUpdateData(updateXml));

View File

@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Documents;
using Castle.Core.Internal;
using Filtration.ObjectModel;
using Filtration.Properties;

View File

@@ -100,7 +100,7 @@
<Image Source="/Filtration;component/Resources/Icons/speaker_icon.png" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Button>
<ComboBox ItemsSource="{Binding ElementName=BlockItemContentControl, Path=DataContext.SoundsAvailable}" SelectedValue="{Binding Value}" Style="{StaticResource MetroComboBox}" />
<xctk:ShortUpDown Value="{Binding Path=SecondValue}" Minimum="1" Maximum="100" HorizontalAlignment="Right" ToolTip="Volume"/>
<xctk:ShortUpDown Value="{Binding Path=SecondValue}" Minimum="1" Maximum="300" HorizontalAlignment="Right" ToolTip="Volume"/>
</WrapPanel>
</DataTemplate>
</ContentControl.Resources>

View File

@@ -17,7 +17,8 @@ namespace Filtration.Utilities
if (viewModel.ChildGroups.All(g => g.IsChecked == true))
{
viewModel.IsChecked = true;
} else if (viewModel.ChildGroups.Any(g => g.IsChecked == true))
}
else if (viewModel.ChildGroups.Any(g => g.IsChecked == true || g.IsChecked == null))
{
viewModel.IsChecked = null;
}

View File

@@ -39,9 +39,9 @@ namespace Filtration.ViewModels
private readonly ReadOnlyObservableCollection<IDocument> _readOnlyOpenDocuments;
public AvalonDockWorkspaceViewModel(ISectionBrowserViewModel sectionBrowserViewModel,
IBlockGroupBrowserViewModel blockGroupBrowserViewModel,
IStartPageViewModel startPageViewModel,
IBlockOutputPreviewViewModel blockOutputPreviewViewModel)
IBlockGroupBrowserViewModel blockGroupBrowserViewModel,
IStartPageViewModel startPageViewModel,
IBlockOutputPreviewViewModel blockOutputPreviewViewModel)
{
_sectionBrowserViewModel = sectionBrowserViewModel;
_blockGroupBrowserViewModel = blockGroupBrowserViewModel;
@@ -122,7 +122,6 @@ namespace Filtration.ViewModels
}
private List<IToolViewModel> _tools;
public IEnumerable<IToolViewModel> Tools
{

View File

@@ -317,6 +317,12 @@ namespace Filtration.ViewModels
get { return Block.HasBlockItemOfType<SoundBlockItem>(); }
}
public bool HasAudioVisualBlockItems
{
get { return AudioVisualBlockItems.Any(); }
}
private void OnSwitchBlockItemsViewCommand()
{
AudioVisualBlockItemsGridVisible = !AudioVisualBlockItemsGridVisible;
@@ -459,6 +465,7 @@ namespace Filtration.ViewModels
RaisePropertyChanged("RegularBlockItems");
RaisePropertyChanged("SummaryBlockItems");
RaisePropertyChanged("AudioVisualBlockItems");
RaisePropertyChanged("HasAudioVisualBlockItems");
}
}
}

View File

@@ -4,11 +4,11 @@ using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Forms;
using System.Windows.Media.Imaging;
using Castle.Core.Internal;
using Filtration.Common.Services;
using Filtration.Common.ViewModels;
using Filtration.Interface;
@@ -19,7 +19,6 @@ using Filtration.Translators;
using GalaSoft.MvvmLight.CommandWpf;
using GalaSoft.MvvmLight.Messaging;
using NLog;
using Clipboard = System.Windows.Clipboard;
namespace Filtration.ViewModels
{
@@ -76,6 +75,8 @@ namespace Filtration.ViewModels
private readonly IAvalonDockWorkspaceViewModel _avalonDockWorkspaceViewModel;
private readonly IItemFilterPersistenceService _persistenceService;
private readonly IMessageBoxService _messageBoxService;
private readonly IClipboardService _clipboardService;
private readonly IBlockGroupHierarchyBuilder _blockGroupHierarchyBuilder;
private bool _isDirty;
private IItemFilterBlockViewModel _selectedBlockViewModel;
@@ -88,7 +89,9 @@ namespace Filtration.ViewModels
IItemFilterBlockTranslator blockTranslator,
IAvalonDockWorkspaceViewModel avalonDockWorkspaceViewModel,
IItemFilterPersistenceService persistenceService,
IMessageBoxService messageBoxService)
IMessageBoxService messageBoxService,
IClipboardService clipboardService,
IBlockGroupHierarchyBuilder blockGroupHierarchyBuilder)
{
_itemFilterBlockViewModelFactory = itemFilterBlockViewModelFactory;
_blockTranslator = blockTranslator;
@@ -96,11 +99,13 @@ namespace Filtration.ViewModels
_avalonDockWorkspaceViewModel.ActiveDocumentChanged += OnActiveDocumentChanged;
_persistenceService = persistenceService;
_messageBoxService = messageBoxService;
_clipboardService = clipboardService;
_blockGroupHierarchyBuilder = blockGroupHierarchyBuilder;
_itemFilterBlockViewModels = new ObservableCollection<IItemFilterBlockViewModel>();
ToggleShowAdvancedCommand = new RelayCommand<bool>(OnToggleShowAdvancedCommand);
ClearFilterCommand = new RelayCommand(OnClearFilterCommand, () => BlockFilterPredicate != null);
CloseCommand = new RelayCommand(OnCloseCommand);
CloseCommand = new RelayCommand(async () => await OnCloseCommand());
DeleteBlockCommand = new RelayCommand(OnDeleteBlockCommand, () => SelectedBlockViewModel != null);
MoveBlockToTopCommand = new RelayCommand(OnMoveBlockToTopCommand, () => SelectedBlockViewModel != null);
MoveBlockUpCommand = new RelayCommand(OnMoveBlockUpCommand, () => SelectedBlockViewModel != null);
@@ -347,20 +352,21 @@ namespace Filtration.ViewModels
ContentId = "ScriptContentId";
}
public void Save()
public async Task SaveAsync()
{
if (!ValidateScript()) return;
if (!CheckForUnusedThemeComponents()) return;
if (_filenameIsFake)
{
SaveAs();
await SaveAsAsync();
return;
}
Messenger.Default.Send(new NotificationMessage("ShowLoadingBanner"));
try
{
_persistenceService.SaveItemFilterScript(Script);
await _persistenceService.SaveItemFilterScriptAsync(Script);
RemoveDirtyFlag();
}
catch (Exception e)
@@ -373,9 +379,15 @@ namespace Filtration.ViewModels
_messageBoxService.Show("Save Error", "Error saving filter file - " + e.Message, MessageBoxButton.OK,
MessageBoxImage.Error);
}
finally
{
Messenger.Default.Send(new NotificationMessage("HideLoadingBanner"));
}
return;
}
public void SaveAs()
public async Task SaveAsAsync()
{
if (!ValidateScript()) return;
if (!CheckForUnusedThemeComponents()) return;
@@ -390,12 +402,14 @@ namespace Filtration.ViewModels
var result = saveDialog.ShowDialog();
if (result != DialogResult.OK) return;
Messenger.Default.Send(new NotificationMessage("ShowLoadingBanner"));
var previousFilePath = Script.FilePath;
try
{
Script.FilePath = saveDialog.FileName;
_persistenceService.SaveItemFilterScript(Script);
await _persistenceService.SaveItemFilterScriptAsync(Script);
_filenameIsFake = false;
Title = Filename;
RemoveDirtyFlag();
@@ -411,6 +425,10 @@ namespace Filtration.ViewModels
MessageBoxImage.Error);
Script.FilePath = previousFilePath;
}
finally
{
Messenger.Default.Send(new NotificationMessage("HideLoadingBanner"));
}
}
private bool CheckForUnusedThemeComponents()
@@ -476,12 +494,12 @@ namespace Filtration.ViewModels
return false;
}
private void OnCloseCommand()
private async Task OnCloseCommand()
{
Close();
await Close();
}
public void Close()
public async Task Close()
{
if (!IsDirty)
{
@@ -490,25 +508,25 @@ namespace Filtration.ViewModels
else
{
var result = _messageBoxService.Show("Filtration",
"Want to save your changes to this script?", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
"Save script \"" + Filename + "\"?", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
switch (result)
{
case MessageBoxResult.Yes:
{
Save();
CloseScript();
break;
}
{
await SaveAsync();
CloseScript();
break;
}
case MessageBoxResult.No:
{
CloseScript();
break;
}
{
CloseScript();
break;
}
case MessageBoxResult.Cancel:
{
return;
}
{
return;
}
}
}
}
@@ -544,7 +562,16 @@ namespace Filtration.ViewModels
public void CopyBlock(IItemFilterBlockViewModel targetBlockViewModel)
{
Clipboard.SetText(_blockTranslator.TranslateItemFilterBlockToString(SelectedBlockViewModel.Block));
try
{
_clipboardService.SetClipboardText(
_blockTranslator.TranslateItemFilterBlockToString(SelectedBlockViewModel.Block));
}
catch
{
_messageBoxService.Show("Clipboard Error", "Failed to access the clipboard, copy command not completed.",
MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void OnCopyBlockStyleCommand()
@@ -564,8 +591,15 @@ namespace Filtration.ViewModels
}
outputText += blockItem.OutputText;
}
Clipboard.SetText(outputText);
try
{
_clipboardService.SetClipboardText(outputText);
}
catch
{
_messageBoxService.Show("Clipboard Error", "Failed to access the clipboard, copy command not completed.",
MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void OnPasteBlockStyleCommand()
@@ -575,7 +609,7 @@ namespace Filtration.ViewModels
public void PasteBlockStyle(IItemFilterBlockViewModel targetBlockViewModel)
{
var clipboardText = Clipboard.GetText();
var clipboardText = _clipboardService.GetClipboardText();
if (string.IsNullOrEmpty(clipboardText))
{
return;
@@ -594,8 +628,9 @@ namespace Filtration.ViewModels
{
try
{
var clipboardText = Clipboard.GetText();
if (clipboardText.IsNullOrEmpty()) return;
var clipboardText = _clipboardService.GetClipboardText();
if (string.IsNullOrEmpty(clipboardText)) return;
_blockGroupHierarchyBuilder.Initialise(Script.ItemFilterBlockGroups.First());
var translatedBlock = _blockTranslator.TranslateStringToItemFilterBlock(clipboardText, Script.ThemeComponents);
if (translatedBlock == null) return;
@@ -621,9 +656,12 @@ namespace Filtration.ViewModels
catch (Exception e)
{
_logger.Error(e);
var innerException = e.InnerException != null
? e.InnerException.Message
: string.Empty;
_messageBoxService.Show("Paste Error",
e.Message + Environment.NewLine + e.StackTrace + Environment.NewLine +
e.InnerException.Message + Environment.NewLine + e.InnerException.StackTrace, MessageBoxButton.OK,
e.Message + Environment.NewLine + innerException, MessageBoxButton.OK,
MessageBoxImage.Error);
}
}
@@ -753,6 +791,7 @@ namespace Filtration.ViewModels
IsDirty = true;
SelectedBlockViewModel = vm;
RaisePropertyChanged("ItemFilterSectionViewModels");
Messenger.Default.Send(new NotificationMessage("SectionsChanged"));
}
private void OnExpandAllBlocksCommand()
@@ -784,9 +823,17 @@ namespace Filtration.ViewModels
if (result == MessageBoxResult.Yes)
{
var isSection = targetBlockViewModel.Block is ItemFilterSection;
Script.ItemFilterBlocks.Remove(targetBlockViewModel.Block);
ItemFilterBlockViewModels.Remove(targetBlockViewModel);
IsDirty = true;
if (isSection)
{
Messenger.Default.Send(new NotificationMessage("SectionsChanged"));
}
}
SelectedBlockViewModel = null;
}

View File

@@ -1,9 +1,13 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Filtration.Common.Services;
@@ -24,7 +28,6 @@ using Filtration.Views;
using GalaSoft.MvvmLight.CommandWpf;
using GalaSoft.MvvmLight.Messaging;
using NLog;
using Clipboard = System.Windows.Clipboard;
using OpenFileDialog = Microsoft.Win32.OpenFileDialog;
namespace Filtration.ViewModels
@@ -33,6 +36,8 @@ namespace Filtration.ViewModels
{
RelayCommand OpenScriptCommand { get; }
RelayCommand NewScriptCommand { get; }
Task<bool> CloseAllDocumentsAsync();
Task OpenDroppedFilesAsync(List<string> filenames);
}
internal class MainWindowViewModel : FiltrationViewModelBase, IMainWindowViewModel
@@ -49,6 +54,8 @@ namespace Filtration.ViewModels
private readonly IUpdateCheckService _updateCheckService;
private readonly IUpdateAvailableViewModel _updateAvailableViewModel;
private readonly IMessageBoxService _messageBoxService;
private readonly IClipboardService _clipboardService;
private bool _showLoadingBanner;
public MainWindowViewModel(IItemFilterScriptRepository itemFilterScriptRepository,
IItemFilterScriptTranslator itemFilterScriptTranslator,
@@ -59,7 +66,8 @@ namespace Filtration.ViewModels
IThemeService themeService,
IUpdateCheckService updateCheckService,
IUpdateAvailableViewModel updateAvailableViewModel,
IMessageBoxService messageBoxService)
IMessageBoxService messageBoxService,
IClipboardService clipboardService)
{
_itemFilterScriptRepository = itemFilterScriptRepository;
_itemFilterScriptTranslator = itemFilterScriptTranslator;
@@ -71,14 +79,15 @@ namespace Filtration.ViewModels
_updateCheckService = updateCheckService;
_updateAvailableViewModel = updateAvailableViewModel;
_messageBoxService = messageBoxService;
_clipboardService = clipboardService;
NewScriptCommand = new RelayCommand(OnNewScriptCommand);
CopyScriptCommand = new RelayCommand(OnCopyScriptCommand, () => ActiveDocumentIsScript);
OpenScriptCommand = new RelayCommand(OnOpenScriptCommand);
OpenThemeCommand = new RelayCommand(OnOpenThemeCommand);
OpenScriptCommand = new RelayCommand(async () => await OnOpenScriptCommand());
OpenThemeCommand = new RelayCommand(async () => await OnOpenThemeCommandAsync());
SaveCommand = new RelayCommand(OnSaveDocumentCommand, ActiveDocumentIsEditable);
SaveAsCommand = new RelayCommand(OnSaveAsCommand, ActiveDocumentIsEditable);
SaveCommand = new RelayCommand(async () => await OnSaveDocumentCommandAsync(), ActiveDocumentIsEditable);
SaveAsCommand = new RelayCommand(async () => await OnSaveAsCommandAsync(), ActiveDocumentIsEditable);
CloseCommand = new RelayCommand(OnCloseDocumentCommand, ActiveDocumentIsEditable);
CopyBlockCommand = new RelayCommand(OnCopyBlockCommand, () => ActiveDocumentIsScript && ActiveScriptHasSelectedBlock);
@@ -102,7 +111,7 @@ namespace Filtration.ViewModels
ReplaceColorsCommand = new RelayCommand(OnReplaceColorsCommand, () => ActiveDocumentIsScript);
CreateThemeCommand = new RelayCommand(OnCreateThemeCommand, () => ActiveDocumentIsScript);
ApplyThemeToScriptCommand = new RelayCommand(OnApplyThemeToScriptCommand, () => ActiveDocumentIsScript);
ApplyThemeToScriptCommand = new RelayCommand(async () => await OnApplyThemeToScriptCommandAsync(), () => ActiveDocumentIsScript);
EditMasterThemeCommand = new RelayCommand(OnEditMasterThemeCommand, () => ActiveDocumentIsScript);
AddTextColorThemeComponentCommand = new RelayCommand(OnAddTextColorThemeComponentCommand, () => ActiveDocumentIsTheme && ActiveThemeIsEditable);
@@ -110,7 +119,7 @@ namespace Filtration.ViewModels
AddBorderColorThemeComponentCommand = new RelayCommand(OnAddBorderColorThemeComponentCommand, () => ActiveDocumentIsTheme && ActiveThemeIsEditable);
DeleteThemeComponentCommand = new RelayCommand(OnDeleteThemeComponentCommand,
() =>
ActiveDocumentIsTheme && ActiveDocumentIsTheme &&
ActiveDocumentIsTheme && ActiveThemeIsEditable &&
_avalonDockWorkspaceViewModel.ActiveThemeViewModel.SelectedThemeComponent != null);
ExpandAllBlocksCommand = new RelayCommand(OnExpandAllBlocksCommand, () => ActiveDocumentIsScript);
@@ -164,12 +173,28 @@ namespace Filtration.ViewModels
}
case "OpenScript":
{
#pragma warning disable 4014
OnOpenScriptCommand();
#pragma warning restore 4014
break;
}
case "ShowLoadingBanner":
{
ShowLoadingBanner = true;
break;
}
case "HideLoadingBanner":
{
ShowLoadingBanner = false;
break;
}
}
});
CheckForUpdates();
Task.Run(async () =>
{
await CheckForUpdatesAsync();
}).Wait();
}
public RelayCommand OpenScriptCommand { get; private set; }
@@ -213,14 +238,14 @@ namespace Filtration.ViewModels
public RelayCommand ClearFiltersCommand { get; private set; }
public async void CheckForUpdates()
public async Task CheckForUpdatesAsync()
{
var assemblyVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location);
var result = await _updateCheckService.GetUpdateData();
try
{
var result = await _updateCheckService.GetUpdateDataAsync();
if (result.LatestVersionMajorPart >= assemblyVersion.FileMajorPart &&
result.LatestVersionMinorPart > assemblyVersion.FileMinorPart)
{
@@ -277,6 +302,16 @@ namespace Filtration.ViewModels
}
}
public bool ShowLoadingBanner
{
get { return _showLoadingBanner; }
private set
{
_showLoadingBanner = value;
RaisePropertyChanged();
}
}
public bool ActiveDocumentIsScript
{
get { return _avalonDockWorkspaceViewModel.ActiveDocument != null && _avalonDockWorkspaceViewModel.ActiveDocument.IsScript; }
@@ -320,6 +355,29 @@ namespace Filtration.ViewModels
}
}
public async Task OpenDroppedFilesAsync(List<string> filenames)
{
foreach (var filename in filenames)
{
var extension = Path.GetExtension(filename);
if (extension == null) continue;
switch (extension.ToUpperInvariant())
{
case ".FILTER":
{
await LoadScriptAsync(filename);
break;
}
case ".FILTERTHEME":
{
await LoadThemeAsync(filename);
break;
}
}
}
}
private void OnCreateThemeCommand()
{
var themeViewModel = _themeProvider.NewThemeForScript(AvalonDockWorkspaceViewModel.ActiveScriptViewModel.Script);
@@ -360,24 +418,31 @@ namespace Filtration.ViewModels
var aboutWindow = new AboutWindow();
aboutWindow.ShowDialog();
}
private void OnOpenScriptCommand()
private async Task OnOpenScriptCommand()
{
var openFileDialog = new OpenFileDialog
var filePath = ShowOpenScriptDialog();
if (string.IsNullOrEmpty(filePath))
{
Filter = "Filter Files (*.filter)|*.filter|All Files (*.*)|*.*",
InitialDirectory = _itemFilterScriptRepository.GetItemFilterScriptDirectory()
};
return;
}
if (openFileDialog.ShowDialog() != true) return;
await LoadScriptAsync(filePath);
}
private async Task LoadScriptAsync(string scriptFilename)
{
IItemFilterScriptViewModel loadedViewModel;
Messenger.Default.Send(new NotificationMessage("ShowLoadingBanner"));
try
{
loadedViewModel = _itemFilterScriptRepository.LoadScriptFromFile(openFileDialog.FileName);
loadedViewModel = await _itemFilterScriptRepository.LoadScriptFromFileAsync(scriptFilename);
}
catch(IOException e)
catch (IOException e)
{
Messenger.Default.Send(new NotificationMessage("HideLoadingBanner"));
if (_logger.IsErrorEnabled)
{
_logger.Error(e);
@@ -388,23 +453,28 @@ namespace Filtration.ViewModels
return;
}
Messenger.Default.Send(new NotificationMessage("HideLoadingBanner"));
_avalonDockWorkspaceViewModel.AddDocument(loadedViewModel);
}
private void OnOpenThemeCommand()
private async Task OnOpenThemeCommandAsync()
{
var filePath = ShowOpenThemeDialog();
if (string.IsNullOrEmpty(filePath))
{
return;
}
await LoadThemeAsync(filePath);
}
private async Task LoadThemeAsync(string themeFilename)
{
IThemeEditorViewModel loadedViewModel;
try
{
loadedViewModel = _themeProvider.LoadThemeFromFile(filePath);
loadedViewModel = await _themeProvider.LoadThemeFromFile(themeFilename);
}
catch (IOException e)
{
@@ -417,11 +487,11 @@ namespace Filtration.ViewModels
MessageBoxImage.Error);
return;
}
_avalonDockWorkspaceViewModel.AddDocument(loadedViewModel);
}
private void OnApplyThemeToScriptCommand()
private async Task OnApplyThemeToScriptCommandAsync()
{
var filePath = ShowOpenThemeDialog();
if (string.IsNullOrEmpty(filePath))
@@ -433,7 +503,7 @@ namespace Filtration.ViewModels
try
{
loadedTheme = _themeProvider.LoadThemeModelFromFile(filePath);
loadedTheme = await _themeProvider.LoadThemeModelFromFile(filePath);
}
catch (IOException e)
{
@@ -459,6 +529,16 @@ namespace Filtration.ViewModels
AvalonDockWorkspaceViewModel.ActiveScriptViewModel.SetDirtyFlag();
}
private string ShowOpenScriptDialog()
{
var openFileDialog = new OpenFileDialog
{
Filter = "Filter Files (*.filter)|*.filter|All Files (*.*)|*.*",
InitialDirectory = _itemFilterScriptRepository.GetItemFilterScriptDirectory()
};
return openFileDialog.ShowDialog() != true ? string.Empty : openFileDialog.FileName;
}
private string ShowOpenThemeDialog()
{
@@ -471,8 +551,6 @@ namespace Filtration.ViewModels
return openFileDialog.ShowDialog() != true ? string.Empty : openFileDialog.FileName;
}
private void SetItemFilterScriptDirectory()
{
var dlg = new FolderBrowserDialog
@@ -488,14 +566,14 @@ namespace Filtration.ViewModels
}
}
private void OnSaveDocumentCommand()
private async Task OnSaveDocumentCommandAsync()
{
((IEditableDocument)_avalonDockWorkspaceViewModel.ActiveDocument).Save();
await ((IEditableDocument)_avalonDockWorkspaceViewModel.ActiveDocument).SaveAsync();
}
private void OnSaveAsCommand()
private async Task OnSaveAsCommandAsync()
{
((IEditableDocument)_avalonDockWorkspaceViewModel.ActiveDocument).SaveAs();
await ((IEditableDocument)_avalonDockWorkspaceViewModel.ActiveDocument).SaveAsAsync();
}
private void OnReplaceColorsCommand()
@@ -507,7 +585,18 @@ namespace Filtration.ViewModels
private void OnCopyScriptCommand()
{
Clipboard.SetText(_itemFilterScriptTranslator.TranslateItemFilterScriptToString(_avalonDockWorkspaceViewModel.ActiveScriptViewModel.Script));
try
{
_clipboardService.SetClipboardText(
_itemFilterScriptTranslator.TranslateItemFilterScriptToString(
_avalonDockWorkspaceViewModel.ActiveScriptViewModel.Script));
}
catch
{
_messageBoxService.Show("Clipboard Error", "Failed to access the clipboard, copy command not completed.",
MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void OnCopyBlockCommand()
@@ -626,5 +715,22 @@ namespace Filtration.ViewModels
_avalonDockWorkspaceViewModel.ActiveThemeViewModel.DeleteThemeComponentCommand.Execute(
_avalonDockWorkspaceViewModel.ActiveThemeViewModel.SelectedThemeComponent);
}
public async Task<bool> CloseAllDocumentsAsync()
{
var openDocuments = _avalonDockWorkspaceViewModel.OpenDocuments.OfType<IEditableDocument>().ToList();
foreach (var document in openDocuments)
{
var docCount = _avalonDockWorkspaceViewModel.OpenDocuments.OfType<IEditableDocument>().Count();
await document.Close();
if (_avalonDockWorkspaceViewModel.OpenDocuments.OfType<IEditableDocument>().Count() == docCount)
{
return false;
}
}
return true;
}
}
}

View File

@@ -1,4 +1,5 @@
using Filtration.Common.ViewModels;
using System.Threading.Tasks;
using Filtration.Common.ViewModels;
using Filtration.Interface;
using GalaSoft.MvvmLight.CommandWpf;
using GalaSoft.MvvmLight.Messaging;
@@ -25,7 +26,7 @@ namespace Filtration.ViewModels
public bool IsScript { get { return false; } }
public bool IsTheme { get { return false; } }
public void Close()
public Task Close()
{
throw new System.NotImplementedException();
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Windows.Media.Imaging;
using GalaSoft.MvvmLight.Messaging;
namespace Filtration.ViewModels.ToolPanes
{
@@ -23,6 +24,18 @@ namespace Filtration.ViewModels.ToolPanes
icon.UriSource = new Uri("pack://application:,,,/Filtration;component/Resources/Icons/add_section_icon.png");
icon.EndInit();
IconSource = icon;
Messenger.Default.Register<NotificationMessage>(this, message =>
{
switch (message.Notification)
{
case "SectionsChanged":
{
OnActiveDocumentChanged(this, EventArgs.Empty);
break;
}
}
});
}
public const string ToolContentId = "SectionBrowserTool";

View File

@@ -10,9 +10,10 @@
xmlns:converters="clr-namespace:Filtration.Converters"
xmlns:xcad="http://schemas.xceed.com/wpf/xaml/avalondock"
xmlns:themeEditorViews="clr-namespace:Filtration.ThemeEditor.Views;assembly=Filtration.ThemeEditor"
xmlns:gif="http://wpfanimatedgif.codeplex.com"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance d:Type=viewModels:AvalonDockWorkspaceViewModel}"
d:DesignHeight="300" d:DesignWidth="300">
d:DesignHeight="300" d:DesignWidth="700">
<UserControl.Resources>
<xcad:BoolToVisibilityConverter x:Key="AvalonBoolToVisibilityConverter" />
<converters:ActiveDocumentConverter x:Key="ActiveDocumentConverter" />

View File

@@ -271,7 +271,9 @@
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock Grid.Row="1" FontStyle="Italic" Visibility="{Binding HasAudioVisualBlockItems, Converter={StaticResource InverseBooleanVisibilityConverter}}">To change the appearance of this block, add a Text, Background or Border Block Item above.</TextBlock>
<!-- Block Items -->
<WrapPanel Grid.Row="1" MaxHeight="200">
<WrapPanel.Resources>

View File

@@ -8,15 +8,18 @@
xmlns:viewModels="clr-namespace:Filtration.ViewModels"
xmlns:viewsAvalonDock="clr-namespace:Filtration.Views.AvalonDock"
xmlns:views="clr-namespace:Filtration.Views"
xmlns:gif="http://wpfanimatedgif.codeplex.com"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=viewModels:MainWindowViewModel}"
Title="{Binding WindowTitle}" Height="762" Width="1126" IsIconVisible="True" >
Title="{Binding WindowTitle}" Height="762" Width="1126" IsIconVisible="True"
Closing="MainWindow_OnClosing" Drop="MainWindow_OnDrop" AllowDrop="True">
<fluent:RibbonWindow.InputBindings>
<KeyBinding Command="{Binding SaveCommand}" Modifiers="Control" Key="S" />
<KeyBinding Command="{Binding OpenScriptCommand}" Modifiers="Control" Key="O" />
<KeyBinding Command="{Binding NewScriptCommand}" Modifiers="Control" Key="N" />
</fluent:RibbonWindow.InputBindings>
<DockPanel x:Name="RootDockPanel">
<fluent:Ribbon DockPanel.Dock="Top" x:Name="RibbonRoot">
<fluent:Ribbon DockPanel.Dock="Top" x:Name="RibbonRoot" IsEnabled="{Binding ShowLoadingBanner, Converter={StaticResource BoolInverterConverter}}">
<fluent:Ribbon.Menu>
<fluent:Backstage>
<fluent:BackstageTabControl>
@@ -29,10 +32,10 @@
</DataTemplate>
</fluent:BackstageTabItem.ContentTemplate>
</fluent:BackstageTabItem>
<fluent:Button Header="New Script" Command="{Binding NewScriptCommand}" Icon="{StaticResource NewIcon}" />
<fluent:Button Header="Open Script" Command="{Binding OpenScriptCommand}" Icon="{StaticResource OpenIcon}" />
<fluent:Button Header="New Script" Command="{Binding NewScriptCommand}" Icon="{StaticResource NewIcon}" ToolTip="New Script (Ctrl+N)" />
<fluent:Button Header="Open Script" Command="{Binding OpenScriptCommand}" Icon="{StaticResource OpenIcon}" ToolTip="Open Script (Ctrl+O)" />
<fluent:Button Header="Open Theme" Command="{Binding OpenThemeCommand}" Icon="{StaticResource OpenIcon}" />
<fluent:Button Header="Save" Command="{Binding SaveCommand}" Icon="{StaticResource SaveIcon}" />
<fluent:Button Header="Save" Command="{Binding SaveCommand}" Icon="{StaticResource SaveIcon}" ToolTip="Save (Ctrl+S)" />
<fluent:Button Header="Save As" Command="{Binding SaveAsCommand}" Icon="{StaticResource SaveIcon}" />
<fluent:Button Header="Close" Command="{Binding CloseCommand}" />
<fluent:SeparatorTabItem />
@@ -71,10 +74,10 @@
</fluent:RibbonTabItem>
<fluent:RibbonTabItem x:Name="ScriptToolsTabItem" Header="Script Tools" Group="{Binding ElementName=ScriptToolsGroup}" Visibility="{Binding ActiveDocumentIsScript, Converter={StaticResource BooleanVisibilityConverter}, Mode=OneWay}" >
<fluent:RibbonGroupBox Header="Clipboard">
<fluent:Button Header="Copy Block" Command="{Binding CopyBlockCommand}" Icon="{StaticResource CopyIcon}" LargeIcon="{StaticResource CopyIcon}"/>
<fluent:Button Header="Paste Block" Command="{Binding PasteCommand}" Icon="{StaticResource PasteIcon}" LargeIcon="{StaticResource PasteIcon}" />
<fluent:Button Header="Copy Style" Command="{Binding CopyBlockStyleCommand}" Icon="{StaticResource CopyIcon}" LargeIcon="{StaticResource CopyIcon}" SizeDefinition="Middle" />
<fluent:Button Header="Paste Style" Command="{Binding PasteBlockStyleCommand}" Icon="{StaticResource PasteStyleIcon}" LargeIcon="{StaticResource PasteIcon}" SizeDefinition="Middle" />
<fluent:Button Header="Copy Block" Command="{Binding CopyBlockCommand}" Icon="{StaticResource CopyIcon}" LargeIcon="{StaticResource CopyIcon}" ToolTip="Copy Block (Ctrl+C)"/>
<fluent:Button Header="Paste Block" Command="{Binding PasteCommand}" Icon="{StaticResource PasteIcon}" LargeIcon="{StaticResource PasteIcon}" ToolTip="Paste Block (Ctrl+V)"/>
<fluent:Button Header="Copy Style" Command="{Binding CopyBlockStyleCommand}" Icon="{StaticResource CopyIcon}" LargeIcon="{StaticResource CopyIcon}" SizeDefinition="Middle" ToolTip="Copy Style (Ctrl+Shift+C)" />
<fluent:Button Header="Paste Style" Command="{Binding PasteBlockStyleCommand}" Icon="{StaticResource PasteStyleIcon}" LargeIcon="{StaticResource PasteIcon}" SizeDefinition="Middle" ToolTip="Paste Style (Ctrl+Shift+V)" />
<fluent:Button Header="Copy Script" Command="{Binding CopyScriptCommand}" Icon="{StaticResource CopyIcon}" LargeIcon="{StaticResource PasteIcon}" SizeDefinition="Middle" />
</fluent:RibbonGroupBox>
<fluent:RibbonGroupBox Header="Blocks">
@@ -116,6 +119,30 @@
</fluent:Ribbon>
<Grid>
<viewsAvalonDock:AvalonDockWorkspaceView DataContext="{Binding AvalonDockWorkspaceViewModel}" />
<Grid ZIndex="9999" Visibility="{Binding ShowLoadingBanner, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter={x:Static Visibility.Hidden}}">
<Grid.Background>
<SolidColorBrush Color="Black" Opacity="0.5" />
</Grid.Background>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Grid.Row="1" Grid.Column="1" BorderBrush="Black" BorderThickness="1" Background="White" Padding="20">
<StackPanel Orientation="Horizontal">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="20" FontWeight="DemiBold">Working...</TextBlock>
<Image gif:ImageBehavior.AnimatedSource="/Filtration;component/Resources/loading_spinner.gif" Height="32" Margin="10,0,0,0"/>
</StackPanel>
</Border>
</Grid>
</Grid>
</Grid>
</DockPanel>
</fluent:RibbonWindow>

View File

@@ -1,4 +1,8 @@
using System.Windows;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using Filtration.ViewModels;
namespace Filtration.Views
@@ -10,8 +14,11 @@ namespace Filtration.Views
internal partial class MainWindow : IMainWindow
{
private readonly IMainWindowViewModel _mainWindowViewModel;
public MainWindow(IMainWindowViewModel mainWindowViewModel)
{
_mainWindowViewModel = mainWindowViewModel;
InitializeComponent();
DataContext = mainWindowViewModel;
}
@@ -31,5 +38,38 @@ namespace Filtration.Views
RibbonRoot.SelectedTabItem = ThemeToolsTabItem;
}
}
private void MainWindow_OnClosing(object sender, CancelEventArgs e)
{
var allDocumentsClosed = _mainWindowViewModel.CloseAllDocumentsAsync().Result;
if (!allDocumentsClosed)
{
e.Cancel = true;
}
}
private async void MainWindow_OnDrop(object sender, DragEventArgs e)
{
if (!e.Data.GetDataPresent(DataFormats.FileDrop)) return;
var filenames = (string[])e.Data.GetData(DataFormats.FileDrop);
var droppedFilterFiles = new List<string>();
foreach (var filename in filenames)
{
var extension = Path.GetExtension(filename);
if (extension != null &&
(extension.ToUpperInvariant() == ".FILTER" || extension.ToUpperInvariant() == ".FILTERTHEME"))
{
droppedFilterFiles.Add(filename);
}
}
if (droppedFilterFiles.Count > 0)
{
await _mainWindowViewModel.OpenDroppedFilesAsync(droppedFilterFiles);
}
}
}
}

View File

@@ -1,14 +0,0 @@
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
namespace Filtration.WindsorInstallers
{
public class ModelsInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
}
}
}

View File

@@ -34,6 +34,11 @@ namespace Filtration.WindsorInstallers
Component.For<IUpdateCheckService>()
.ImplementedBy<UpdateCheckService>()
.LifeStyle.Singleton);
container.Register(
Component.For<IClipboardService>()
.ImplementedBy<ClipboardService>()
.LifeStyle.Singleton);
}
}
}

View File

@@ -11,5 +11,6 @@
<package id="NLog" version="4.0.1" targetFramework="net451" />
<package id="NLog.Config" version="4.0.1" targetFramework="net451" />
<package id="NLog.Schema" version="4.0.1" targetFramework="net451" />
<package id="WpfAnimatedGif" version="1.4.13" targetFramework="net451" />
<package id="WPFToolkit" version="3.5.50211.1" targetFramework="net451" />
</packages>

View File

@@ -2,10 +2,10 @@
Filtration is an editor for Path of Exile item filter scripts.
## Current Release (Released 2015-07-06)
<b>Installer (6.31mb)</b> <a href="https://github.com/ben-wallis/Filtration/releases/download/0.7/filtration_0.7_setup.exe">filtration_0.7_setup.exe</a>
## Current Release (Released 2015-07-26)
<b>Installer (6.37mb)</b> <a href="https://github.com/ben-wallis/Filtration/releases/download/0.10/filtration_0.10_setup.exe">filtration_0.10_setup.exe</a>
<b>Zip File (7.91mb)</b> <a href="https://github.com/ben-wallis/Filtration/releases/download/0.7/filtration_0.7.zip">filtration_0.7.zip</a>
<b>Zip File (7.97mb)</b> <a href="https://github.com/ben-wallis/Filtration/releases/download/0.10/filtration_0.10.zip">filtration_0.10.zip</a>
## System Requirements
Filtration requires .NET Framework 4.5.1 installed.