diff --git a/mdfinder/App.config b/mdfinder/App.config
index 86c251c..004b9b3 100644
--- a/mdfinder/App.config
+++ b/mdfinder/App.config
@@ -36,6 +36,9 @@
en-US
+
+
+
\ No newline at end of file
diff --git a/mdfinder/DBHelper.cs b/mdfinder/DBHelper.cs
index f25c5a0..685db31 100644
--- a/mdfinder/DBHelper.cs
+++ b/mdfinder/DBHelper.cs
@@ -63,8 +63,15 @@ namespace mdfinder
/// The hash provider.
public void InsertFileRecord(string path, long size, string hash, string hashProvider)
{
- var fileRecord = new FileRecord() { Path = new Uri(path), Size = size, Hash = hash, HashProvider = hashProvider };
- this.FileRecordCollection.Insert(fileRecord);
+ var fileRecord = new FileRecord(path, size, hash, hashProvider);
+ this.FileRecordCollection.Upsert(fileRecord);
+ }
+
+ /// Removes the file record described by ID.
+ /// The identifier.
+ public void RemoveFileRecord(string path)
+ {
+ this.FileRecordCollection.Delete(fr => fr.Id == path);
}
/// Gets the file records in this collection.
diff --git a/mdfinder/DuplicateFileGroup.cs b/mdfinder/DuplicateFileGroup.cs
new file mode 100644
index 0000000..d30ee9b
--- /dev/null
+++ b/mdfinder/DuplicateFileGroup.cs
@@ -0,0 +1,77 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace mdfinder
+{
+ public class DuplicateFileGroup : PropertyChangedAlerter
+ {
+ #region Properties
+
+ /// Gets the hash.
+ /// The hash.
+ public string Hash { get; }
+
+ /// Gets the number of.
+ /// The count.
+ public int Count { get; }
+
+ /// Gets the total size of the file group.
+ /// The total number of size.
+ public long TotalSize { get; }
+
+ /// Gets the potential size saving.
+ /// The potential size saving.
+ public long PotentialSizeSaving { get; }
+
+ /// Gets or sets the file records.
+ /// The file records.
+ public List FileRecords { get; set; }
+
+ #endregion
+
+ /// Constructor.
+ /// The file records.
+ /// (Optional) Type of the size savings to calculate.
+ public DuplicateFileGroup(IEnumerable fileRecords, SavingsType savingsType = SavingsType.SaveBiggest)
+ {
+ this.FileRecords = new List(fileRecords);
+
+ //Precalculate stats.
+ this.Hash = this.FileRecords.Select(fr => fr.Hash).FirstOrDefault();
+ this.Count = this.FileRecords.Count();
+
+ this.TotalSize = this.FileRecords.Sum(fr => fr.Size);
+
+ switch (savingsType)
+ {
+ case SavingsType.SaveBiggest:
+ this.PotentialSizeSaving = this.FileRecords.OrderByDescending(fr => fr.Size).Skip(1).Sum(fr => fr.Size);
+ break;
+ case SavingsType.SaveSmallest:
+ this.PotentialSizeSaving = this.FileRecords.OrderBy(fr => fr.Size).Skip(1).Sum(fr => fr.Size);
+ break;
+ case SavingsType.SaveMedian:
+ //This is kind of hacky, but good enough for our purposes here. CLOSE ENOUGH
+ var medianFileRecord = this.FileRecords.OrderBy(fr => fr.Size).ElementAt(this.Count / 2);
+ this.PotentialSizeSaving = this.FileRecords.Except(new[] { medianFileRecord }).Sum(fr => fr.Size);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /// Values that represent the ways of saving space.
+ public enum SavingsType
+ {
+ /// Saves the biggest, and presumably highest quality, file.
+ SaveBiggest,
+ /// Saves the smallest file.
+ SaveSmallest,
+ /// .
+ SaveMedian
+ }
+ }
+}
diff --git a/mdfinder/FileRecord.cs b/mdfinder/FileRecord.cs
index dcd14e8..645c7f4 100644
--- a/mdfinder/FileRecord.cs
+++ b/mdfinder/FileRecord.cs
@@ -6,29 +6,149 @@ using System.Threading.Tasks;
namespace mdfinder
{
- public class FileRecord
+ public class FileRecord : PropertyChangedAlerter
{
+ #region Members
+
+ /// The identifier.
+ private string id;
+
+ /// Full pathname of the file.
+ private Uri path;
+
+ /// The size.
+ private long size;
+
+ /// The hash.
+ private string hash;
+
+ /// The hash provider.
+ private string hashProvider;
+
+ /// True to keep.
+ private bool keep;
+
+ #endregion
+
#region Properties
/// Gets or sets the identifier.
/// The identifier.
- public Int64 Id { get; set; }
+ public string Id
+ {
+ get
+ {
+ return this.id;
+ }
+ set
+ {
+ this.id = value;
+ OnPropertyChanged();
+ }
+ }
/// Gets or sets the full pathname of the file.
/// The full pathname of the file.
- public Uri Path { get; set; }
+ public Uri Path
+ {
+ get
+ {
+ return this.path;
+ }
+ set
+ {
+ this.path = value;
+ OnPropertyChanged();
+ }
+ }
/// Gets or sets the size.
/// The size.
- public long Size { get; set; }
+ public long Size
+ {
+ get
+ {
+ return this.size;
+ }
+ set
+ {
+ this.size = value;
+ OnPropertyChanged();
+ }
+ }
/// Gets or sets the hash.
/// The hash.
- public string Hash { get; set; }
+ public string Hash
+ {
+ get
+ {
+ return this.hash;
+ }
+ set
+ {
+ this.hash = value;
+ OnPropertyChanged();
+ }
+ }
/// Gets or sets the hash provider.
/// The hash provider.
- public string HashProvider { get; set; }
+ public string HashProvider
+ {
+ get
+ {
+ return this.hashProvider;
+ }
+ set
+ {
+ this.hashProvider = value;
+ OnPropertyChanged();
+ }
+ }
+
+ /// Gets or sets a value indicating whether to keep the file when processing duplicates.
+ /// True if keep, false if not.
+ public bool Keep
+ {
+ get
+ {
+ return this.keep;
+ }
+ set
+ {
+ this.keep = value;
+ OnPropertyChanged();
+ }
+ }
+
+ #endregion
+
+ #region Constructors
+
+ public FileRecord()
+ {
+ this.Id = string.Empty;
+ this.Path = default(Uri);
+ this.Size = 0;
+ this.Hash = string.Empty;
+ this.HashProvider = string.Empty;
+ }
+
+ /// Constructor.
+ /// Full pathname of the file.
+ /// The size.
+ /// The hash.
+ /// The hash provider.
+ public FileRecord(string path, long size, string hash, string hashProvider)
+ {
+ this.Id = path;
+ this.Path = new Uri(path);
+ this.Size = size;
+ this.Hash = hash;
+ this.HashProvider = hashProvider;
+
+ }
#endregion
}
diff --git a/mdfinder/Icons.xaml b/mdfinder/Icons.xaml
index 184dd6d..96877c5 100644
--- a/mdfinder/Icons.xaml
+++ b/mdfinder/Icons.xaml
@@ -170,4 +170,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mdfinder/Localization/Localization.Designer.cs b/mdfinder/Localization/Localization.Designer.cs
index def609d..a1a3e77 100644
--- a/mdfinder/Localization/Localization.Designer.cs
+++ b/mdfinder/Localization/Localization.Designer.cs
@@ -106,7 +106,16 @@ namespace mdfinder.Localization {
}
///
- /// Looks up a localized string similar to Actions.
+ /// Looks up a localized string similar to Archive Remaining Files.
+ ///
+ public static string ActionArchiveLabel {
+ get {
+ return ResourceManager.GetString("ActionArchiveLabel", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Duplicate Actions.
///
public static string ActionBarLabel {
get {
@@ -114,6 +123,42 @@ namespace mdfinder.Localization {
}
}
+ ///
+ /// Looks up a localized string similar to Keep Largest.
+ ///
+ public static string ActionLargestLabel {
+ get {
+ return ResourceManager.GetString("ActionLargestLabel", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to KeepSelected.
+ ///
+ public static string ActionSelectedLabel {
+ get {
+ return ResourceManager.GetString("ActionSelectedLabel", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Keep Smallest.
+ ///
+ public static string ActionSmallestLabel {
+ get {
+ return ResourceManager.GetString("ActionSmallestLabel", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Archive Folder.
+ ///
+ public static string ArchiveFolderLabel {
+ get {
+ return ResourceManager.GetString("ArchiveFolderLabel", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Would you like to visit mdfinder to update to the latest version?.
///
@@ -159,6 +204,15 @@ namespace mdfinder.Localization {
}
}
+ ///
+ /// Looks up a localized string similar to Keep File.
+ ///
+ public static string ColumnHeaderKeep {
+ get {
+ return ResourceManager.GetString("ColumnHeaderKeep", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Hash.
///
@@ -268,29 +322,11 @@ namespace mdfinder.Localization {
}
///
- /// Looks up a localized string similar to Filters.
+ /// Looks up a localized string similar to Files.
///
- public static string FilterBarLabel {
+ public static string FilesLabel {
get {
- return ResourceManager.GetString("FilterBarLabel", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Duplicates.
- ///
- public static string FilterDuplicatesLabel {
- get {
- return ResourceManager.GetString("FilterDuplicatesLabel", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Show All.
- ///
- public static string FilterShowAllLabel {
- get {
- return ResourceManager.GetString("FilterShowAllLabel", resourceCulture);
+ return ResourceManager.GetString("FilesLabel", resourceCulture);
}
}
@@ -330,6 +366,15 @@ namespace mdfinder.Localization {
}
}
+ ///
+ /// Looks up a localized string similar to No Preview Available.
+ ///
+ public static string NoPreviewLabel {
+ get {
+ return ResourceManager.GetString("NoPreviewLabel", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to OK.
///
@@ -384,6 +429,15 @@ namespace mdfinder.Localization {
}
}
+ ///
+ /// Looks up a localized string similar to Potential Space Savings.
+ ///
+ public static string PotentialSpaceSavingsLabel {
+ get {
+ return ResourceManager.GetString("PotentialSpaceSavingsLabel", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Provider Location.
///
@@ -429,6 +483,15 @@ namespace mdfinder.Localization {
}
}
+ ///
+ /// Looks up a localized string similar to Scan Location.
+ ///
+ public static string ScanningLabel {
+ get {
+ return ResourceManager.GetString("ScanningLabel", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Scan the selected path.
///
@@ -438,6 +501,24 @@ namespace mdfinder.Localization {
}
}
+ ///
+ /// Looks up a localized string similar to Size:.
+ ///
+ public static string SizeLabel {
+ get {
+ return ResourceManager.GetString("SizeLabel", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Size On Disk:.
+ ///
+ public static string SizeOnDiskLabel {
+ get {
+ return ResourceManager.GetString("SizeOnDiskLabel", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Skip Empty Files.
///
diff --git a/mdfinder/Localization/Localization.resx b/mdfinder/Localization/Localization.resx
index 89b00bc..950bca9 100644
--- a/mdfinder/Localization/Localization.resx
+++ b/mdfinder/Localization/Localization.resx
@@ -132,8 +132,17 @@
About mdfinder
+
+ Archive Remaining Files
+
- Actions
+ Duplicate Actions
+
+
+ Keep Largest
+
+
+ Keep Smallest
Would you like to visit mdfinder to update to the latest version?
@@ -186,14 +195,8 @@
File
-
- Filters
-
-
- Duplicates
-
-
- Show All
+
+ Files
Help
@@ -240,9 +243,15 @@
Location to Scan
+
+ Scan Location
+
Scan the selected path
+
+ Size:
+
Skip Empty Files
@@ -255,4 +264,22 @@
Version
+
+ KeepSelected
+
+
+ Archive Folder
+
+
+ Keep File
+
+
+ No Preview Available
+
+
+ Potential Space Savings
+
+
+ Size On Disk:
+
\ No newline at end of file
diff --git a/mdfinder/MainWindow.xaml b/mdfinder/MainWindow.xaml
index ceeacac..13ec573 100644
--- a/mdfinder/MainWindow.xaml
+++ b/mdfinder/MainWindow.xaml
@@ -3,10 +3,11 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
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"
mc:Ignorable="d"
- Title="{x:Static loc:Localization.Title}" Height="450" Width="800">
+ Title="{x:Static loc:Localization.Title}" Height="520.293" Width="814.505">
@@ -33,7 +34,7 @@
@@ -62,7 +63,7 @@
-
+
@@ -85,80 +86,168 @@
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mdfinder/MainWindow.xaml.cs b/mdfinder/MainWindow.xaml.cs
index 9f16c2b..ea288c6 100644
--- a/mdfinder/MainWindow.xaml.cs
+++ b/mdfinder/MainWindow.xaml.cs
@@ -18,6 +18,7 @@ using mdfinder.hashprovider;
using System.Diagnostics;
using System.Reflection;
using System.IO;
+using System.IO.Compression;
namespace mdfinder
{
@@ -26,6 +27,16 @@ namespace mdfinder
///
public partial class MainWindow : Window
{
+ /// The media extentions.
+ private static readonly string[] MEDIA_EXTENTIONS = new[] { ".AVI", ".MPG", ".MPEG", ".MP3", ".MP4", ".MKV", ".WAV" };
+
+ /// The image extentions.
+ private static readonly string[] IMAGE_EXTENTIONS = new[] { ".JPG", ".JPEG", ".PNG", ".BMP", ".TIF", ".TIFF", ".ICO", "GIF" };
+
+ /// The text extentions.
+ private static readonly string[] TEXT_EXTENTIONS = new[] { ".TXT", ".XML", ".HTM", ".HTML", ".JS", ".CSS" };
+
+
#region Properties
/// Gets or sets the database.
@@ -44,6 +55,10 @@ namespace mdfinder
/// The default provider.
public IHashProvider DefaultProvider { get; set; }
+ /// Gets or sets the scan results.
+ /// The scan results.
+ public ScanResults ScanResults { get; set; }
+
#endregion
#region Constructors
@@ -55,6 +70,7 @@ namespace mdfinder
this.Scanner = new Scanner();
this.DefaultProvider = new MD5HashProvider();
this.HashProviders = GetProviderPlugins();
+ this.ScanResults = new ScanResults();
this.Scanner.DirectoryFound += (sender, args) => Dispatcher.Invoke(() => txtProgressLabel.Content = args.Directory.Name);
this.Scanner.FilesFound += (sender, args) =>
@@ -87,17 +103,52 @@ namespace mdfinder
///
private IEnumerable GetProviderPlugins()
{
- var directory = new DirectoryInfo(Properties.Settings.Default.ProviderFolder);
- foreach (var pluginFile in directory.GetFiles("*.dll"))
+ if (!string.IsNullOrWhiteSpace(Properties.Settings.Default.ProviderFolder) && Directory.Exists(Properties.Settings.Default.ProviderFolder))
{
- var assembly = Assembly.LoadFrom(pluginFile.FullName);
- foreach (var type in assembly.GetTypes().Where(t => t.GetInterface("IHashProvider") != null))
+ var directory = new DirectoryInfo(Properties.Settings.Default.ProviderFolder);
+ foreach (var pluginFile in directory.GetFiles("*.dll"))
{
- yield return Activator.CreateInstance(type) as IHashProvider;
+ var assembly = Assembly.LoadFrom(pluginFile.FullName);
+ foreach (var type in assembly.GetTypes().Where(t => t.GetInterface("IHashProvider") != null))
+ {
+ yield return Activator.CreateInstance(type) as IHashProvider;
+ }
}
}
}
+ /// Sets duplicate file collection.
+ /// The duplicates.
+ private void SetDuplicateFileCollection(IEnumerable duplicates)
+ {
+ this.ScanResults.DuplicateFiles = duplicates;
+ }
+
+ /// Gets the duplicate files in this collection.
+ ///
+ /// An enumerator that allows foreach to be used to process the duplicate files in this
+ /// collection.
+ ///
+ private IEnumerable GetDuplicateFiles()
+ {
+ return this.Database.GetFileRecords().GroupBy(fr => fr.Hash).Where(g => g.Count() > 1).Select(g => new DuplicateFileGroup(g)).ToArray();
+ }
+
+ /// Resets the media preview.
+ private void ResetMediaPreview()
+ {
+ this.mediaPreview.Stop();
+
+ this.mediaPreview.Source = null;
+ this.imagePreview.Source = null;
+ this.textPreview.Text = string.Empty;
+
+ this.mediaPreviewContainer.Visibility = Visibility.Hidden;
+ this.imagePreview.Visibility = Visibility.Hidden;
+ this.textPreview.Visibility = Visibility.Hidden;
+ this.stackNoPreview.Visibility = Visibility.Visible;
+ }
+
/// Event handler. Called by btnFilePicker for click events.
/// Source of the event.
/// Routed event information.
@@ -117,49 +168,27 @@ namespace mdfinder
private void btnScan_Click(object sender, RoutedEventArgs e)
{
var location = txtScanLocation.Text;
+ ResetMediaPreview();
if (!this.Scanner.IsScanning)
{
new Thread(() =>
{
this.Scanner.Scan(location);
this.Dispatcher.Invoke(() => txtProgressLabel.Content = string.Empty);
- this.Dispatcher.Invoke(() => datagridFileRecords.ItemsSource = this.Database.GetFileRecords());
+ this.Dispatcher.Invoke(() => progressBar.Value = 0);
+ this.Dispatcher.Invoke(() => SetDuplicateFileCollection(GetDuplicateFiles()));
}).Start();
}
}
- /// Event handler. Called by DatagridFileRecords for initialized events.
- /// Source of the event.
- /// Event information.
- private void DatagridFileRecords_Initialized(object sender, EventArgs e)
- {
- this.datagridFileRecords.ItemsSource = this.Database.GetFileRecords();
- }
-
- /// Event handler. Called by BtnFilterDuplicates for click events.
- /// Source of the event.
- /// Routed event information.
- private void BtnFilterDuplicates_Click(object sender, RoutedEventArgs e)
- {
- this.datagridFileRecords.ItemsSource = new ListCollectionView(this.Database.GetFileRecords().GroupBy(fr => fr.Hash).Where(g => g.Count() > 1).SelectMany(g => g).ToList());
- ((ListCollectionView)this.datagridFileRecords.ItemsSource).GroupDescriptions.Add(new PropertyGroupDescription("Hash"));
- }
-
- /// Event handler. Called by BtnFilterShowAll for click events.
- /// Source of the event.
- /// Routed event information.
- private void BtnFilterShowAll_Click(object sender, RoutedEventArgs e)
- {
- this.datagridFileRecords.ItemsSource = this.Database.GetFileRecords();
- }
-
/// Event handler. Called by BtnClear for click events.
/// Source of the event.
/// Routed event information.
private void BtnClear_Click(object sender, RoutedEventArgs e)
{
this.Database.Clear();
- this.datagridFileRecords.ItemsSource = Enumerable.Empty();
+ ResetMediaPreview();
+ SetDuplicateFileCollection(Enumerable.Empty());
}
/// Event handler. Called by Hyperlink for click events.
@@ -183,14 +212,153 @@ namespace mdfinder
this.HashProviders = GetProviderPlugins();
}
+ /// Event handler. Called by MenuAbout for click events.
+ /// Source of the event.
+ /// Routed event information.
private void MenuAbout_Click(object sender, RoutedEventArgs e)
{
var aboutWindow = new AboutWindow();
aboutWindow.Show();
}
- #endregion
+ /// Event handler. Called by ListBoxDupes for initialized events.
+ /// Source of the event.
+ /// Event information.
+ private void ListBoxDupes_Initialized(object sender, EventArgs e)
+ {
+ new Thread(() =>
+ {
+ this.Dispatcher.Invoke(() => SetDuplicateFileCollection(GetDuplicateFiles()));
+ }).Start();
+ }
+ /// Event handler. Called by ListBoxDupes for selection changed events.
+ /// Source of the event.
+ /// Selection changed event information.
+ private void ListBoxDupes_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ if (e.AddedItems.Count > 0)
+ {
+ this.ScanResults.SelectedDuplicateFileGroup = e.AddedItems[0] as DuplicateFileGroup;
+ }
+ else
+ {
+ this.ScanResults.SelectedDuplicateFileGroup = null;
+ }
+ }
+
+ /// Event handler. Called by PerformDuplicateAction for click events.
+ /// Source of the event.
+ /// Routed event information.
+ private void PerformDuplicateAction_Click(object sender, RoutedEventArgs e)
+ {
+ var tag = (sender as System.Windows.Controls.Button).Tag.ToString();
+ var duplicateFileGroup = this.listBoxDupes.SelectedItem as DuplicateFileGroup;
+ var actionableFiles = Enumerable.Empty();
+ var archive = this.checkboxArchiveRemainingFiles.IsChecked ?? false;
+
+ ResetMediaPreview();
+
+ 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);
+ }
+
+ foreach (var file in actionableFiles)
+ {
+ if(archive && zipFile != null)
+ {
+ zipFile.CreateEntryFromFile(file.Path.LocalPath, System.IO.Path.GetFileName(file.Path.LocalPath));
+ }
+
+ File.Delete(file.Path.LocalPath);
+
+ this.Database.RemoveFileRecord(file.Id);
+ }
+
+ if(zipFile != null)
+ {
+ zipFile.Dispose();
+ }
+
+ SetDuplicateFileCollection(GetDuplicateFiles());
+ }
+ }
+
+ ///
+ /// Event handler. Called by DatagridFileList for selection changed events.
+ ///
+ /// Source of the event.
+ /// Selection changed event information.
+ private void DatagridFileList_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ if (e.AddedItems.Count == 1)
+ {
+ var fileRecord = e.AddedItems[0] as FileRecord;
+ if (fileRecord != null)
+ {
+ var extension = System.IO.Path.GetExtension(fileRecord.Path.LocalPath).ToUpper();
+
+ if (MEDIA_EXTENTIONS.Contains(extension))
+ {
+ this.mediaPreview.Source = fileRecord.Path;
+ this.imagePreview.Source = null;
+ this.textPreview.Text = string.Empty;
+
+ this.mediaPreviewContainer.Visibility = Visibility.Visible;
+ this.imagePreview.Visibility = Visibility.Hidden;
+ this.textPreview.Visibility = Visibility.Hidden;
+ this.stackNoPreview.Visibility = Visibility.Hidden;
+ }
+ else if (IMAGE_EXTENTIONS.Contains(extension))
+ {
+ this.mediaPreview.Source = null;
+ this.imagePreview.Source = new BitmapImage(fileRecord.Path);
+ this.textPreview.Text = string.Empty;
+
+ this.mediaPreviewContainer.Visibility = Visibility.Hidden;
+ this.imagePreview.Visibility = Visibility.Visible;
+ this.textPreview.Visibility = Visibility.Hidden;
+ this.stackNoPreview.Visibility = Visibility.Hidden;
+ }
+ else if (TEXT_EXTENTIONS.Contains(extension))
+ {
+ this.mediaPreview.Source = null;
+ this.imagePreview.Source = null;
+ this.textPreview.Text = File.ReadAllText(fileRecord.Path.LocalPath);
+
+ this.mediaPreviewContainer.Visibility = Visibility.Hidden;
+ this.imagePreview.Visibility = Visibility.Hidden;
+ this.textPreview.Visibility = Visibility.Visible;
+ this.stackNoPreview.Visibility = Visibility.Hidden;
+ }
+ else //Can't preivew.
+ {
+ ResetMediaPreview();
+ }
+ }
+ }
+ }
}
+ #endregion
+
+
}
diff --git a/mdfinder/OptionsWindow.xaml b/mdfinder/OptionsWindow.xaml
index fb16a2b..8ca402b 100644
--- a/mdfinder/OptionsWindow.xaml
+++ b/mdfinder/OptionsWindow.xaml
@@ -26,16 +26,29 @@
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mdfinder/OptionsWindow.xaml.cs b/mdfinder/OptionsWindow.xaml.cs
index 0375a06..18cafff 100644
--- a/mdfinder/OptionsWindow.xaml.cs
+++ b/mdfinder/OptionsWindow.xaml.cs
@@ -63,5 +63,18 @@ namespace mdfinder
Properties.Settings.Default.ProviderFolder = fbd.SelectedPath;
}
}
+
+ /// Event handler. Called by BtnArchiveLocationDirectory for click events.
+ /// Source of the event.
+ /// Routed event information.
+ private void BtnArchiveLocationDirectory_Click(object sender, RoutedEventArgs e)
+ {
+ var fbd = new FolderBrowserDialog();
+
+ if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
+ {
+ Properties.Settings.Default.ArchiveFolder = fbd.SelectedPath;
+ }
+ }
}
}
diff --git a/mdfinder/Properties/Settings.Designer.cs b/mdfinder/Properties/Settings.Designer.cs
index 4ea131a..927e4e3 100644
--- a/mdfinder/Properties/Settings.Designer.cs
+++ b/mdfinder/Properties/Settings.Designer.cs
@@ -70,5 +70,17 @@ namespace mdfinder.Properties {
this["Language"] = value;
}
}
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("")]
+ public string ArchiveFolder {
+ get {
+ return ((string)(this["ArchiveFolder"]));
+ }
+ set {
+ this["ArchiveFolder"] = value;
+ }
+ }
}
}
diff --git a/mdfinder/Properties/Settings.settings b/mdfinder/Properties/Settings.settings
index c8c4bf7..afa4cce 100644
--- a/mdfinder/Properties/Settings.settings
+++ b/mdfinder/Properties/Settings.settings
@@ -14,5 +14,8 @@
en-US
+
+
+
\ No newline at end of file
diff --git a/mdfinder/ScanResults.cs b/mdfinder/ScanResults.cs
new file mode 100644
index 0000000..a6bd01b
--- /dev/null
+++ b/mdfinder/ScanResults.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace mdfinder
+{
+ /// A scan results model providing bindable properties.
+ public class ScanResults : PropertyChangedAlerter
+ {
+ #region Members
+
+ /// The duplicate files.
+ private IEnumerable duplicateFiles;
+ /// The selected duplicate file group.
+ private DuplicateFileGroup selectedDuplicateFileGroup;
+
+ #endregion
+
+ #region Properties
+
+ /// Gets or sets the duplicate files.
+ /// The duplicate files.
+ public IEnumerable DuplicateFiles
+ {
+ get
+ {
+ return this.duplicateFiles;
+ }
+ set
+ {
+ this.duplicateFiles = value;
+ OnPropertyChanged();
+ }
+ }
+
+ /// Gets or sets the selected duplicate file group.
+ /// The selected duplicate file group.
+ public DuplicateFileGroup SelectedDuplicateFileGroup
+ {
+ get
+ {
+ return this.selectedDuplicateFileGroup;
+ }
+ set
+ {
+ this.selectedDuplicateFileGroup = value;
+ OnPropertyChanged();
+ }
+ }
+
+ #endregion
+
+ #region Constructors
+
+ public ScanResults()
+ {
+ this.duplicateFiles = Enumerable.Empty();
+ this.selectedDuplicateFileGroup = new DuplicateFileGroup(Enumerable.Empty());
+ }
+
+ #endregion
+ }
+}
diff --git a/mdfinder/Scanner.cs b/mdfinder/Scanner.cs
index 74fabbd..844acf8 100644
--- a/mdfinder/Scanner.cs
+++ b/mdfinder/Scanner.cs
@@ -76,8 +76,15 @@ namespace mdfinder
public void Scan(string path)
{
+ if(string.IsNullOrWhiteSpace(path))
+ {
+ this.IsScanning = false;
+ return;
+ }
+
this.Processed = 0;
this.Total = 0;
+ this.IsScanning = true;
var scanPath = new DirectoryInfo(path);
if (scanPath.Exists)
@@ -85,6 +92,8 @@ namespace mdfinder
Discover(scanPath);
Scan(scanPath);
}
+
+ this.IsScanning = false;
}
private void Discover(DirectoryInfo directory)
diff --git a/mdfinder/mdfinder.csproj b/mdfinder/mdfinder.csproj
index a156230..b5f69be 100644
--- a/mdfinder/mdfinder.csproj
+++ b/mdfinder/mdfinder.csproj
@@ -40,6 +40,9 @@
..\packages\csmic.1.1.4\lib\net40\csmic.dll
+
+ ..\packages\Gu.Wpf.Media.0.5.0.2\lib\net45\Gu.Wpf.Media.dll
+
..\packages\LiteDB.4.1.4\lib\net40\LiteDB.dll
@@ -49,6 +52,8 @@
+
+
@@ -73,9 +78,11 @@
AboutWindow.xaml
+
OptionsWindow.xaml
+
diff --git a/mdfinder/packages.config b/mdfinder/packages.config
index 6e60896..165b701 100644
--- a/mdfinder/packages.config
+++ b/mdfinder/packages.config
@@ -1,6 +1,7 @@
+
\ No newline at end of file