Gearing up for release.

Added installer. Consolidated logic for scanner. Fixed some race conditions with file access. Changed icon.
This commit is contained in:
Jordan Wages 2021-02-12 01:30:36 -06:00
parent f230812765
commit 0c5cb4df3b
14 changed files with 546 additions and 317 deletions

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="MDFinder" Language="1033" Version="0.9.0.0" Manufacturer="Jordan Wages" UpgradeCode="bed4df95-335c-4e57-be16-4fb662f39921">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate EmbedCab="yes" />
<Feature Id="ProductFeature" Title="mdfinder.installer" Level="1">
<ComponentGroupRef Id="ProductComponents" />
</Feature>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="mdfinder" />
</Directory>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<!-- TODO: Remove the comments around this Component element and the ComponentRef below in order to add resources to this installer. -->
<Component Id="mdfinder" Guid="6D7CD382-5E6D-44A8-953D-AF135FD2865E">
<File Source="$(var.mdfinder.TargetDir)" Id="csmic.dll" />
<File Source="$(var.mdfinder.TargetDir)" Id="mdfinder.exe.config" />
<File Source="$(var.mdfinder.TargetDir)" Id="Gu.Wpf.Media.dll" />
<File Source="$(var.mdfinder.TargetDir)" Id="LiteDB.dll" />
<File Source="$(var.mdfinder.TargetDir)" Id="Octokit.dll" />
<File Source="$(var.mdfinder.TargetDir)" Id="mdfinder.hashprovider.dll" />
<File Source="$(var.mdfinder.TargetPath)" />
</Component>
</ComponentGroup>
</Fragment>
</Wix>

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" InitialTargets="EnsureWixToolsetInstalled" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>3.10</ProductVersion>
<ProjectGuid>a8185834-0eea-4255-86df-fea9dfdf9752</ProjectGuid>
<SchemaVersion>2.0</SchemaVersion>
<OutputName>mdfinder.installer</OutputName>
<OutputType>Package</OutputType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<OutputPath>bin\$(Configuration)\</OutputPath>
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
<DefineConstants>Debug</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<OutputPath>bin\$(Configuration)\</OutputPath>
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
</PropertyGroup>
<ItemGroup>
<Compile Include="Product.wxs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\mdfinder.hashprovider\mdfinder.hashprovider.csproj">
<Name>mdfinder.hashprovider</Name>
<Project>{f383e2d1-f62e-44cf-9e58-63542dcbd06e}</Project>
<Private>True</Private>
<DoNotHarvest>True</DoNotHarvest>
<RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>
<RefTargetDir>INSTALLFOLDER</RefTargetDir>
</ProjectReference>
<ProjectReference Include="..\mdfinder\mdfinder.csproj">
<Name>mdfinder</Name>
<Project>{e0f831fa-fce1-471e-8767-d3fd7edc7ccf}</Project>
<Private>True</Private>
<DoNotHarvest>True</DoNotHarvest>
<RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>
<RefTargetDir>INSTALLFOLDER</RefTargetDir>
</ProjectReference>
</ItemGroup>
<Import Project="$(WixTargetsPath)" Condition=" '$(WixTargetsPath)' != '' " />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets" Condition=" '$(WixTargetsPath)' == '' AND Exists('$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets') " />
<Target Name="EnsureWixToolsetInstalled" Condition=" '$(WixTargetsImported)' != 'true' ">
<Error Text="The WiX Toolset v3.11 (or newer) build tools must be installed to build this project. To download the WiX Toolset, see http://wixtoolset.org/releases/" />
</Target>
<!--
To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Wix.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -7,20 +7,38 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mdfinder", "mdfinder\mdfind
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mdfinder.hashprovider", "mdfinder.hashprovider\mdfinder.hashprovider.csproj", "{F383E2D1-F62E-44CF-9E58-63542DCBD06E}"
EndProject
Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "mdfinder.installer", "mdfinder.installer\mdfinder.installer.wixproj", "{A8185834-0EEA-4255-86DF-FEA9DFDF9752}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E0F831FA-FCE1-471E-8767-D3FD7EDC7CCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E0F831FA-FCE1-471E-8767-D3FD7EDC7CCF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E0F831FA-FCE1-471E-8767-D3FD7EDC7CCF}.Debug|x86.ActiveCfg = Debug|Any CPU
{E0F831FA-FCE1-471E-8767-D3FD7EDC7CCF}.Debug|x86.Build.0 = Debug|Any CPU
{E0F831FA-FCE1-471E-8767-D3FD7EDC7CCF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E0F831FA-FCE1-471E-8767-D3FD7EDC7CCF}.Release|Any CPU.Build.0 = Release|Any CPU
{E0F831FA-FCE1-471E-8767-D3FD7EDC7CCF}.Release|x86.ActiveCfg = Release|Any CPU
{E0F831FA-FCE1-471E-8767-D3FD7EDC7CCF}.Release|x86.Build.0 = Release|Any CPU
{F383E2D1-F62E-44CF-9E58-63542DCBD06E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F383E2D1-F62E-44CF-9E58-63542DCBD06E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F383E2D1-F62E-44CF-9E58-63542DCBD06E}.Debug|x86.ActiveCfg = Debug|Any CPU
{F383E2D1-F62E-44CF-9E58-63542DCBD06E}.Debug|x86.Build.0 = Debug|Any CPU
{F383E2D1-F62E-44CF-9E58-63542DCBD06E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F383E2D1-F62E-44CF-9E58-63542DCBD06E}.Release|Any CPU.Build.0 = Release|Any CPU
{F383E2D1-F62E-44CF-9E58-63542DCBD06E}.Release|x86.ActiveCfg = Release|Any CPU
{F383E2D1-F62E-44CF-9E58-63542DCBD06E}.Release|x86.Build.0 = Release|Any CPU
{A8185834-0EEA-4255-86DF-FEA9DFDF9752}.Debug|Any CPU.ActiveCfg = Debug|x86
{A8185834-0EEA-4255-86DF-FEA9DFDF9752}.Debug|x86.ActiveCfg = Debug|x86
{A8185834-0EEA-4255-86DF-FEA9DFDF9752}.Debug|x86.Build.0 = Debug|x86
{A8185834-0EEA-4255-86DF-FEA9DFDF9752}.Release|Any CPU.ActiveCfg = Release|x86
{A8185834-0EEA-4255-86DF-FEA9DFDF9752}.Release|x86.ActiveCfg = Release|x86
{A8185834-0EEA-4255-86DF-FEA9DFDF9752}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -1,11 +1,7 @@
using LiteDB;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace mdfinder
{
@ -35,6 +31,16 @@ namespace mdfinder
}
}
/// <summary> Gets the database statistics string. </summary>
/// <value> The database statistics. </value>
public string DbStatistics
{
get
{
return string.Format("{0} Files In Database.", this.FileRecordCollection.Count());
}
}
#endregion Properties
#region Constructors
@ -42,7 +48,7 @@ namespace mdfinder
/// <summary> Default constructor. </summary>
public DBHelper()
{
this.Database = new LiteDatabase(DEFAULT_DB_FILE_NAME);
this.Database = new LiteDatabase(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), DEFAULT_DB_FILE_NAME));
}
/// <summary> Constructor. </summary>
@ -65,6 +71,8 @@ namespace mdfinder
{
var fileRecord = new FileRecord(path, size, hash, hashProvider);
this.FileRecordCollection.Upsert(fileRecord);
this.OnPropertyChanged("DbStatistics");
}
/// <summary> Removes the file record described by its path. </summary>
@ -72,6 +80,8 @@ namespace mdfinder
public void RemoveFileRecord(string id)
{
this.FileRecordCollection.Delete(fr => fr.Id == id);
this.OnPropertyChanged("DbStatistics");
}
/// <summary> Gets the file records in this collection. </summary>
@ -97,6 +107,8 @@ namespace mdfinder
public void Clear()
{
this.FileRecordCollection.Delete(Query.All());
this.OnPropertyChanged("DbStatistics");
}
#endregion Methods

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 806 B

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -1,6 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
@ -9,37 +7,41 @@
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
viewBox="0 0 64 64"
sodipodi:docname="icon.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
width="128.0px"
height="128.0px"
viewBox="0 0 128.0 128.0"
version="1.1"
id="SVGRoot"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="icon.svg">
id="SVGRoot">
<defs
id="defs815" />
id="defs833" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.6568542"
inkscape:cx="-5.6227241"
inkscape:cy="50.292753"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1057"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:snap-global="true"
inkscape:window-maximized="1"
inkscape:grid-bbox="true"
inkscape:snap-bbox="true" />
inkscape:window-y="357"
inkscape:window-x="1072"
inkscape:window-height="1417"
inkscape:window-width="3440"
showgrid="true"
inkscape:document-rotation="0"
inkscape:current-layer="layer1"
inkscape:document-units="px"
inkscape:cy="89.76195"
inkscape:cx="48.534596"
inkscape:zoom="5.6568542"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base">
<inkscape:grid
type="xygrid"
id="grid1403" />
</sodipodi:namedview>
<metadata
id="metadata818">
id="metadata836">
<rdf:RDF>
<cc:Work
rdf:about="">
@ -51,102 +53,107 @@
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
id="layer1"
inkscape:groupmode="layer"
id="layer1">
inkscape:label="Layer 1">
<g
id="g1425"
transform="translate(4.125,0.75)">
<g
id="g1396">
transform="translate(0.22489393,-25.677048)"
id="g1585">
<rect
style="fill:#c2092f;fill-opacity:1;stroke:#000000;stroke-width:2.00617;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect1410"
width="52.96468"
height="15.501858"
x="3.1943736"
y="60.288105" />
<rect
y="81.926117"
x="3.1943736"
height="15.501858"
width="52.96468"
id="rect1410-5"
style="fill:#00732b;fill-opacity:1;stroke:#000000;stroke-width:2.00617;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
y="103.56413"
x="3.1943736"
height="15.501858"
width="52.96468"
id="rect1410-9"
style="fill:#b5732b;fill-opacity:1;stroke:#000000;stroke-width:2.00617;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
y="71.053925"
x="107.83192"
height="16.362434"
width="16.362461"
id="rect1410-4"
style="fill:#ffe718;fill-opacity:1;stroke:#000000;stroke-width:2.0062;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
style="fill:#0ba7d1;fill-opacity:1;stroke:#000000;stroke-width:2.0062;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect1410-4-3"
width="16.362461"
height="16.362434"
x="107.99336"
y="92.69194" />
<path
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 18.875,6.0625 v 50.375"
id="path1377"
inkscape:connector-curvature="0" />
id="path1477-5"
d="M 56.159055,90 H 70"
style="fill:none;stroke:#000000;stroke-width:1.09179px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 36.875,6.0625 v 50.375"
id="path1377-6"
inkscape:connector-curvature="0" />
id="path1477-4"
d="M 56.159055,110.66914 H 70"
style="fill:none;stroke:#000000;stroke-width:1.09179px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
id="path1477-0"
d="m 93.99097,79.665428 h 13.84094"
style="fill:none;stroke:#000000;stroke-width:1.09179px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
id="path1477-7"
d="m 94.9137,100.33457 h 13.84095"
style="fill:none;stroke:#000000;stroke-width:1.09179px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="fill:none;stroke:#000000;stroke-width:1.09179px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
d="M 70,90 93.99097,79.665428"
id="path1512" />
<path
style="fill:none;stroke:#000000;stroke-width:1.09179px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
d="M 56.159055,68.039034 H 70"
id="path1525" />
<path
style="fill:none;stroke:#000000;stroke-width:1.09179px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
d="M 94.9137,100.33457 70,68.039034"
id="path1514" />
<path
style="fill:none;stroke:#000000;stroke-width:1.09179px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
d="M 70,110.66914 94.9137,100.33457"
id="path1520" />
</g>
<g
transform="rotate(90,27.875,31.25)"
id="g1396-3">
transform="translate(-4.5526783,-1.286792)"
id="g1593">
<circle
style="fill:#66c0c8;fill-opacity:0.16049381;stroke:#e9e9e9;stroke-width:4.92946;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path1555"
cx="51.918816"
cy="50.387043"
r="31.741579" />
<path
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 18.875,6.0625 v 50.375"
id="path1377-8"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 36.875,6.0625 v 50.375"
id="path1377-6-2"
inkscape:connector-curvature="0" />
style="fill:none;stroke:#e9e9e9;stroke-width:11.2551;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 80,75 33.7653,33.7653"
id="path1557" />
<circle
d="m -34.979605,-52.489803 a 18.008158,18.008158 0 0 1 -18.008157,18.008157"
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2.25102;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path1565"
sodipodi:type="arc"
sodipodi:cx="-52.987762"
sodipodi:cy="-52.489803"
sodipodi:rx="18.008158"
sodipodi:ry="18.008158"
sodipodi:start="0"
sodipodi:end="1.5707963"
sodipodi:open="true"
sodipodi:arc-type="arc"
transform="scale(-1)" />
</g>
</g>
<rect
style="opacity:1;fill:#4aae59;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect1427"
width="14.142136"
height="14.142136"
x="6.8125"
y="6.8125" />
<rect
style="opacity:1;fill:#ae4a4a;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect1427-3"
width="14.142136"
height="14.142136"
x="24.928932"
y="24.928932" />
<rect
style="opacity:1;fill:#4a94ae;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect1427-7"
width="14.142136"
height="14.142136"
x="24.928932"
y="6.8125" />
<rect
style="opacity:1;fill:#984aae;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect1427-38"
width="14.142136"
height="14.142136"
x="43.045364"
y="6.8125" />
<rect
style="opacity:1;fill:#7c7c7c;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect1427-2"
width="14.142136"
height="14.142136"
x="43.045364"
y="24.928932" />
<rect
style="opacity:1;fill:#aea74a;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect1427-4"
width="14.142136"
height="14.142136"
x="6.8125"
y="24.928932" />
<rect
style="opacity:1;fill:#4a5cae;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect1427-5"
width="14.142136"
height="14.142136"
x="6.8125"
y="43.045364" />
<rect
style="opacity:1;fill:#ae8a4a;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect1427-8"
width="14.142136"
height="14.142136"
x="24.928932"
y="43.045364" />
<rect
style="opacity:1;fill:#d3dc1c;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect1427-1"
width="14.142136"
height="14.142136"
x="43.045364"
y="43.045364" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@ -1,52 +1,76 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:mdfinder">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ControlTemplate x:Key="MdfinderUIIcon">
<Viewbox>
<Canvas Width="64" Height="64">
<Canvas Width="128" Height="128">
<Canvas Name="layer1">
<Canvas Name="g1425">
<Canvas Name="g1585">
<Canvas.RenderTransform>
<TranslateTransform X="4.125" Y="0.75"/>
<TranslateTransform X="0.22489393" Y="-25.677048" />
</Canvas.RenderTransform>
<Canvas Name="g1396">
<Path xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path1377" StrokeThickness="1" Stroke="#FF000000" StrokeMiterLimit="4" StrokeLineJoin="Miter" StrokeStartLineCap="Flat" StrokeEndLineCap="Flat">
<Rectangle xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Canvas.Left="3.1943736" Canvas.Top="60.288105" Width="52.96468" Height="15.501858" Name="rect1410" Fill="#FFC2092F" StrokeThickness="2.00617" Stroke="#FF000000" StrokeMiterLimit="4" StrokeStartLineCap="Round" StrokeEndLineCap="Round" />
<Rectangle xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Canvas.Left="3.1943736" Canvas.Top="81.926117" Width="52.96468" Height="15.501858" Name="rect14105" Fill="#FF00732B" StrokeThickness="2.00617" Stroke="#FF000000" StrokeMiterLimit="4" StrokeStartLineCap="Round" StrokeEndLineCap="Round" />
<Rectangle xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Canvas.Left="3.1943736" Canvas.Top="103.56413" Width="52.96468" Height="15.501858" Name="rect14109" Fill="#FFB5732B" StrokeThickness="2.00617" Stroke="#FF000000" StrokeMiterLimit="4" StrokeStartLineCap="Round" StrokeEndLineCap="Round" />
<Rectangle xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Canvas.Left="107.83192" Canvas.Top="71.053925" Width="16.362461" Height="16.362434" Name="rect14104" Fill="#FFFFE718" StrokeThickness="2.0062" Stroke="#FF000000" StrokeMiterLimit="4" StrokeStartLineCap="Round" StrokeEndLineCap="Round" />
<Rectangle xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Canvas.Left="107.99336" Canvas.Top="92.69194" Width="16.362461" Height="16.362434" Name="rect141043" Fill="#FF0BA7D1" StrokeThickness="2.0062" Stroke="#FF000000" StrokeMiterLimit="4" StrokeStartLineCap="Round" StrokeEndLineCap="Round" />
<Path xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path14775" StrokeThickness="1.09179" Stroke="#FF000000" StrokeLineJoin="Miter" StrokeStartLineCap="Flat" StrokeEndLineCap="Flat">
<Path.Data>
<PathGeometry Figures="m 18.875 6.0625 v 50.375" FillRule="NonZero"/>
<PathGeometry Figures="M 56.159055 90 H 70" FillRule="NonZero" />
</Path.Data>
</Path>
<Path xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path13776" StrokeThickness="1" Stroke="#FF000000" StrokeMiterLimit="4" StrokeLineJoin="Miter" StrokeStartLineCap="Flat" StrokeEndLineCap="Flat">
<Path xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path14774" StrokeThickness="1.09179" Stroke="#FF000000" StrokeLineJoin="Miter" StrokeStartLineCap="Flat" StrokeEndLineCap="Flat">
<Path.Data>
<PathGeometry Figures="m 36.875 6.0625 v 50.375" FillRule="NonZero"/>
<PathGeometry Figures="M 56.159055 110.66914 H 70" FillRule="NonZero" />
</Path.Data>
</Path>
<Path xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path14770" StrokeThickness="1.09179" Stroke="#FF000000" StrokeLineJoin="Miter" StrokeStartLineCap="Flat" StrokeEndLineCap="Flat">
<Path.Data>
<PathGeometry Figures="m 93.99097 79.665428 h 13.84094" FillRule="NonZero" />
</Path.Data>
</Path>
<Path xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path14777" StrokeThickness="1.09179" Stroke="#FF000000" StrokeLineJoin="Miter" StrokeStartLineCap="Flat" StrokeEndLineCap="Flat">
<Path.Data>
<PathGeometry Figures="m 94.9137 100.33457 h 13.84095" FillRule="NonZero" />
</Path.Data>
</Path>
<Path xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path1512" StrokeThickness="1.09179" Stroke="#FF000000" StrokeLineJoin="Miter" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
<Path.Data>
<PathGeometry Figures="M 70 90 93.99097 79.665428" FillRule="NonZero" />
</Path.Data>
</Path>
<Path xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path1525" StrokeThickness="1.09179" Stroke="#FF000000" StrokeLineJoin="Round" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
<Path.Data>
<PathGeometry Figures="M 56.159055 68.039034 H 70" FillRule="NonZero" />
</Path.Data>
</Path>
<Path xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path1514" StrokeThickness="1.09179" Stroke="#FF000000" StrokeLineJoin="Round" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
<Path.Data>
<PathGeometry Figures="M 94.9137 100.33457 70 68.039034" FillRule="NonZero" />
</Path.Data>
</Path>
<Path xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path1520" StrokeThickness="1.09179" Stroke="#FF000000" StrokeLineJoin="Miter" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
<Path.Data>
<PathGeometry Figures="M 70 110.66914 94.9137 100.33457" FillRule="NonZero" />
</Path.Data>
</Path>
</Canvas>
<Canvas Name="g13963">
<Canvas Name="g1593">
<Canvas.RenderTransform>
<RotateTransform Angle="90" CenterX="27.875" CenterY="31.25"/>
<TranslateTransform X="-4.5526783" Y="-1.286792" />
</Canvas.RenderTransform>
<Path xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path13778" StrokeThickness="1" Stroke="#FF000000" StrokeMiterLimit="4" StrokeLineJoin="Miter" StrokeStartLineCap="Flat" StrokeEndLineCap="Flat">
<Ellipse xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Canvas.Left="20.2" Canvas.Top="18.6" Width="63.5" Height="63.5" Name="path1555" Fill="#2966C0C8" StrokeThickness="4.92946" Stroke="#FFE9E9E9" StrokeMiterLimit="4" StrokeLineJoin="Round" StrokeStartLineCap="Round" StrokeEndLineCap="Round" />
<Path xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path1557" StrokeThickness="11.2551" Stroke="#FFE9E9E9" StrokeMiterLimit="4" StrokeLineJoin="Miter" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
<Path.Data>
<PathGeometry Figures="m 18.875 6.0625 v 50.375" FillRule="NonZero"/>
</Path.Data>
</Path>
<Path xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path137762" StrokeThickness="1" Stroke="#FF000000" StrokeMiterLimit="4" StrokeLineJoin="Miter" StrokeStartLineCap="Flat" StrokeEndLineCap="Flat">
<Path.Data>
<PathGeometry Figures="m 36.875 6.0625 v 50.375" FillRule="NonZero"/>
<PathGeometry Figures="m 80 75 33.7653 33.7653" FillRule="NonZero" />
</Path.Data>
</Path>
<Ellipse xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path1565" StrokeThickness="2.25102" Stroke="#FFFFFFFF" StrokeMiterLimit="4" StrokeLineJoin="Round" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
<Ellipse.RenderTransform>
<ScaleTransform ScaleX="-1" ScaleY="-1" />
</Ellipse.RenderTransform>
</Ellipse>
</Canvas>
</Canvas>
<Rectangle xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Canvas.Left="6.8125" Canvas.Top="6.8125" Width="14.142136" Height="14.142136" Name="rect1427" Fill="#FF4AAE59" StrokeThickness="1" StrokeMiterLimit="4" StrokeStartLineCap="Round" StrokeEndLineCap="Round" Opacity="1"/>
<Rectangle xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Canvas.Left="24.928932" Canvas.Top="24.928932" Width="14.142136" Height="14.142136" Name="rect14273" Fill="#FFAE4A4A" StrokeThickness="1" StrokeMiterLimit="4" StrokeStartLineCap="Round" StrokeEndLineCap="Round" Opacity="1"/>
<Rectangle xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Canvas.Left="24.928932" Canvas.Top="6.8125" Width="14.142136" Height="14.142136" Name="rect14277" Fill="#FF4A94AE" StrokeThickness="1" StrokeMiterLimit="4" StrokeStartLineCap="Round" StrokeEndLineCap="Round" Opacity="1"/>
<Rectangle xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Canvas.Left="43.045364" Canvas.Top="6.8125" Width="14.142136" Height="14.142136" Name="rect142738" Fill="#FF984AAE" StrokeThickness="1" StrokeMiterLimit="4" StrokeStartLineCap="Round" StrokeEndLineCap="Round" Opacity="1"/>
<Rectangle xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Canvas.Left="43.045364" Canvas.Top="24.928932" Width="14.142136" Height="14.142136" Name="rect14272" Fill="#FF7C7C7C" StrokeThickness="1" StrokeMiterLimit="4" StrokeStartLineCap="Round" StrokeEndLineCap="Round" Opacity="1"/>
<Rectangle xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Canvas.Left="6.8125" Canvas.Top="24.928932" Width="14.142136" Height="14.142136" Name="rect14274" Fill="#FFAEA74A" StrokeThickness="1" StrokeMiterLimit="4" StrokeStartLineCap="Round" StrokeEndLineCap="Round" Opacity="1"/>
<Rectangle xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Canvas.Left="6.8125" Canvas.Top="43.045364" Width="14.142136" Height="14.142136" Name="rect14275" Fill="#FF4A5CAE" StrokeThickness="1" StrokeMiterLimit="4" StrokeStartLineCap="Round" StrokeEndLineCap="Round" Opacity="1"/>
<Rectangle xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Canvas.Left="24.928932" Canvas.Top="43.045364" Width="14.142136" Height="14.142136" Name="rect14278" Fill="#FFAE8A4A" StrokeThickness="1" StrokeMiterLimit="4" StrokeStartLineCap="Round" StrokeEndLineCap="Round" Opacity="1"/>
<Rectangle xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Canvas.Left="43.045364" Canvas.Top="43.045364" Width="14.142136" Height="14.142136" Name="rect14271" Fill="#FFD3DC1C" StrokeThickness="1" StrokeMiterLimit="4" StrokeStartLineCap="Round" StrokeEndLineCap="Round" Opacity="1"/>
</Canvas>
</Canvas>
</Viewbox>
</ControlTemplate>

View File

@ -132,6 +132,15 @@ namespace mdfinder.Localization {
}
}
/// <summary>
/// Looks up a localized string similar to Keep the largest item from each duplicate file group.
/// </summary>
public static string ActionLargestTooltip {
get {
return ResourceManager.GetString("ActionLargestTooltip", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to KeepSelected.
/// </summary>
@ -141,6 +150,15 @@ namespace mdfinder.Localization {
}
}
/// <summary>
/// Looks up a localized string similar to Keep the selected items from each duplicate file group.
/// </summary>
public static string ActionSelectedTooltip {
get {
return ResourceManager.GetString("ActionSelectedTooltip", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Keep Smallest.
/// </summary>
@ -150,6 +168,15 @@ namespace mdfinder.Localization {
}
}
/// <summary>
/// Looks up a localized string similar to Keep the smallest item from each duplicate file group.
/// </summary>
public static string ActionSmallestTooltip {
get {
return ResourceManager.GetString("ActionSmallestTooltip", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Archive Folder.
/// </summary>
@ -204,6 +231,15 @@ namespace mdfinder.Localization {
}
}
/// <summary>
/// Looks up a localized string similar to Clear the file database completely.
/// </summary>
public static string ClearTooltip {
get {
return ResourceManager.GetString("ClearTooltip", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Keep File.
/// </summary>
@ -384,6 +420,15 @@ namespace mdfinder.Localization {
}
}
/// <summary>
/// Looks up a localized string similar to Mark this set of files as unique.
/// </summary>
public static string NotDuplicateTooltip {
get {
return ResourceManager.GetString("NotDuplicateTooltip", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to OK.
/// </summary>
@ -493,7 +538,7 @@ namespace mdfinder.Localization {
}
/// <summary>
/// Looks up a localized string similar to Scan Location.
/// Looks up a localized string similar to Scanning Actions.
/// </summary>
public static string ScanningLabel {
get {

View File

@ -244,7 +244,7 @@
<value>Location to Scan</value>
</data>
<data name="ScanningLabel" xml:space="preserve">
<value>Scan Location</value>
<value>Scanning Actions</value>
</data>
<data name="ScanTooltip" xml:space="preserve">
<value>Scan the selected path</value>
@ -285,4 +285,19 @@
<data name="NotDupliateLabel" xml:space="preserve">
<value>Not A Duplicate</value>
</data>
<data name="ActionLargestTooltip" xml:space="preserve">
<value>Keep the largest item from each duplicate file group</value>
</data>
<data name="ActionSelectedTooltip" xml:space="preserve">
<value>Keep the selected items from each duplicate file group</value>
</data>
<data name="ActionSmallestTooltip" xml:space="preserve">
<value>Keep the smallest item from each duplicate file group</value>
</data>
<data name="ClearTooltip" xml:space="preserve">
<value>Clear the file database completely</value>
</data>
<data name="NotDuplicateTooltip" xml:space="preserve">
<value>Mark this set of files as unique</value>
</data>
</root>

View File

@ -1,13 +1,14 @@
<Window x:Class="mdfinder.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:gu="https://github.com/JohanLarsson/Gu.Wpf.Media"
xmlns:mdfinder="clr-namespace:mdfinder"
xmlns:loc="clr-namespace:mdfinder.Localization"
xmlns:gu="https://github.com/JohanLarsson/Gu.Wpf.Media"
mc:Ignorable="d"
Title="{x:Static loc:Localization.Title}" Height="520.293" Width="1055.509">
Title="{x:Static loc:Localization.Title}" Height="520.293" Width="1055.509"
Icon="./Icon/icon.ico">
<Window.Resources>
<mdfinder:InverseBoolConverter x:Key="InverseBoolConverter" />
<mdfinder:BoolVisibilityConverter x:Key="BoolVisibilityConverter" />
@ -15,6 +16,9 @@
<mdfinder:URIConverter x:Key="URIConverter" />
<mdfinder:SizeConverter x:Key="SizeConverter" />
</Window.Resources>
<Window.TaskbarItemInfo>
<TaskbarItemInfo x:Name="taskBarInfo" Description="Taskbar progress"></TaskbarItemInfo>
</Window.TaskbarItemInfo>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="{x:Static loc:Localization.FileMenu}">
@ -66,6 +70,8 @@
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="32" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
@ -78,35 +84,37 @@
<Label Content="{x:Static loc:Localization.ScanLabel}" />
</StackPanel>
</Button>
<Button Grid.Row="0" Grid.Column="1" Name="btnNotDuplicate" ToolTip="{x:Static loc:Localization.ScanTooltip}" IsEnabled="{Binding Scanner.IsScanning, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type mdfinder:MainWindow}}, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource InverseBoolConverter}}" Click="BtnNotDuplicate_Click">
<Button Grid.Row="0" Grid.Column="1" Name="btnNotDuplicate" ToolTip="{x:Static loc:Localization.NotDuplicateTooltip}" IsEnabled="{Binding Scanner.IsScanning, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type mdfinder:MainWindow}}, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource InverseBoolConverter}}" Click="BtnNotDuplicate_Click">
<StackPanel Orientation="Horizontal">
<ContentControl MaxWidth="16" HorizontalAlignment="Center" Template="{StaticResource ClearIcon}" />
<Label Content="{x:Static loc:Localization.NotDupliateLabel}" />
</StackPanel>
</Button>
<Button Grid.Row="0" Grid.Column="2" Name="btnClear" ToolTip="{x:Static loc:Localization.ScanTooltip}" IsEnabled="{Binding Scanner.IsScanning, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type mdfinder:MainWindow}}, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource InverseBoolConverter}}" Click="BtnClear_Click">
<Button Grid.Row="0" Grid.Column="2" Name="btnClear" ToolTip="{x:Static loc:Localization.ClearTooltip}" IsEnabled="{Binding Scanner.IsScanning, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type mdfinder:MainWindow}}, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource InverseBoolConverter}}" Click="BtnClear_Click">
<StackPanel Orientation="Horizontal">
<ContentControl MaxWidth="16" HorizontalAlignment="Center" Template="{StaticResource ClearIcon}" />
<Label Content="{x:Static loc:Localization.ClearLabel}" />
</StackPanel>
</Button>
<Label Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" Name="txtDupeStats" Content="{Binding ScanResults.Statistics, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type mdfinder:MainWindow}}}"></Label>
<Label Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3" Name="txtDbStats" Content="{Binding Database.DbStatistics, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type mdfinder:MainWindow}}}"></Label>
</Grid>
</GroupBox>
<GroupBox Name="SingleFileGroupDuplicateActions" Grid.Column="1" Grid.ColumnSpan="3" Grid.Row="1" Header="{x:Static loc:Localization.ActionBarLabel}">
<StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="1">
<Button Grid.Row="0" Grid.Column="1" Name="btnKeepLargest" ToolTip="{x:Static loc:Localization.ScanTooltip}" IsEnabled="{Binding Scanner.IsScanning, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type mdfinder:MainWindow}}, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource InverseBoolConverter}}" Tag="largest" Click="PerformDuplicateAction_Click">
<Button Grid.Row="0" Grid.Column="1" Name="btnKeepLargest" ToolTip="{x:Static loc:Localization.ActionLargestTooltip}" IsEnabled="{Binding Scanner.IsScanning, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type mdfinder:MainWindow}}, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource InverseBoolConverter}}" Tag="largest" Click="PerformDuplicateAction_Click">
<StackPanel Orientation="Horizontal">
<ContentControl MaxWidth="16" HorizontalAlignment="Center" Template="{StaticResource LargeFileIcon}" />
<Label Content="{x:Static loc:Localization.ActionLargestLabel}" />
</StackPanel>
</Button>
<Button Grid.Row="0" Grid.Column="1" Name="btnKeepSmallest" ToolTip="{x:Static loc:Localization.ScanTooltip}" IsEnabled="{Binding Scanner.IsScanning, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type mdfinder:MainWindow}}, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource InverseBoolConverter}}" Tag="smallest" Click="PerformDuplicateAction_Click">
<Button Grid.Row="0" Grid.Column="1" Name="btnKeepSmallest" ToolTip="{x:Static loc:Localization.ActionSmallestTooltip}" IsEnabled="{Binding Scanner.IsScanning, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type mdfinder:MainWindow}}, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource InverseBoolConverter}}" Tag="smallest" Click="PerformDuplicateAction_Click">
<StackPanel Orientation="Horizontal">
<ContentControl MaxWidth="16" HorizontalAlignment="Center" Template="{StaticResource SmallFileIcon}" />
<Label Content="{x:Static loc:Localization.ActionSmallestLabel}" />
</StackPanel>
</Button>
<Button Grid.Row="0" Grid.Column="1" Name="btnKeepSelected" ToolTip="{x:Static loc:Localization.ScanTooltip}" IsEnabled="{Binding Scanner.IsScanning, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type mdfinder:MainWindow}}, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource InverseBoolConverter}}" Tag="selected" Click="PerformDuplicateAction_Click">
<Button Grid.Row="0" Grid.Column="1" Name="btnKeepSelected" ToolTip="{x:Static loc:Localization.ActionSelectedTooltip}" IsEnabled="{Binding Scanner.IsScanning, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type mdfinder:MainWindow}}, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource InverseBoolConverter}}" Tag="selected" Click="PerformDuplicateAction_Click">
<StackPanel Orientation="Horizontal">
<ContentControl MaxWidth="16" HorizontalAlignment="Center" Template="{StaticResource SelectedFileIcon}" />
<Label Content="{x:Static loc:Localization.ActionSelectedLabel}" />

View File

@ -1,24 +1,17 @@
using System;
using mdfinder.hashprovider;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Forms;
using System.Threading;
using mdfinder.hashprovider;
using System.Diagnostics;
using System.Reflection;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Media.Imaging;
namespace mdfinder
{
@ -86,7 +79,18 @@ namespace mdfinder
Dispatcher.Invoke(() => txtProgressLabel.Content = file.FullName);
}
};
this.Scanner.ReportProgress += (sender, args) => Dispatcher.Invoke(() => { if(args.Processed > 0) { this.progressBar.Value = args.Percentage * 100; } });
this.Scanner.ReportProgress += (sender, args) => Dispatcher.Invoke(() =>
{
if(args.Processed > 0)
{
this.progressBar.Value = args.Percentage * 100;
this.taskBarInfo.ProgressValue = args.Percentage;
}
else
{
this.taskBarInfo.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None;
}
});
InitializeComponent();
}
@ -149,6 +153,84 @@ namespace mdfinder
this.stackNoPreview.Visibility = Visibility.Visible;
}
private void ProcessDuplicateFileGroups(string tag, bool archive, params DuplicateFileGroup[] duplicateFileGroups)
{
new Thread(() =>
{
var actionableFiles = Enumerable.Empty<FileRecord>();
var archiveName = string.Format("archive-{0}.zip", DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss"));
this.Dispatcher.Invoke(() => this.IsEnabled = false);
if(duplicateFileGroups.Any())
{
foreach(var duplicateFileGroup in duplicateFileGroups)
{
if(duplicateFileGroup != null)
{
if(tag == "largest")
{
actionableFiles = duplicateFileGroup.FileRecords.OrderByDescending(fr => fr.Size).Skip(1);
}
else if(tag == "smallest")
{
actionableFiles = duplicateFileGroup.FileRecords.OrderBy(fr => fr.Size).Skip(1);
}
else
{
actionableFiles = duplicateFileGroup.FileRecords.Where(fr => !fr.Keep);
}
ZipArchive zipFile = null;
if(archive)
{
if(duplicateFileGroups.Count() == 1)
{
archiveName = string.Format("{0}.zip", duplicateFileGroup.Hash);
}
zipFile = ZipFile.Open(System.IO.Path.Combine(Properties.Settings.Default.ArchiveFolder, archiveName), ZipArchiveMode.Update);
}
if(archive && zipFile != null)
{
//Zip everything up.
foreach(var file in actionableFiles)
{
zipFile.CreateEntryFromFile(file.Path.LocalPath, System.IO.Path.GetFileName(file.Path.LocalPath));
}
zipFile.Dispose();
}
// Make sure the garbage collector has enough time to clear up all
// references to the files.
GC.Collect();
GC.WaitForPendingFinalizers();
foreach(var file in actionableFiles)
{
//Do the deletion
try
{
File.Delete(file.Path.LocalPath);
this.Database.RemoveFileRecord(file.Id);
}
catch(Exception ex)
{
var r = System.Windows.MessageBox.Show(ex.Message, string.Format("Error deleting {0}", file.Path));
}
}
SetDuplicateFileCollection(GetDuplicateFiles());
}
}
}
this.Dispatcher.Invoke(() => this.IsEnabled = true);
}).Start();
}
/// <summary> Event handler. Called by btnFilePicker for click events. </summary>
/// <param name="sender"> Source of the event. </param>
/// <param name="e"> Routed event information. </param>
@ -176,6 +258,8 @@ namespace mdfinder
this.Scanner.Scan(location);
this.Dispatcher.Invoke(() => txtProgressLabel.Content = string.Empty);
this.Dispatcher.Invoke(() => progressBar.Value = 0);
this.Dispatcher.Invoke(() => taskBarInfo.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Normal);
this.Dispatcher.Invoke(() => taskBarInfo.ProgressValue = 0);
this.Dispatcher.Invoke(() => SetDuplicateFileCollection(GetDuplicateFiles()));
}).Start();
}
@ -327,112 +411,31 @@ namespace mdfinder
{
var tag = (sender as System.Windows.Controls.Button).Tag.ToString();
var duplicateFileGroup = this.listBoxDupes.SelectedItem as DuplicateFileGroup;
var actionableFiles = Enumerable.Empty<FileRecord>();
var archive = this.checkboxArchiveRemainingFiles.IsChecked ?? false;
this.ScanResults.SelectedDuplicateFileGroup = null;
ResetMediaPreview();
new Thread(() =>
{
if(duplicateFileGroup != null)
{
if(tag == "largest")
{
actionableFiles = duplicateFileGroup.FileRecords.OrderByDescending(fr => fr.Size).Skip(1);
}
else if(tag == "smallest")
{
actionableFiles = duplicateFileGroup.FileRecords.OrderBy(fr => fr.Size).Skip(1);
}
else
{
actionableFiles = duplicateFileGroup.FileRecords.Where(fr => !fr.Keep);
}
ZipArchive zipFile = null;
if(archive)
{
zipFile = ZipFile.Open(System.IO.Path.Combine(Properties.Settings.Default.ArchiveFolder, duplicateFileGroup.Hash + ".zip"), ZipArchiveMode.Update);
}
if(archive && zipFile != null)
{
//Zip everything up.
foreach(var file in actionableFiles)
{
zipFile.CreateEntryFromFile(file.Path.LocalPath, System.IO.Path.GetFileName(file.Path.LocalPath));
}
zipFile.Dispose();
}
foreach(var file in actionableFiles)
{
//Do the deletion
File.Delete(file.Path.LocalPath);
this.Database.RemoveFileRecord(file.Id);
}
SetDuplicateFileCollection(GetDuplicateFiles());
}
}).Start();
ProcessDuplicateFileGroups(tag, archive, duplicateFileGroup);
}
private void PerformDuplicateActionAll_Click(object sender, RoutedEventArgs e)
{
var tag = (sender as System.Windows.Controls.Button).Tag.ToString();
var duplicateFileGroups = new List<DuplicateFileGroup>();
var actionableFiles = new List<FileRecord>();
var archive = this.checkboxArchiveRemainingFiles.IsChecked ?? false;
foreach(var item in this.listBoxDupes.Items)
{
duplicateFileGroups.Add(item as DuplicateFileGroup);
}
this.ScanResults.SelectedDuplicateFileGroup = null;
ResetMediaPreview();
this.IsEnabled = false;
new Thread(() =>
{
foreach(var duplicateFileGroup in duplicateFileGroups)
{
if(tag == "largest")
{
actionableFiles.AddRange(duplicateFileGroup.FileRecords.Where(fr => !fr.Keep).OrderByDescending(fr => fr.Size).Skip(1));
}
else if(tag == "smallest")
{
actionableFiles.AddRange(duplicateFileGroup.FileRecords.Where(fr => !fr.Keep).OrderBy(fr => fr.Size).Skip(1));
}
}
var zipFile = ZipFile.Open(System.IO.Path.Combine(Properties.Settings.Default.ArchiveFolder, "archive.zip"), ZipArchiveMode.Update);
//Zip all the actionable files at once.
if(zipFile != null)
{
foreach(var file in actionableFiles)
{
zipFile.CreateEntryFromFile(file.Path.LocalPath, System.IO.Path.GetFileName(file.Path.LocalPath));
}
zipFile.Dispose();
foreach(var file in actionableFiles)
{
//Do the deletions
File.Delete(file.Path.LocalPath);
this.Database.RemoveFileRecord(file.Id);
}
}
SetDuplicateFileCollection(GetDuplicateFiles());
Dispatcher.Invoke(() => this.IsEnabled = true);
}).Start();
ProcessDuplicateFileGroups(tag, archive, duplicateFileGroups.ToArray());
}
/// <summary>

View File

@ -1,6 +1,4 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
@ -30,7 +28,6 @@ using System.Windows;
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
@ -40,7 +37,6 @@ using System.Windows;
// app, or any theme specific resource dictionaries)
)]
// Version information for an assembly consists of the following four values:
//
// Major Version
@ -51,5 +47,5 @@ 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("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyVersion("0.9.0.0")]
[assembly: AssemblyFileVersion("0.9.0.0")]

View File

@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace mdfinder
{
@ -13,10 +10,11 @@ namespace mdfinder
/// <summary> The duplicate files. </summary>
private IEnumerable<DuplicateFileGroup> duplicateFiles;
/// <summary> The selected duplicate file group. </summary>
private DuplicateFileGroup selectedDuplicateFileGroup;
#endregion
#endregion Members
#region Properties
@ -50,7 +48,17 @@ namespace mdfinder
}
}
#endregion
/// <summary> Gets the statistics string. </summary>
/// <value> The statistics string. </value>
public string Statistics
{
get
{
return string.Format("{0} Duplicates", this.duplicateFiles.Sum(df => df.Count - 1));
}
}
#endregion Properties
#region Constructors
@ -58,8 +66,10 @@ namespace mdfinder
{
this.duplicateFiles = Enumerable.Empty<DuplicateFileGroup>();
this.selectedDuplicateFileGroup = new DuplicateFileGroup(Enumerable.Empty<FileRecord>());
this.AddConstantCallProperty("Statistics");
}
#endregion
#endregion Constructors
}
}