From 73ba331283f790800d1b323b115ac6d89ba54db9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Magyar?= Date: Wed, 9 Mar 2016 07:34:59 +0100 Subject: [PATCH 01/11] Unnecessarily literals have been removed. --- .../FileHandling/FileNotification.cs | 2 +- .../FileHandling/FileNotificationType.cs | 2 +- .../FileHandling/FileSearchEx.cs | 1 - .../FileHandling/FileSearchResult.cs | 3 +- .../FileHandling/FileSearcher.cs | 1 - .../FileHandling/FileSegment.cs | 2 +- .../FileHandling/FileSegmentCollection.cs | 2 +- .../FileHandling/FileSegmentEx.cs | 1 - .../FileHandling/FileSegmentSearch.cs | 2 +- .../FileHandling/FileSegmenter.cs | 3 -- .../TailBlazer.Domain/FileHandling/Index.cs | 2 +- .../FileHandling/IndexCollection.cs | 1 - .../TailBlazer.Domain/FileHandling/Indexer.cs | 1 - Source/TailBlazer.Domain/FileHandling/Line.cs | 2 +- .../FileHandling/LineReaderEx.cs | 8 +---- .../FileHandling/Recent/RecentFile.cs | 2 +- .../Recent/RecentFilesToStateConverter.cs | 2 +- .../FileHandling/ScrollRequest.cs | 3 +- .../Search/IDefaultIconSelector.cs | 3 -- .../FileHandling/Search/IconTypeSelector.cs | 2 -- .../FileHandling/Search/SearchEx.cs | 6 +++- .../FileHandling/Search/SearchInfo.cs | 2 +- .../FileHandling/Search/SearchMetadata.cs | 2 +- .../FileHandling/StreamReaderExtended.cs | 32 ++++++++--------- .../Formatting/DisplayText.cs | 5 --- Source/TailBlazer.Domain/Formatting/Hue.cs | 2 +- .../Formatting/ILineMatches.cs | 1 - .../Formatting/MatchedString.cs | 2 +- .../Infrastructure/DynamicDataEx.cs | 5 ++- .../Infrastructure/EnumerableEx.cs | 3 +- .../Infrastructure/Equality.cs | 3 +- .../Infrastructure/ImmutableArray.cs | 1 - .../Infrastructure/ImmutableList.cs | 3 +- .../Infrastructure/StringEx.cs | 3 -- .../Properties/Annotations.cs | 4 +-- .../Properties/AssemblyInfo.cs | 1 - Source/TailBlazer.Domain/Settings/Setting.cs | 2 +- .../Settings/SettingsRegister.cs | 2 +- .../Settings/SettingsStore.cs | 1 - Source/TailBlazer.Domain/Settings/State.cs | 2 +- .../TailBlazer.Fixtures/FileTailerFixture.cs | 5 --- .../TailBlazer.Fixtures/FileWatchFixture.cs | 12 +++---- .../TailBlazer.Fixtures/LargeFileGenerator.cs | 8 ++--- Source/TailBlazer.Fixtures/LogFixtures.cs | 6 +--- .../Properties/AssemblyInfo.cs | 1 - Source/TailBlazer.Fixtures/SchedulerEx.cs | 4 --- .../TailBlazer.Fixtures/SettingsConversion.cs | 4 +-- .../SplitFileByMatchingTextFixture.cs | 7 +--- Source/TailBlazer/App.xaml.cs | 7 +--- Source/TailBlazer/BootStrap.cs | 1 - Source/TailBlazer/Controls/ExitIcon.cs | 1 - .../TailBlazer/Controls/RegexMatchedIcon.cs | 14 +------- Source/TailBlazer/Controls/SaveLayoutIcon.cs | 14 +------- .../TailBlazer/Controls/ScrollChangedArgs.cs | 4 +-- Source/TailBlazer/Controls/SearchIcon.cs | 1 - .../Controls/SearchResultIndicator.cs | 8 ++--- Source/TailBlazer/Controls/TextMatchedIcon.cs | 14 +------- .../TailBlazer/Controls/VirtualScrollPanel.cs | 3 +- Source/TailBlazer/DialogNames.cs | 8 +---- .../Infrastucture/AppConventions.cs | 3 -- .../TailBlazer/Infrastucture/AppRegistry.cs | 11 +++--- Source/TailBlazer/Infrastucture/Command.cs | 2 +- Source/TailBlazer/Infrastucture/FileNamer.cs | 6 ++-- .../Infrastucture/IAttachedListBox.cs | 1 - .../Infrastucture/IntertabClient.cs | 1 - .../TailBlazer/Infrastucture/ListBoxHelper.cs | 2 +- .../TailBlazer/Infrastucture/Log4NetLogger.cs | 1 - .../Infrastucture/MouseWheelGesture.cs | 2 +- .../Infrastucture/SelectionMonitor.cs | 5 ++- .../TailBlazer/Infrastucture/ViewContainer.cs | 2 +- .../Infrastucture/VirtualizingWrapPanel.cs | 6 ++-- Source/TailBlazer/MainWindow.xaml.cs | 9 ++--- Source/TailBlazer/Properties/AssemblyInfo.cs | 2 -- .../Properties/Resources.Designer.cs | 35 +++++++++++-------- .../Properties/Settings.Designer.cs | 12 ++++--- .../Views/Formatting/ColourProvider.cs | 2 +- .../Views/Formatting/DefaultColourSelector.cs | 1 - .../Views/Formatting/IconDescription.cs | 2 +- .../TailBlazer/Views/Layout/LayoutAnalyser.cs | 4 +-- .../TailBlazer/Views/Layout/ShellSettings.cs | 2 +- .../Views/Options/GeneralOptions.cs | 4 +-- .../Views/Options/GeneralOptionsConverter.cs | 3 +- .../Views/Recent/RecentFileProxy.cs | 2 +- .../Recent/RecentFilesToStateConverter.cs | 3 +- .../TailBlazer/Views/Recent/RecentSearch.cs | 2 +- .../Views/Recent/RecentSearchCollection.cs | 1 - .../Views/Searching/IconSelectorView.xaml.cs | 15 +------- .../Views/Searching/SearchOptionsConverter.cs | 2 +- .../Views/Searching/SearchOptionsProxy.cs | 6 ++-- .../Views/Searching/SearchOptionsView.xaml.cs | 15 +------- .../Views/Searching/SearchOptionsViewModel.cs | 2 +- Source/TailBlazer/Views/Tail/LineProxy.cs | 2 +- Source/TailBlazer/Views/Tail/TailViewModel.cs | 8 ++--- .../Views/Tail/TailViewModelFactory.cs | 2 +- .../Views/Tail/TailViewPersister.cs | 2 +- 95 files changed, 136 insertions(+), 293 deletions(-) diff --git a/Source/TailBlazer.Domain/FileHandling/FileNotification.cs b/Source/TailBlazer.Domain/FileHandling/FileNotification.cs index d5b1e208..b7dd234b 100644 --- a/Source/TailBlazer.Domain/FileHandling/FileNotification.cs +++ b/Source/TailBlazer.Domain/FileHandling/FileNotification.cs @@ -98,7 +98,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((FileNotification) obj); } diff --git a/Source/TailBlazer.Domain/FileHandling/FileNotificationType.cs b/Source/TailBlazer.Domain/FileHandling/FileNotificationType.cs index e63d1446..b2c272e4 100644 --- a/Source/TailBlazer.Domain/FileHandling/FileNotificationType.cs +++ b/Source/TailBlazer.Domain/FileHandling/FileNotificationType.cs @@ -9,6 +9,6 @@ public enum FileNotificationType CreatedOrOpened, Changed, Missing, - Error, + Error } } \ No newline at end of file diff --git a/Source/TailBlazer.Domain/FileHandling/FileSearchEx.cs b/Source/TailBlazer.Domain/FileHandling/FileSearchEx.cs index ca6dda77..acff1415 100644 --- a/Source/TailBlazer.Domain/FileHandling/FileSearchEx.cs +++ b/Source/TailBlazer.Domain/FileHandling/FileSearchEx.cs @@ -4,7 +4,6 @@ using System.Reactive.Concurrency; using System.Reactive.Disposables; using System.Reactive.Linq; -using TailBlazer.Domain.FileHandling.Search; namespace TailBlazer.Domain.FileHandling { diff --git a/Source/TailBlazer.Domain/FileHandling/FileSearchResult.cs b/Source/TailBlazer.Domain/FileHandling/FileSearchResult.cs index ec2737db..4317a7ef 100644 --- a/Source/TailBlazer.Domain/FileHandling/FileSearchResult.cs +++ b/Source/TailBlazer.Domain/FileHandling/FileSearchResult.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Text; using DynamicData.Kernel; -using TailBlazer.Domain.FileHandling.Search; namespace TailBlazer.Domain.FileHandling { @@ -203,7 +202,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((FileSearchResult) obj); } diff --git a/Source/TailBlazer.Domain/FileHandling/FileSearcher.cs b/Source/TailBlazer.Domain/FileHandling/FileSearcher.cs index 39a170d4..c21bcad9 100644 --- a/Source/TailBlazer.Domain/FileHandling/FileSearcher.cs +++ b/Source/TailBlazer.Domain/FileHandling/FileSearcher.cs @@ -8,7 +8,6 @@ using System.Text; using DynamicData; using TailBlazer.Domain.Annotations; -using TailBlazer.Domain.FileHandling.Search; using TailBlazer.Domain.Infrastructure; namespace TailBlazer.Domain.FileHandling diff --git a/Source/TailBlazer.Domain/FileHandling/FileSegment.cs b/Source/TailBlazer.Domain/FileHandling/FileSegment.cs index c6aba507..97b17b77 100644 --- a/Source/TailBlazer.Domain/FileHandling/FileSegment.cs +++ b/Source/TailBlazer.Domain/FileHandling/FileSegment.cs @@ -42,7 +42,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((FileSegment) obj); } diff --git a/Source/TailBlazer.Domain/FileHandling/FileSegmentCollection.cs b/Source/TailBlazer.Domain/FileHandling/FileSegmentCollection.cs index bb980b25..b9cd4080 100644 --- a/Source/TailBlazer.Domain/FileHandling/FileSegmentCollection.cs +++ b/Source/TailBlazer.Domain/FileHandling/FileSegmentCollection.cs @@ -67,7 +67,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((FileSegmentCollection) obj); } diff --git a/Source/TailBlazer.Domain/FileHandling/FileSegmentEx.cs b/Source/TailBlazer.Domain/FileHandling/FileSegmentEx.cs index e5136ee0..ab36cd4a 100644 --- a/Source/TailBlazer.Domain/FileHandling/FileSegmentEx.cs +++ b/Source/TailBlazer.Domain/FileHandling/FileSegmentEx.cs @@ -1,7 +1,6 @@ using System; using System.Reactive.Linq; - namespace TailBlazer.Domain.FileHandling { public static class FileSegmentEx diff --git a/Source/TailBlazer.Domain/FileHandling/FileSegmentSearch.cs b/Source/TailBlazer.Domain/FileHandling/FileSegmentSearch.cs index 2aec1852..f23455ee 100644 --- a/Source/TailBlazer.Domain/FileHandling/FileSegmentSearch.cs +++ b/Source/TailBlazer.Domain/FileHandling/FileSegmentSearch.cs @@ -63,7 +63,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((FileSegmentSearch) obj); } diff --git a/Source/TailBlazer.Domain/FileHandling/FileSegmenter.cs b/Source/TailBlazer.Domain/FileHandling/FileSegmenter.cs index 5fd5d8cd..ec345da8 100644 --- a/Source/TailBlazer.Domain/FileHandling/FileSegmenter.cs +++ b/Source/TailBlazer.Domain/FileHandling/FileSegmenter.cs @@ -2,10 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Reactive; using System.Reactive.Linq; -using TailBlazer.Domain.FileHandling.Search; -using TailBlazer.Domain.Infrastructure; namespace TailBlazer.Domain.FileHandling { diff --git a/Source/TailBlazer.Domain/FileHandling/Index.cs b/Source/TailBlazer.Domain/FileHandling/Index.cs index ba27272f..045ae70c 100644 --- a/Source/TailBlazer.Domain/FileHandling/Index.cs +++ b/Source/TailBlazer.Domain/FileHandling/Index.cs @@ -69,7 +69,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((Index) obj); } diff --git a/Source/TailBlazer.Domain/FileHandling/IndexCollection.cs b/Source/TailBlazer.Domain/FileHandling/IndexCollection.cs index 4571e6c8..f29b4f7a 100644 --- a/Source/TailBlazer.Domain/FileHandling/IndexCollection.cs +++ b/Source/TailBlazer.Domain/FileHandling/IndexCollection.cs @@ -3,7 +3,6 @@ using System.IO; using System.Linq; using System.Text; -using TailBlazer.Domain.FileHandling.Search; namespace TailBlazer.Domain.FileHandling { diff --git a/Source/TailBlazer.Domain/FileHandling/Indexer.cs b/Source/TailBlazer.Domain/FileHandling/Indexer.cs index 3108b8c8..25f0dd96 100644 --- a/Source/TailBlazer.Domain/FileHandling/Indexer.cs +++ b/Source/TailBlazer.Domain/FileHandling/Indexer.cs @@ -9,7 +9,6 @@ using DynamicData; using DynamicData.Binding; using TailBlazer.Domain.Annotations; -using TailBlazer.Domain.FileHandling.Search; namespace TailBlazer.Domain.FileHandling { diff --git a/Source/TailBlazer.Domain/FileHandling/Line.cs b/Source/TailBlazer.Domain/FileHandling/Line.cs index 114a4148..f881886b 100644 --- a/Source/TailBlazer.Domain/FileHandling/Line.cs +++ b/Source/TailBlazer.Domain/FileHandling/Line.cs @@ -75,7 +75,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((Line) obj); } diff --git a/Source/TailBlazer.Domain/FileHandling/LineReaderEx.cs b/Source/TailBlazer.Domain/FileHandling/LineReaderEx.cs index caa5053d..7f6d7c07 100644 --- a/Source/TailBlazer.Domain/FileHandling/LineReaderEx.cs +++ b/Source/TailBlazer.Domain/FileHandling/LineReaderEx.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; - -namespace TailBlazer.Domain.FileHandling +namespace TailBlazer.Domain.FileHandling { public static class LineReaderEx { diff --git a/Source/TailBlazer.Domain/FileHandling/Recent/RecentFile.cs b/Source/TailBlazer.Domain/FileHandling/Recent/RecentFile.cs index d2ae63c3..5c9fdc69 100644 --- a/Source/TailBlazer.Domain/FileHandling/Recent/RecentFile.cs +++ b/Source/TailBlazer.Domain/FileHandling/Recent/RecentFile.cs @@ -33,7 +33,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((RecentFile) obj); } diff --git a/Source/TailBlazer.Domain/FileHandling/Recent/RecentFilesToStateConverter.cs b/Source/TailBlazer.Domain/FileHandling/Recent/RecentFilesToStateConverter.cs index 66a5baf0..2dfdd323 100644 --- a/Source/TailBlazer.Domain/FileHandling/Recent/RecentFilesToStateConverter.cs +++ b/Source/TailBlazer.Domain/FileHandling/Recent/RecentFilesToStateConverter.cs @@ -54,7 +54,7 @@ public State Convert(RecentFile[] files) fileNodeArray.ForEach(root.Add); - XDocument doc = new XDocument(root); + var doc = new XDocument(root); return new State(2, doc.ToString()); } diff --git a/Source/TailBlazer.Domain/FileHandling/ScrollRequest.cs b/Source/TailBlazer.Domain/FileHandling/ScrollRequest.cs index f271c6a2..65a7f67a 100644 --- a/Source/TailBlazer.Domain/FileHandling/ScrollRequest.cs +++ b/Source/TailBlazer.Domain/FileHandling/ScrollRequest.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; namespace TailBlazer.Domain.FileHandling { @@ -71,7 +70,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((ScrollRequest) obj); } diff --git a/Source/TailBlazer.Domain/FileHandling/Search/IDefaultIconSelector.cs b/Source/TailBlazer.Domain/FileHandling/Search/IDefaultIconSelector.cs index a0a1207b..f7ea6223 100644 --- a/Source/TailBlazer.Domain/FileHandling/Search/IDefaultIconSelector.cs +++ b/Source/TailBlazer.Domain/FileHandling/Search/IDefaultIconSelector.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using DynamicData.Kernel; - namespace TailBlazer.Domain.FileHandling.Search { public interface IDefaultIconSelector diff --git a/Source/TailBlazer.Domain/FileHandling/Search/IconTypeSelector.cs b/Source/TailBlazer.Domain/FileHandling/Search/IconTypeSelector.cs index 4bfa5bd0..5227e502 100644 --- a/Source/TailBlazer.Domain/FileHandling/Search/IconTypeSelector.cs +++ b/Source/TailBlazer.Domain/FileHandling/Search/IconTypeSelector.cs @@ -1,5 +1,3 @@ -using System.Linq; - namespace TailBlazer.Domain.FileHandling.Search { //public class IconTypeSelector diff --git a/Source/TailBlazer.Domain/FileHandling/Search/SearchEx.cs b/Source/TailBlazer.Domain/FileHandling/Search/SearchEx.cs index c3718b7a..e28dcdc0 100644 --- a/Source/TailBlazer.Domain/FileHandling/Search/SearchEx.cs +++ b/Source/TailBlazer.Domain/FileHandling/Search/SearchEx.cs @@ -25,7 +25,11 @@ public static Func BuildPredicate(this SearchMetadata source) { var options = source.IgnoreCase ? caseInsensitiveOptions : caseSensitiveOptions; var regex = new Regex(source.SearchText, options); - predicate = s => regex.IsMatch(s); + predicate = s => + { + if (s == null) throw new ArgumentNullException(nameof(s)); + return regex.IsMatch(s); + }; } return predicate; } diff --git a/Source/TailBlazer.Domain/FileHandling/Search/SearchInfo.cs b/Source/TailBlazer.Domain/FileHandling/Search/SearchInfo.cs index 34df47c2..5c4a5915 100644 --- a/Source/TailBlazer.Domain/FileHandling/Search/SearchInfo.cs +++ b/Source/TailBlazer.Domain/FileHandling/Search/SearchInfo.cs @@ -32,7 +32,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((SearchInfo)obj); } diff --git a/Source/TailBlazer.Domain/FileHandling/Search/SearchMetadata.cs b/Source/TailBlazer.Domain/FileHandling/Search/SearchMetadata.cs index 48388a80..150938a9 100644 --- a/Source/TailBlazer.Domain/FileHandling/Search/SearchMetadata.cs +++ b/Source/TailBlazer.Domain/FileHandling/Search/SearchMetadata.cs @@ -81,7 +81,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((SearchMetadata) obj); } diff --git a/Source/TailBlazer.Domain/FileHandling/StreamReaderExtended.cs b/Source/TailBlazer.Domain/FileHandling/StreamReaderExtended.cs index 2ef98bda..16b4cc08 100644 --- a/Source/TailBlazer.Domain/FileHandling/StreamReaderExtended.cs +++ b/Source/TailBlazer.Domain/FileHandling/StreamReaderExtended.cs @@ -3,6 +3,7 @@ using System.IO; using System.Runtime.InteropServices; using System.Runtime.Versioning; +using System.Security; using System.Text; namespace TailBlazer.Domain.FileHandling @@ -11,7 +12,7 @@ namespace TailBlazer.Domain.FileHandling /// Pilferred from MS because they hide all the best fields /// [Serializable] - [System.Runtime.InteropServices.ComVisible(true)] + [ComVisible(true)] public class StreamReaderExtended : TextReader { // StreamReader.Null is threadsafe. @@ -122,7 +123,7 @@ internal StreamReaderExtended(Stream stream, Encoding encoding, bool detectEncod _closable = closable; } - [System.Security.SecuritySafeCritical] // auto-generated + [SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] public StreamReaderExtended(String path) @@ -130,7 +131,7 @@ public StreamReaderExtended(String path) { } - [System.Security.SecuritySafeCritical] // auto-generated + [SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] public StreamReaderExtended(String path, bool detectEncodingFromByteOrderMarks) @@ -138,7 +139,7 @@ public StreamReaderExtended(String path, bool detectEncodingFromByteOrderMarks) { } - [System.Security.SecuritySafeCritical] // auto-generated + [SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] public StreamReaderExtended(String path, Encoding encoding) @@ -146,7 +147,7 @@ public StreamReaderExtended(String path, Encoding encoding) { } - [System.Security.SecuritySafeCritical] // auto-generated + [SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] public StreamReaderExtended(String path, Encoding encoding, bool detectEncodingFromByteOrderMarks) @@ -154,7 +155,7 @@ public StreamReaderExtended(String path, Encoding encoding, bool detectEncodingF { } - [System.Security.SecuritySafeCritical] // auto-generated + [SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] public StreamReaderExtended(String path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize) @@ -269,7 +270,7 @@ public void DiscardBufferedData() public bool EndOfStream { - [System.Security.SecuritySafeCritical] // auto-generated + [SecuritySafeCritical] // auto-generated get { @@ -283,7 +284,7 @@ public bool EndOfStream } [Pure] - [System.Security.SecuritySafeCritical] // auto-generated + [SecuritySafeCritical] // auto-generated public override int Peek() { @@ -294,7 +295,7 @@ public override int Peek() return charBuffer[charPos]; } - [System.Security.SecuritySafeCritical] // auto-generated + [SecuritySafeCritical] // auto-generated public override int Read() { @@ -307,7 +308,7 @@ public override int Read() return result; } - [System.Security.SecuritySafeCritical] // auto-generated + [SecuritySafeCritical] // auto-generated public override int Read([In, Out] char[] buffer, int index, int count) { if (buffer == null) @@ -343,12 +344,12 @@ public override int Read([In, Out] char[] buffer, int index, int count) return charsRead; } - [System.Security.SecuritySafeCritical] // auto-generated + [SecuritySafeCritical] // auto-generated public override String ReadToEnd() { // Call ReadBuffer, then pull data out of charBuffer. - StringBuilder sb = new StringBuilder(charLen - charPos); + var sb = new StringBuilder(charLen - charPos); do { sb.Append(charBuffer, charPos, charLen - charPos); @@ -417,8 +418,7 @@ private void DetectEncoding() changedEncoding = true; } #endif - else if (byteLen == 2) - _detectEncoding = true; + else _detectEncoding |= byteLen == 2; // Note: in the future, if we change this algorithm significantly, // we can support checking for the preamble of the given encoding. @@ -647,7 +647,7 @@ private int ReadBuffer(char[] userBuffer, int userOffset, int desiredChars, out // contain the terminating carriage return and/or line feed. The returned // value is null if the end of the input stream has been reached. // - [System.Security.SecuritySafeCritical] // auto-generated + [SecuritySafeCritical] // auto-generated public override String ReadLine() { //if (stream == null) @@ -697,7 +697,7 @@ public override String ReadLine() public long AbsolutePosition() { // The number of bytes that the already-read characters need when encoded. - int numReadBytes = this.CurrentEncoding.GetByteCount(charBuffer, 0, charPos); + int numReadBytes = CurrentEncoding.GetByteCount(charBuffer, 0, charPos); return BaseStream.Position - byteLen + numReadBytes; } diff --git a/Source/TailBlazer.Domain/Formatting/DisplayText.cs b/Source/TailBlazer.Domain/Formatting/DisplayText.cs index b18ab81a..3f012449 100644 --- a/Source/TailBlazer.Domain/Formatting/DisplayText.cs +++ b/Source/TailBlazer.Domain/Formatting/DisplayText.cs @@ -1,9 +1,4 @@ -using System.Collections; -using System.Collections.Generic; -using System.Windows.Media; -using DynamicData.Kernel; - namespace TailBlazer.Domain.Formatting { diff --git a/Source/TailBlazer.Domain/Formatting/Hue.cs b/Source/TailBlazer.Domain/Formatting/Hue.cs index 5c819887..adb9ccec 100644 --- a/Source/TailBlazer.Domain/Formatting/Hue.cs +++ b/Source/TailBlazer.Domain/Formatting/Hue.cs @@ -50,7 +50,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((Hue) obj); } diff --git a/Source/TailBlazer.Domain/Formatting/ILineMatches.cs b/Source/TailBlazer.Domain/Formatting/ILineMatches.cs index 7c250f2f..4fc71012 100644 --- a/Source/TailBlazer.Domain/Formatting/ILineMatches.cs +++ b/Source/TailBlazer.Domain/Formatting/ILineMatches.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; namespace TailBlazer.Domain.Formatting { diff --git a/Source/TailBlazer.Domain/Formatting/MatchedString.cs b/Source/TailBlazer.Domain/Formatting/MatchedString.cs index afb35b30..69ac5300 100644 --- a/Source/TailBlazer.Domain/Formatting/MatchedString.cs +++ b/Source/TailBlazer.Domain/Formatting/MatchedString.cs @@ -45,7 +45,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((MatchedString) obj); } diff --git a/Source/TailBlazer.Domain/Infrastructure/DynamicDataEx.cs b/Source/TailBlazer.Domain/Infrastructure/DynamicDataEx.cs index 61619ddd..961bcb5d 100644 --- a/Source/TailBlazer.Domain/Infrastructure/DynamicDataEx.cs +++ b/Source/TailBlazer.Domain/Infrastructure/DynamicDataEx.cs @@ -5,7 +5,6 @@ using System.Linq; using System.Reactive.Disposables; using System.Reactive.Linq; -using DynamicData; using TailBlazer.Domain.Annotations; using TailBlazer.Domain.Infrastructure; @@ -62,7 +61,7 @@ public static IObservable> ToObservableChangeSet(this ReadOnlyO Func> initialChangeSet = () => { var initial = new Change(ListChangeReason.AddRange, source.ToList()); - return new ChangeSet() { initial }; + return new ChangeSet { initial }; }; //populate local cache, otherwise there is no way to deal with a reset @@ -100,7 +99,7 @@ public static IObservable> ToObservableChangeSet(this ReadOnlyO case NotifyCollectionChangedAction.Reset: { var cleared = new Change(ListChangeReason.Clear, cloneOfList.Items.ToList(), 0); - var clearedChangeSet = new ChangeSet() { cleared }; + var clearedChangeSet = new ChangeSet { cleared }; return clearedChangeSet.Concat(initialChangeSet()); } diff --git a/Source/TailBlazer.Domain/Infrastructure/EnumerableEx.cs b/Source/TailBlazer.Domain/Infrastructure/EnumerableEx.cs index 6335c77d..32c48ff9 100644 --- a/Source/TailBlazer.Domain/Infrastructure/EnumerableEx.cs +++ b/Source/TailBlazer.Domain/Infrastructure/EnumerableEx.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using DynamicData.Kernel; using TailBlazer.Domain.Annotations; diff --git a/Source/TailBlazer.Domain/Infrastructure/Equality.cs b/Source/TailBlazer.Domain/Infrastructure/Equality.cs index c6284f1d..72e79d36 100644 --- a/Source/TailBlazer.Domain/Infrastructure/Equality.cs +++ b/Source/TailBlazer.Domain/Infrastructure/Equality.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using DynamicData.Binding; namespace TailBlazer.Domain.Infrastructure { @@ -38,7 +37,7 @@ public class GenericEqualityComparer : IEqualityComparer public GenericEqualityComparer(IEqualityComparer rootComparer,Func compareFunction, Func hashFunction) { - _hashFunction = (t) => + _hashFunction = t => { unchecked { diff --git a/Source/TailBlazer.Domain/Infrastructure/ImmutableArray.cs b/Source/TailBlazer.Domain/Infrastructure/ImmutableArray.cs index fe6c0e7f..2f36a41b 100644 --- a/Source/TailBlazer.Domain/Infrastructure/ImmutableArray.cs +++ b/Source/TailBlazer.Domain/Infrastructure/ImmutableArray.cs @@ -1,6 +1,5 @@ using System; - namespace TailBlazer.Domain.Infrastructure { /// diff --git a/Source/TailBlazer.Domain/Infrastructure/ImmutableList.cs b/Source/TailBlazer.Domain/Infrastructure/ImmutableList.cs index 58e47cbf..13e87aae 100644 --- a/Source/TailBlazer.Domain/Infrastructure/ImmutableList.cs +++ b/Source/TailBlazer.Domain/Infrastructure/ImmutableList.cs @@ -1,5 +1,4 @@ -using System.Collections; -using System.Collections.Generic; +using System.Collections.Generic; using System.Collections.ObjectModel; using DynamicData; diff --git a/Source/TailBlazer.Domain/Infrastructure/StringEx.cs b/Source/TailBlazer.Domain/Infrastructure/StringEx.cs index de4c98ba..016e4f27 100644 --- a/Source/TailBlazer.Domain/Infrastructure/StringEx.cs +++ b/Source/TailBlazer.Domain/Infrastructure/StringEx.cs @@ -1,7 +1,4 @@  -using System.Collections.Generic; -using System.Reactive.Linq; - // ReSharper disable once CheckNamespace namespace System { diff --git a/Source/TailBlazer.Domain/Properties/Annotations.cs b/Source/TailBlazer.Domain/Properties/Annotations.cs index aba257da..69fb9d84 100644 --- a/Source/TailBlazer.Domain/Properties/Annotations.cs +++ b/Source/TailBlazer.Domain/Properties/Annotations.cs @@ -355,7 +355,7 @@ public enum ImplicitUseKindFlags /// InstantiatedWithFixedConstructorSignature = 4, /// Indicates implicit instantiation of a type. - InstantiatedNoFixedConstructorSignature = 8, + InstantiatedNoFixedConstructorSignature = 8 } /// @@ -798,7 +798,7 @@ public enum AssertionConditionType /// Marked parameter should be evaluated to null value. IS_NULL = 2, /// Marked parameter should be evaluated to not null value. - IS_NOT_NULL = 3, + IS_NOT_NULL = 3 } /// diff --git a/Source/TailBlazer.Domain/Properties/AssemblyInfo.cs b/Source/TailBlazer.Domain/Properties/AssemblyInfo.cs index e13ade89..52e6dda9 100644 --- a/Source/TailBlazer.Domain/Properties/AssemblyInfo.cs +++ b/Source/TailBlazer.Domain/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/Source/TailBlazer.Domain/Settings/Setting.cs b/Source/TailBlazer.Domain/Settings/Setting.cs index 8ac2ca61..a83be2d3 100644 --- a/Source/TailBlazer.Domain/Settings/Setting.cs +++ b/Source/TailBlazer.Domain/Settings/Setting.cs @@ -75,7 +75,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((Setting)obj); } diff --git a/Source/TailBlazer.Domain/Settings/SettingsRegister.cs b/Source/TailBlazer.Domain/Settings/SettingsRegister.cs index d174781b..50fbe462 100644 --- a/Source/TailBlazer.Domain/Settings/SettingsRegister.cs +++ b/Source/TailBlazer.Domain/Settings/SettingsRegister.cs @@ -23,7 +23,7 @@ public void Register([NotNull] IConverter converter, [NotNull] string key) if (key == null) throw new ArgumentNullException(nameof(key)); var setting = _settingFactory.Create(converter, key); - _register.Register>(setting); + _register.Register(setting); } } } diff --git a/Source/TailBlazer.Domain/Settings/SettingsStore.cs b/Source/TailBlazer.Domain/Settings/SettingsStore.cs index 0a5ab8a9..ebe4b9ff 100644 --- a/Source/TailBlazer.Domain/Settings/SettingsStore.cs +++ b/Source/TailBlazer.Domain/Settings/SettingsStore.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Xml; using System.Xml.Linq; using TailBlazer.Domain.Infrastructure; diff --git a/Source/TailBlazer.Domain/Settings/State.cs b/Source/TailBlazer.Domain/Settings/State.cs index 63de88d6..8305bdb0 100644 --- a/Source/TailBlazer.Domain/Settings/State.cs +++ b/Source/TailBlazer.Domain/Settings/State.cs @@ -28,7 +28,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((State) obj); } diff --git a/Source/TailBlazer.Fixtures/FileTailerFixture.cs b/Source/TailBlazer.Fixtures/FileTailerFixture.cs index 836ba043..372e741e 100644 --- a/Source/TailBlazer.Fixtures/FileTailerFixture.cs +++ b/Source/TailBlazer.Fixtures/FileTailerFixture.cs @@ -1,15 +1,10 @@ using System; -using System.IO; using System.Linq; using System.Reactive.Linq; -using System.Reactive.Subjects; -using System.Runtime.Remoting.Messaging; -using System.Threading; using FluentAssertions; using Microsoft.Reactive.Testing; using TailBlazer.Domain.FileHandling; using TailBlazer.Domain.Infrastructure; -using TailBlazer.Infrastucture; using Xunit; namespace TailBlazer.Fixtures diff --git a/Source/TailBlazer.Fixtures/FileWatchFixture.cs b/Source/TailBlazer.Fixtures/FileWatchFixture.cs index 01da970b..04f179a2 100644 --- a/Source/TailBlazer.Fixtures/FileWatchFixture.cs +++ b/Source/TailBlazer.Fixtures/FileWatchFixture.cs @@ -1,10 +1,10 @@  using System; -using System.IO; -using System.Linq; -using FluentAssertions; -using Microsoft.Reactive.Testing; -using TailBlazer.Domain.FileHandling; -using Xunit; + using System.IO; + using System.Linq; + using FluentAssertions; + using Microsoft.Reactive.Testing; + using TailBlazer.Domain.FileHandling; + using Xunit; namespace TailBlazer.Fixtures { diff --git a/Source/TailBlazer.Fixtures/LargeFileGenerator.cs b/Source/TailBlazer.Fixtures/LargeFileGenerator.cs index 51259bcb..814f7e09 100644 --- a/Source/TailBlazer.Fixtures/LargeFileGenerator.cs +++ b/Source/TailBlazer.Fixtures/LargeFileGenerator.cs @@ -1,10 +1,6 @@ -using System; -using System.Collections.Generic; -using System.IO; +using System.IO; using System.Linq; using System.Text; -using System.Threading.Tasks; -using Xunit; namespace TailBlazer.Fixtures { @@ -46,7 +42,7 @@ public void GenerateWideLinesInFile() { - File.AppendAllLines(fileName,new string[] {sb.ToString()}); + File.AppendAllLines(fileName,new[] {sb.ToString()}); } } diff --git a/Source/TailBlazer.Fixtures/LogFixtures.cs b/Source/TailBlazer.Fixtures/LogFixtures.cs index ddea2d05..1730a003 100644 --- a/Source/TailBlazer.Fixtures/LogFixtures.cs +++ b/Source/TailBlazer.Fixtures/LogFixtures.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.Generic; using FluentAssertions; using TailBlazer.Infrastucture; using Xunit; diff --git a/Source/TailBlazer.Fixtures/Properties/AssemblyInfo.cs b/Source/TailBlazer.Fixtures/Properties/AssemblyInfo.cs index adbaa2aa..b3c11828 100644 --- a/Source/TailBlazer.Fixtures/Properties/AssemblyInfo.cs +++ b/Source/TailBlazer.Fixtures/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/Source/TailBlazer.Fixtures/SchedulerEx.cs b/Source/TailBlazer.Fixtures/SchedulerEx.cs index 5e07d292..bc58d2e0 100644 --- a/Source/TailBlazer.Fixtures/SchedulerEx.cs +++ b/Source/TailBlazer.Fixtures/SchedulerEx.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.Reactive.Testing; namespace TailBlazer.Fixtures diff --git a/Source/TailBlazer.Fixtures/SettingsConversion.cs b/Source/TailBlazer.Fixtures/SettingsConversion.cs index 7096e86f..71f37230 100644 --- a/Source/TailBlazer.Fixtures/SettingsConversion.cs +++ b/Source/TailBlazer.Fixtures/SettingsConversion.cs @@ -1,8 +1,6 @@ using System.IO; using FluentAssertions; -using TailBlazer.Domain.FileHandling; using TailBlazer.Domain.FileHandling.Recent; -using TailBlazer.Settings; using TailBlazer.Views.Options; using Xunit; @@ -17,7 +15,7 @@ public void RecentFiles() var files = new[] { new RecentFile(new FileInfo(@"C:\\File1.txt")), - new RecentFile(new FileInfo(@"C:\\File2.txt")), + new RecentFile(new FileInfo(@"C:\\File2.txt")) }; var converter = new RecentFilesToStateConverter(); diff --git a/Source/TailBlazer.Fixtures/SplitFileByMatchingTextFixture.cs b/Source/TailBlazer.Fixtures/SplitFileByMatchingTextFixture.cs index 9527a1e4..99a2c977 100644 --- a/Source/TailBlazer.Fixtures/SplitFileByMatchingTextFixture.cs +++ b/Source/TailBlazer.Fixtures/SplitFileByMatchingTextFixture.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections; +using System.Collections; using System.Linq; using FluentAssertions; using TailBlazer.Domain.Formatting; @@ -9,10 +8,6 @@ namespace TailBlazer.Fixtures { public class SplitFileByMatchingTextFixture { - public SplitFileByMatchingTextFixture() - { - } - [Fact] public void FindMatchingText() diff --git a/Source/TailBlazer/App.xaml.cs b/Source/TailBlazer/App.xaml.cs index 8e3facde..731a5a01 100644 --- a/Source/TailBlazer/App.xaml.cs +++ b/Source/TailBlazer/App.xaml.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Linq; -using System.Threading.Tasks; -using System.Windows; +using System.Windows; namespace TailBlazer { diff --git a/Source/TailBlazer/BootStrap.cs b/Source/TailBlazer/BootStrap.cs index 22561e37..9f16fb42 100644 --- a/Source/TailBlazer/BootStrap.cs +++ b/Source/TailBlazer/BootStrap.cs @@ -3,7 +3,6 @@ using System.Windows.Threading; using StructureMap; using TailBlazer.Infrastucture; -using TailBlazer.Views; using TailBlazer.Views.WindowManagement; namespace TailBlazer diff --git a/Source/TailBlazer/Controls/ExitIcon.cs b/Source/TailBlazer/Controls/ExitIcon.cs index 7d005c8f..a4f5b75f 100644 --- a/Source/TailBlazer/Controls/ExitIcon.cs +++ b/Source/TailBlazer/Controls/ExitIcon.cs @@ -1,7 +1,6 @@ using System.Windows; using System.Windows.Controls; - namespace TailBlazer.Controls { diff --git a/Source/TailBlazer/Controls/RegexMatchedIcon.cs b/Source/TailBlazer/Controls/RegexMatchedIcon.cs index b6c4eaa9..f6b77afc 100644 --- a/Source/TailBlazer/Controls/RegexMatchedIcon.cs +++ b/Source/TailBlazer/Controls/RegexMatchedIcon.cs @@ -1,17 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; +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; namespace TailBlazer.Controls { diff --git a/Source/TailBlazer/Controls/SaveLayoutIcon.cs b/Source/TailBlazer/Controls/SaveLayoutIcon.cs index d0dec7c8..4adb6675 100644 --- a/Source/TailBlazer/Controls/SaveLayoutIcon.cs +++ b/Source/TailBlazer/Controls/SaveLayoutIcon.cs @@ -1,17 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; +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; namespace TailBlazer.Controls { diff --git a/Source/TailBlazer/Controls/ScrollChangedArgs.cs b/Source/TailBlazer/Controls/ScrollChangedArgs.cs index 26d14f1c..39427e18 100644 --- a/Source/TailBlazer/Controls/ScrollChangedArgs.cs +++ b/Source/TailBlazer/Controls/ScrollChangedArgs.cs @@ -1,6 +1,4 @@ -using TailBlazer.Infrastucture; - -namespace TailBlazer.Controls +namespace TailBlazer.Controls { public class ScrollChangedArgs { diff --git a/Source/TailBlazer/Controls/SearchIcon.cs b/Source/TailBlazer/Controls/SearchIcon.cs index a6f6a0b2..d7f2a663 100644 --- a/Source/TailBlazer/Controls/SearchIcon.cs +++ b/Source/TailBlazer/Controls/SearchIcon.cs @@ -2,7 +2,6 @@ using System.Windows; using System.Windows.Controls; - namespace TailBlazer.Controls { diff --git a/Source/TailBlazer/Controls/SearchResultIndicator.cs b/Source/TailBlazer/Controls/SearchResultIndicator.cs index 00d27772..8d18ab80 100644 --- a/Source/TailBlazer/Controls/SearchResultIndicator.cs +++ b/Source/TailBlazer/Controls/SearchResultIndicator.cs @@ -1,8 +1,6 @@  -using System; using System.Windows; using System.Windows.Controls; -using System.Windows.Media; using TailBlazer.Domain.Annotations; namespace TailBlazer.Controls @@ -23,7 +21,7 @@ public enum SearchResultIndicatorStatus public class SearchResultIndicator : Control { [UsedImplicitly] - private class SearchResultIndicatorStates + private static class SearchResultIndicatorStates { public const string None = "None"; public const string Regex = "Regex"; @@ -31,7 +29,7 @@ private class SearchResultIndicatorStates } [UsedImplicitly] - private class TemplateParts + private static class TemplateParts { public const string Regex = "PART_RegexImage"; public const string Text = "PART_TextImage"; @@ -79,7 +77,7 @@ private static void OnStatusPropertyChanged(DependencyObject sender, DependencyP private void UpdateVisualState(bool useTransitions) { - switch (this.Status) + switch (Status) { case SearchResultIndicatorStatus.Regex: var x = VisualStateManager.GoToState(this, SearchResultIndicatorStates.Regex, useTransitions); diff --git a/Source/TailBlazer/Controls/TextMatchedIcon.cs b/Source/TailBlazer/Controls/TextMatchedIcon.cs index 1bdb6565..577e8d6b 100644 --- a/Source/TailBlazer/Controls/TextMatchedIcon.cs +++ b/Source/TailBlazer/Controls/TextMatchedIcon.cs @@ -1,17 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; +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; namespace TailBlazer.Controls { diff --git a/Source/TailBlazer/Controls/VirtualScrollPanel.cs b/Source/TailBlazer/Controls/VirtualScrollPanel.cs index cdaf5782..9a7ad92c 100644 --- a/Source/TailBlazer/Controls/VirtualScrollPanel.cs +++ b/Source/TailBlazer/Controls/VirtualScrollPanel.cs @@ -7,7 +7,6 @@ using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Media; -using System.Windows.Threading; using TailBlazer.Infrastucture; namespace TailBlazer.Controls @@ -37,7 +36,7 @@ public class VirtualScrollPanel : VirtualizingPanel, IScrollInfo { private const double ScrollLineAmount = 16.0; private Size _extentSize; - private ExtentInfo _extentInfo = new ExtentInfo(); + private ExtentInfo _extentInfo; private Size _viewportSize; private Point _offset; private ItemsControl _itemsControl; diff --git a/Source/TailBlazer/DialogNames.cs b/Source/TailBlazer/DialogNames.cs index 0c543338..2450e992 100644 --- a/Source/TailBlazer/DialogNames.cs +++ b/Source/TailBlazer/DialogNames.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace TailBlazer +namespace TailBlazer { public static class DialogNames { diff --git a/Source/TailBlazer/Infrastucture/AppConventions.cs b/Source/TailBlazer/Infrastucture/AppConventions.cs index 11503016..7c3c6ed7 100644 --- a/Source/TailBlazer/Infrastucture/AppConventions.cs +++ b/Source/TailBlazer/Infrastucture/AppConventions.cs @@ -1,12 +1,9 @@ using System; using System.Collections; -using System.Collections.Generic; using System.Linq; using StructureMap; -using StructureMap.Configuration.DSL; using StructureMap.Graph; using StructureMap.Graph.Scanning; -using StructureMap.TypeRules; namespace TailBlazer.Infrastucture { diff --git a/Source/TailBlazer/Infrastucture/AppRegistry.cs b/Source/TailBlazer/Infrastucture/AppRegistry.cs index 35d490c2..4b4815f8 100644 --- a/Source/TailBlazer/Infrastucture/AppRegistry.cs +++ b/Source/TailBlazer/Infrastucture/AppRegistry.cs @@ -1,13 +1,14 @@ using System; using System.IO; +using System.Text; +using log4net.Config; using StructureMap; -using StructureMap.Configuration.DSL; using TailBlazer.Domain.FileHandling; using TailBlazer.Domain.FileHandling.Search; using TailBlazer.Domain.Formatting; using TailBlazer.Domain.Infrastructure; using TailBlazer.Domain.Settings; -using ILogger = TailBlazer.Domain.Infrastructure.ILogger; +using TailBlazer.Properties; namespace TailBlazer.Infrastucture { @@ -20,14 +21,14 @@ public AppRegistry() if (!File.Exists(path)) { // should use the default config which is a resource - using (var stream = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(TailBlazer.Properties.Resources.log4net))) + using (var stream = new MemoryStream(Encoding.ASCII.GetBytes(Resources.log4net))) { - log4net.Config.XmlConfigurator.Configure(stream); + XmlConfigurator.Configure(stream); } } else { - log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(path)); + XmlConfigurator.ConfigureAndWatch(new FileInfo(path)); } For().Use().Ctor("type").Is(x => x.ParentType).AlwaysUnique(); diff --git a/Source/TailBlazer/Infrastucture/Command.cs b/Source/TailBlazer/Infrastucture/Command.cs index 75a0e3c3..beaae387 100644 --- a/Source/TailBlazer/Infrastucture/Command.cs +++ b/Source/TailBlazer/Infrastucture/Command.cs @@ -17,7 +17,7 @@ public Command(Action execute, Func canExecute = null) if (execute == null) throw new ArgumentNullException(nameof(execute)); _execute = execute; - _canExecute = canExecute ?? ((t) => true); + _canExecute = canExecute ?? (t => true); } diff --git a/Source/TailBlazer/Infrastucture/FileNamer.cs b/Source/TailBlazer/Infrastucture/FileNamer.cs index 0dd35720..d82ab67e 100644 --- a/Source/TailBlazer/Infrastucture/FileNamer.cs +++ b/Source/TailBlazer/Infrastucture/FileNamer.cs @@ -25,7 +25,7 @@ public FileNamer(IEnumerable paths) public string GetName(string path) { - return CombinePath(GetName(Root, path: new Stack(path.Split(DirectorySeparators)))); + return CombinePath(GetName(Root, new Stack(path.Split(DirectorySeparators)))); } private static string CombinePath(Stack path) @@ -49,7 +49,7 @@ private static string CombinePath(Stack path) private static Stack GetName(Node node, Stack path) { - return GetName(node, path, result: new Stack()); + return GetName(node, path, new Stack()); } private static Stack GetName(Node node, Stack path, Stack result) @@ -79,7 +79,7 @@ private static Stack GetName(Node node, Stack path, Stack(path.Split(DirectorySeparators))); + Insert(Root, new Stack(path.Split(DirectorySeparators))); } private static void Insert(Node node, Stack path) diff --git a/Source/TailBlazer/Infrastucture/IAttachedListBox.cs b/Source/TailBlazer/Infrastucture/IAttachedListBox.cs index d8a456aa..c0b49da4 100644 --- a/Source/TailBlazer/Infrastucture/IAttachedListBox.cs +++ b/Source/TailBlazer/Infrastucture/IAttachedListBox.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Windows.Controls; using DynamicData; -using TailBlazer.Views; using TailBlazer.Views.Tail; namespace TailBlazer.Infrastucture diff --git a/Source/TailBlazer/Infrastucture/IntertabClient.cs b/Source/TailBlazer/Infrastucture/IntertabClient.cs index 620da7e2..340c322c 100644 --- a/Source/TailBlazer/Infrastucture/IntertabClient.cs +++ b/Source/TailBlazer/Infrastucture/IntertabClient.cs @@ -1,7 +1,6 @@ using System.Linq; using System.Windows; using Dragablz; -using TailBlazer.Views; using TailBlazer.Views.WindowManagement; namespace TailBlazer.Infrastucture diff --git a/Source/TailBlazer/Infrastucture/ListBoxHelper.cs b/Source/TailBlazer/Infrastucture/ListBoxHelper.cs index 91afa02d..1a6119b9 100644 --- a/Source/TailBlazer/Infrastucture/ListBoxHelper.cs +++ b/Source/TailBlazer/Infrastucture/ListBoxHelper.cs @@ -4,7 +4,7 @@ namespace TailBlazer.Infrastucture { - public class ListBoxHelper + public static class ListBoxHelper { public static readonly DependencyProperty SelectionMonitorProperty = DependencyProperty.RegisterAttached("SelectionMonitor", typeof(IAttachedListBox), typeof(ListBoxHelper), diff --git a/Source/TailBlazer/Infrastucture/Log4NetLogger.cs b/Source/TailBlazer/Infrastucture/Log4NetLogger.cs index 64a42988..031c4505 100644 --- a/Source/TailBlazer/Infrastucture/Log4NetLogger.cs +++ b/Source/TailBlazer/Infrastucture/Log4NetLogger.cs @@ -1,6 +1,5 @@ using System; using System.Collections; -using System.Collections.Generic; using System.Linq; using log4net; using TailBlazer.Domain.Infrastructure; diff --git a/Source/TailBlazer/Infrastucture/MouseWheelGesture.cs b/Source/TailBlazer/Infrastucture/MouseWheelGesture.cs index 6e8bdc6f..fac60b2f 100644 --- a/Source/TailBlazer/Infrastucture/MouseWheelGesture.cs +++ b/Source/TailBlazer/Infrastucture/MouseWheelGesture.cs @@ -44,7 +44,7 @@ public enum WheelDirection { None, Up, - Down, + Down } } diff --git a/Source/TailBlazer/Infrastucture/SelectionMonitor.cs b/Source/TailBlazer/Infrastucture/SelectionMonitor.cs index 4be12cda..35d65923 100644 --- a/Source/TailBlazer/Infrastucture/SelectionMonitor.cs +++ b/Source/TailBlazer/Infrastucture/SelectionMonitor.cs @@ -3,15 +3,14 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; +using System.Reactive.Concurrency; using System.Reactive.Disposables; using System.Reactive.Linq; -using System.Reactive.Concurrency; using System.Windows.Controls; using System.Windows.Input; using DynamicData; using DynamicData.Binding; using TailBlazer.Domain.Infrastructure; -using TailBlazer.Views; using TailBlazer.Views.Tail; namespace TailBlazer.Infrastucture @@ -43,7 +42,7 @@ public class SelectionMonitor : ISelectionMonitor, IAttachedListBox private bool _isSelecting; private ListBox _selector; - private LineProxy _lastSelected = null; + private LineProxy _lastSelected; public SelectionMonitor(ILogger logger, ISchedulerProvider schedulerProvider) { diff --git a/Source/TailBlazer/Infrastucture/ViewContainer.cs b/Source/TailBlazer/Infrastucture/ViewContainer.cs index fec28c37..172e3fc7 100644 --- a/Source/TailBlazer/Infrastucture/ViewContainer.cs +++ b/Source/TailBlazer/Infrastucture/ViewContainer.cs @@ -32,7 +32,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((ViewContainer) obj); } diff --git a/Source/TailBlazer/Infrastucture/VirtualizingWrapPanel.cs b/Source/TailBlazer/Infrastucture/VirtualizingWrapPanel.cs index 40c795ab..6bd25b3a 100644 --- a/Source/TailBlazer/Infrastucture/VirtualizingWrapPanel.cs +++ b/Source/TailBlazer/Infrastucture/VirtualizingWrapPanel.cs @@ -260,7 +260,7 @@ private ItemLayoutInfo GetLayoutInfo(Size availableSize, double itemHeight, Exte FirstRealizedItemIndex = firstRealizedIndex, FirstRealizedItemLeft = firstRealizedItemLeft, FirstRealizedLineTop = firstRealizedItemTop, - LastRealizedItemIndex = lastRealizedIndex, + LastRealizedItemIndex = lastRealizedIndex }; } @@ -275,12 +275,12 @@ private ExtentInfo GetExtentInfo(Size viewPortSize, double itemHeight) var totalLines = (int)Math.Ceiling((double)_itemsControl.Items.Count / itemsPerLine); var extentHeight = Math.Max(totalLines * ItemHeight, viewPortSize.Height); - return new ExtentInfo() + return new ExtentInfo { ItemsPerLine = itemsPerLine, TotalLines = totalLines, ExtentHeight = extentHeight, - MaxVerticalOffset = extentHeight - viewPortSize.Height, + MaxVerticalOffset = extentHeight - viewPortSize.Height }; } diff --git a/Source/TailBlazer/MainWindow.xaml.cs b/Source/TailBlazer/MainWindow.xaml.cs index 0adefae0..cbc72c3b 100644 --- a/Source/TailBlazer/MainWindow.xaml.cs +++ b/Source/TailBlazer/MainWindow.xaml.cs @@ -1,10 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; +using System.ComponentModel; using MahApps.Metro.Controls; -using TailBlazer.Views; using TailBlazer.Views.WindowManagement; namespace TailBlazer @@ -25,7 +20,7 @@ public MainWindow() Closing += MainWindow_Closing; } - private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) + private void MainWindow_Closing(object sender, CancelEventArgs e) { var windowsModel = DataContext as WindowViewModel; diff --git a/Source/TailBlazer/Properties/AssemblyInfo.cs b/Source/TailBlazer/Properties/AssemblyInfo.cs index 2d654723..38295ff4 100644 --- a/Source/TailBlazer/Properties/AssemblyInfo.cs +++ b/Source/TailBlazer/Properties/AssemblyInfo.cs @@ -1,6 +1,4 @@ using System.Reflection; -using System.Resources; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Windows; diff --git a/Source/TailBlazer/Properties/Resources.Designer.cs b/Source/TailBlazer/Properties/Resources.Designer.cs index ae7f66bb..44bebaf7 100644 --- a/Source/TailBlazer/Properties/Resources.Designer.cs +++ b/Source/TailBlazer/Properties/Resources.Designer.cs @@ -8,10 +8,15 @@ // //------------------------------------------------------------------------------ +using System.CodeDom.Compiler; +using System.ComponentModel; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Resources; +using System.Runtime.CompilerServices; + namespace TailBlazer.Properties { - using System; - - /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -19,27 +24,27 @@ namespace TailBlazer.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [DebuggerNonUserCode()] + [CompilerGenerated()] internal class Resources { - private static global::System.Resources.ResourceManager resourceMan; + private static ResourceManager resourceMan; - private static global::System.Globalization.CultureInfo resourceCulture; + private static CultureInfo resourceCulture; - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resources() { } /// /// Returns the cached ResourceManager instance used by this class. /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { + [EditorBrowsable(EditorBrowsableState.Advanced)] + internal static ResourceManager ResourceManager { get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TailBlazer.Properties.Resources", typeof(Resources).Assembly); + if (ReferenceEquals(resourceMan, null)) { + ResourceManager temp = new ResourceManager("TailBlazer.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; @@ -50,8 +55,8 @@ internal Resources() { /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { + [EditorBrowsable(EditorBrowsableState.Advanced)] + internal static CultureInfo Culture { get { return resourceCulture; } diff --git a/Source/TailBlazer/Properties/Settings.Designer.cs b/Source/TailBlazer/Properties/Settings.Designer.cs index 3f8582c0..5f21c6ee 100644 --- a/Source/TailBlazer/Properties/Settings.Designer.cs +++ b/Source/TailBlazer/Properties/Settings.Designer.cs @@ -8,14 +8,18 @@ // //------------------------------------------------------------------------------ +using System.CodeDom.Compiler; +using System.Configuration; +using System.Runtime.CompilerServices; + namespace TailBlazer.Properties { - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + [CompilerGenerated()] + [GeneratedCode("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] + internal sealed partial class Settings : ApplicationSettingsBase { - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + private static Settings defaultInstance = ((Settings)(Synchronized(new Settings()))); public static Settings Default { get { diff --git a/Source/TailBlazer/Views/Formatting/ColourProvider.cs b/Source/TailBlazer/Views/Formatting/ColourProvider.cs index c6277084..95a97da4 100644 --- a/Source/TailBlazer/Views/Formatting/ColourProvider.cs +++ b/Source/TailBlazer/Views/Formatting/ColourProvider.cs @@ -30,7 +30,7 @@ public class ColourProvider : IColourProvider "pink", "red", "purple", - "deeppurple", + "deeppurple" }; public ColourProvider() diff --git a/Source/TailBlazer/Views/Formatting/DefaultColourSelector.cs b/Source/TailBlazer/Views/Formatting/DefaultColourSelector.cs index 918a891c..6d9deedf 100644 --- a/Source/TailBlazer/Views/Formatting/DefaultColourSelector.cs +++ b/Source/TailBlazer/Views/Formatting/DefaultColourSelector.cs @@ -3,7 +3,6 @@ using System.Linq; using DynamicData; using DynamicData.Kernel; -using MaterialDesignThemes.Wpf; using TailBlazer.Domain.FileHandling.Search; using TailBlazer.Domain.Formatting; diff --git a/Source/TailBlazer/Views/Formatting/IconDescription.cs b/Source/TailBlazer/Views/Formatting/IconDescription.cs index 1db2ea45..cd1fd8ad 100644 --- a/Source/TailBlazer/Views/Formatting/IconDescription.cs +++ b/Source/TailBlazer/Views/Formatting/IconDescription.cs @@ -33,7 +33,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((IconDescription) obj); } diff --git a/Source/TailBlazer/Views/Layout/LayoutAnalyser.cs b/Source/TailBlazer/Views/Layout/LayoutAnalyser.cs index 098244b9..81fd629e 100644 --- a/Source/TailBlazer/Views/Layout/LayoutAnalyser.cs +++ b/Source/TailBlazer/Views/Layout/LayoutAnalyser.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Windows; using Dragablz; @@ -7,7 +6,6 @@ using TailBlazer.Domain.Settings; using TailBlazer.Infrastucture; - namespace TailBlazer.Views.Layout { diff --git a/Source/TailBlazer/Views/Layout/ShellSettings.cs b/Source/TailBlazer/Views/Layout/ShellSettings.cs index 62e2af4d..9b61d6c0 100644 --- a/Source/TailBlazer/Views/Layout/ShellSettings.cs +++ b/Source/TailBlazer/Views/Layout/ShellSettings.cs @@ -38,7 +38,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((ShellSettings) obj); } diff --git a/Source/TailBlazer/Views/Options/GeneralOptions.cs b/Source/TailBlazer/Views/Options/GeneralOptions.cs index 18359233..23e91dec 100644 --- a/Source/TailBlazer/Views/Options/GeneralOptions.cs +++ b/Source/TailBlazer/Views/Options/GeneralOptions.cs @@ -1,6 +1,4 @@ -using TailBlazer.Settings; - -namespace TailBlazer.Views.Options +namespace TailBlazer.Views.Options { public class GeneralOptions { diff --git a/Source/TailBlazer/Views/Options/GeneralOptionsConverter.cs b/Source/TailBlazer/Views/Options/GeneralOptionsConverter.cs index 39fb5e47..29bf9152 100644 --- a/Source/TailBlazer/Views/Options/GeneralOptionsConverter.cs +++ b/Source/TailBlazer/Views/Options/GeneralOptionsConverter.cs @@ -2,7 +2,6 @@ using System.Xml.Linq; using DynamicData.Kernel; using TailBlazer.Domain.Settings; -using TailBlazer.Settings; namespace TailBlazer.Views.Options { @@ -19,7 +18,7 @@ private static class Structure public GeneralOptions Convert(State state) { - var defaults = this.GetDefaultValue(); + var defaults = GetDefaultValue(); var doc = XDocument.Parse(state.Value); var root = doc.ElementOrThrow(Structure.Root); diff --git a/Source/TailBlazer/Views/Recent/RecentFileProxy.cs b/Source/TailBlazer/Views/Recent/RecentFileProxy.cs index 58ad7a76..4d541591 100644 --- a/Source/TailBlazer/Views/Recent/RecentFileProxy.cs +++ b/Source/TailBlazer/Views/Recent/RecentFileProxy.cs @@ -49,7 +49,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((RecentFileProxy) obj); } diff --git a/Source/TailBlazer/Views/Recent/RecentFilesToStateConverter.cs b/Source/TailBlazer/Views/Recent/RecentFilesToStateConverter.cs index 11d9ba56..29426859 100644 --- a/Source/TailBlazer/Views/Recent/RecentFilesToStateConverter.cs +++ b/Source/TailBlazer/Views/Recent/RecentFilesToStateConverter.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Xml.Linq; using TailBlazer.Domain.Settings; -using TailBlazer.Settings; namespace TailBlazer.Views.Recent { @@ -49,7 +48,7 @@ public State Convert(RecentSearch[] files) fileNodeArray.ForEach(root.Add); - XDocument doc = new XDocument(root); + var doc = new XDocument(root); return new State(2, doc.ToString()); } diff --git a/Source/TailBlazer/Views/Recent/RecentSearch.cs b/Source/TailBlazer/Views/Recent/RecentSearch.cs index a711bacc..2275b205 100644 --- a/Source/TailBlazer/Views/Recent/RecentSearch.cs +++ b/Source/TailBlazer/Views/Recent/RecentSearch.cs @@ -32,7 +32,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((RecentSearch) obj); } diff --git a/Source/TailBlazer/Views/Recent/RecentSearchCollection.cs b/Source/TailBlazer/Views/Recent/RecentSearchCollection.cs index 2a783ab3..25f250ec 100644 --- a/Source/TailBlazer/Views/Recent/RecentSearchCollection.cs +++ b/Source/TailBlazer/Views/Recent/RecentSearchCollection.cs @@ -4,7 +4,6 @@ using DynamicData; using TailBlazer.Domain.Infrastructure; using TailBlazer.Domain.Settings; -using TailBlazer.Settings; using TailBlazer.Views.Searching; namespace TailBlazer.Views.Recent diff --git a/Source/TailBlazer/Views/Searching/IconSelectorView.xaml.cs b/Source/TailBlazer/Views/Searching/IconSelectorView.xaml.cs index 6748bb24..d54cc55b 100644 --- a/Source/TailBlazer/Views/Searching/IconSelectorView.xaml.cs +++ b/Source/TailBlazer/Views/Searching/IconSelectorView.xaml.cs @@ -1,17 +1,4 @@ -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.Controls; namespace TailBlazer.Views.Searching { diff --git a/Source/TailBlazer/Views/Searching/SearchOptionsConverter.cs b/Source/TailBlazer/Views/Searching/SearchOptionsConverter.cs index 36997638..4647bad1 100644 --- a/Source/TailBlazer/Views/Searching/SearchOptionsConverter.cs +++ b/Source/TailBlazer/Views/Searching/SearchOptionsConverter.cs @@ -16,7 +16,7 @@ private static class Structure public SearchOptions Convert(State state) { - var defaults = this.GetDefaultValue(); + var defaults = GetDefaultValue(); //var doc = XDocument.Parse(state.Value); //var root = doc.ElementOrThrow(Structure.Root); diff --git a/Source/TailBlazer/Views/Searching/SearchOptionsProxy.cs b/Source/TailBlazer/Views/Searching/SearchOptionsProxy.cs index 33217ae5..c8b77e4a 100644 --- a/Source/TailBlazer/Views/Searching/SearchOptionsProxy.cs +++ b/Source/TailBlazer/Views/Searching/SearchOptionsProxy.cs @@ -1,19 +1,17 @@ using System; using System.Collections.Generic; -using System.Reactive.Linq; using System.Reactive.Disposables; +using System.Reactive.Linq; using System.Windows.Input; using System.Windows.Media; using DynamicData.Binding; using DynamicData.Kernel; using MaterialDesignThemes.Wpf; -using TailBlazer.Controls; using TailBlazer.Domain.Annotations; using TailBlazer.Domain.FileHandling.Search; using TailBlazer.Domain.Formatting; using TailBlazer.Domain.Infrastructure; using TailBlazer.Infrastucture; -using Hue = TailBlazer.Domain.Formatting.Hue; namespace TailBlazer.Views.Searching { @@ -176,7 +174,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((SearchOptionsProxy) obj); } diff --git a/Source/TailBlazer/Views/Searching/SearchOptionsView.xaml.cs b/Source/TailBlazer/Views/Searching/SearchOptionsView.xaml.cs index cd7cc74d..060690d8 100644 --- a/Source/TailBlazer/Views/Searching/SearchOptionsView.xaml.cs +++ b/Source/TailBlazer/Views/Searching/SearchOptionsView.xaml.cs @@ -1,17 +1,4 @@ -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.Controls; namespace TailBlazer.Settings { diff --git a/Source/TailBlazer/Views/Searching/SearchOptionsViewModel.cs b/Source/TailBlazer/Views/Searching/SearchOptionsViewModel.cs index 81c9e437..05f71913 100644 --- a/Source/TailBlazer/Views/Searching/SearchOptionsViewModel.cs +++ b/Source/TailBlazer/Views/Searching/SearchOptionsViewModel.cs @@ -3,9 +3,9 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; +using System.Reactive.Concurrency; using System.Reactive.Disposables; using System.Reactive.Linq; -using System.Reactive.Concurrency; using Dragablz; using DynamicData; using DynamicData.Binding; diff --git a/Source/TailBlazer/Views/Tail/LineProxy.cs b/Source/TailBlazer/Views/Tail/LineProxy.cs index 8ba0c32c..e0d82b03 100644 --- a/Source/TailBlazer/Views/Tail/LineProxy.cs +++ b/Source/TailBlazer/Views/Tail/LineProxy.cs @@ -111,7 +111,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((LineProxy) obj); } diff --git a/Source/TailBlazer/Views/Tail/TailViewModel.cs b/Source/TailBlazer/Views/Tail/TailViewModel.cs index 7a51f33f..647a3d51 100644 --- a/Source/TailBlazer/Views/Tail/TailViewModel.cs +++ b/Source/TailBlazer/Views/Tail/TailViewModel.cs @@ -1,8 +1,6 @@ using System; -using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; -using System.IO; using System.Linq; using System.Reactive.Disposables; using System.Reactive.Linq; @@ -13,7 +11,6 @@ using DynamicData.Binding; using DynamicData.PLinq; using MaterialDesignThemes.Wpf; -using Microsoft.Win32; using TailBlazer.Controls; using TailBlazer.Domain.Annotations; using TailBlazer.Domain.FileHandling; @@ -192,7 +189,7 @@ public TailViewModel([NotNull] ILogger logger, //return an empty line provider unless user is viewing inline - this saves needless trips to the file var inline = searchInfoCollection.All.CombineLatest(inlineViewerVisible, (index, ud) => ud ? index : new EmptyLineProvider()); - var firstVisibleRow = this._data.ToObservableChangeSet().ToCollection() + var firstVisibleRow = _data.ToObservableChangeSet().ToCollection() .Select(collection => collection.FirstOrDefault()); //var itemToSelect = this.WhenValueChanged(vm => vm.SelectedItem) @@ -281,8 +278,7 @@ each time I have tried to remove it all hell has broken loose void IScrollReceiver.ScrollChanged(ScrollChangedArgs scrollChangedArgs) { - if (scrollChangedArgs.Direction == ScrollDirection.Up) - AutoTail = false; + AutoTail &= scrollChangedArgs.Direction != ScrollDirection.Up; } void IScrollReceiver.ScrollDiff(int linesChanged) diff --git a/Source/TailBlazer/Views/Tail/TailViewModelFactory.cs b/Source/TailBlazer/Views/Tail/TailViewModelFactory.cs index 79383d88..6bad97ad 100644 --- a/Source/TailBlazer/Views/Tail/TailViewModelFactory.cs +++ b/Source/TailBlazer/Views/Tail/TailViewModelFactory.cs @@ -50,7 +50,7 @@ public TailViewModel Create(FileInfo fileInfo) new[] { new ExplictArg("fileWatcher", fileWatcher), - new ExplictArg("searchMetadataCollection", searchMetadataCollection), + new ExplictArg("searchMetadataCollection", searchMetadataCollection) } ); diff --git a/Source/TailBlazer/Views/Tail/TailViewPersister.cs b/Source/TailBlazer/Views/Tail/TailViewPersister.cs index 6e837376..c9a46773 100644 --- a/Source/TailBlazer/Views/Tail/TailViewPersister.cs +++ b/Source/TailBlazer/Views/Tail/TailViewPersister.cs @@ -124,7 +124,7 @@ public State Convert(TailViewState state) root.Add(list); - XDocument doc = new XDocument(root); + var doc = new XDocument(root); return new State(1, doc.ToString()); } From bf5136e8a4012b5c93ccf22bf34df95ac6d37280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Magyar?= Date: Sat, 2 Apr 2016 10:41:11 +0200 Subject: [PATCH 02/11] File tailing mechanism has been implemented. Added some test files. --- .../FileHandling/EmptyLineProvider.cs | 6 + .../FileHandling/FileSearchResult.cs | 6 + .../FileHandling/FileSegment.cs | 4 + .../FileHandling/FileSegmentCollection.cs | 34 +- .../FileHandling/FileSegmentEx.cs | 3 + .../FileHandling/FileSegmenter.cs | 50 ++- .../FileHandling/FilesWatcher.cs | 85 +++++ .../FileHandling/ILineProvider.cs | 5 +- .../TailBlazer.Domain/FileHandling/Index.cs | 3 +- .../FileHandling/IndexCollection.cs | 323 +++++++++++------- .../TailBlazer.Domain/FileHandling/IndexEx.cs | 7 +- .../TailBlazer.Domain/FileHandling/Indexer.cs | 119 ++++--- .../FileHandling/LineScroller.cs | 53 ++- .../Search/ISearchInfoCollection.cs | 2 + .../FileHandling/Search/SearchInfo.cs | 2 + .../Search/SearchInfoCollection.cs | 46 +-- .../FileHandling/StreamReaderExtended.cs | 270 +++++++-------- .../FileHandling/TailInfo.cs | 8 +- .../Infrastructure/ImmutableList.cs | 15 +- .../Infrastructure/ReactiveEx.cs | 143 ++++++-- .../TailBlazer.Domain.csproj | 1 + .../TailBlazer.Fixtures/FileSegmentFixture.cs | 41 +++ Source/TailBlazer.Fixtures/IndexerFixture.cs | 59 +++- .../ReorderingEventsTests.cs | 122 +++++++ .../TailBlazer.Fixtures.csproj | 2 + .../TailBlazer.Fixtures/TestFileCollection.cs | 74 ++++ .../Infrastucture/DebugConverter.cs | 26 ++ .../TailBlazer/Infrastucture/FilesHeader.cs | 32 ++ .../Infrastucture/FilesNameConverter.cs | 32 ++ Source/TailBlazer/MainWindow.xaml | 9 + Source/TailBlazer/TailBlazer.csproj | 31 +- .../Views/FileDrop/FileDropMonitor.cs | 7 +- .../Views/Searching/SearchCollection.cs | 6 +- Source/TailBlazer/Views/Tail/TailView.xaml | 7 +- Source/TailBlazer/Views/Tail/TailViewModel.cs | 204 +++++------ .../Views/Tail/TailViewModelFactory.cs | 55 ++- .../Views/Tail/TailViewPersister.cs | 7 +- Source/TailBlazer/Views/Tail/TailViewState.cs | 6 +- .../Views/WindowManagement/WindowViewModel.cs | 48 +++ Source/TailBlazer/packages.config | 8 + 40 files changed, 1412 insertions(+), 549 deletions(-) create mode 100644 Source/TailBlazer.Domain/FileHandling/FilesWatcher.cs create mode 100644 Source/TailBlazer.Fixtures/ReorderingEventsTests.cs create mode 100644 Source/TailBlazer.Fixtures/TestFileCollection.cs create mode 100644 Source/TailBlazer/Infrastucture/DebugConverter.cs create mode 100644 Source/TailBlazer/Infrastucture/FilesHeader.cs create mode 100644 Source/TailBlazer/Infrastucture/FilesNameConverter.cs diff --git a/Source/TailBlazer.Domain/FileHandling/EmptyLineProvider.cs b/Source/TailBlazer.Domain/FileHandling/EmptyLineProvider.cs index 47aaa53e..322bf19a 100644 --- a/Source/TailBlazer.Domain/FileHandling/EmptyLineProvider.cs +++ b/Source/TailBlazer.Domain/FileHandling/EmptyLineProvider.cs @@ -10,5 +10,11 @@ public IEnumerable ReadLines(ScrollRequest scroll) { yield break; } + + public int CompareTo(object obj) + { + var other = obj as EmptyLineProvider; + return Count.CompareTo(other?.Count); + } } } \ No newline at end of file diff --git a/Source/TailBlazer.Domain/FileHandling/FileSearchResult.cs b/Source/TailBlazer.Domain/FileHandling/FileSearchResult.cs index 4317a7ef..75d308c6 100644 --- a/Source/TailBlazer.Domain/FileHandling/FileSearchResult.cs +++ b/Source/TailBlazer.Domain/FileHandling/FileSearchResult.cs @@ -218,6 +218,12 @@ public override int GetHashCode() } } + public int CompareTo(object obj) + { + //TODO: implement this the right way + throw new NotImplementedException(); + } + public static bool operator ==(FileSearchResult left, FileSearchResult right) { return Equals(left, right); diff --git a/Source/TailBlazer.Domain/FileHandling/FileSegment.cs b/Source/TailBlazer.Domain/FileHandling/FileSegment.cs index 97b17b77..78989b23 100644 --- a/Source/TailBlazer.Domain/FileHandling/FileSegment.cs +++ b/Source/TailBlazer.Domain/FileHandling/FileSegment.cs @@ -1,4 +1,5 @@ using System; +using System.Security.AccessControl; namespace TailBlazer.Domain.FileHandling { @@ -11,6 +12,7 @@ public class FileSegment : IEquatable public long Size => End - Start; public FileSegmentKey Key { get; } + public FileSegment(int index, long start, long end, FileSegmentType type) { Index = index; @@ -20,6 +22,7 @@ public FileSegment(int index, long start, long end, FileSegmentType type) Key=new FileSegmentKey(index,type); } + public FileSegment(FileSegment previous, long end) { Index = previous.Index; @@ -29,6 +32,7 @@ public FileSegment(FileSegment previous, long end) Key = previous.Key; } + #region Equality public bool Equals(FileSegment other) diff --git a/Source/TailBlazer.Domain/FileHandling/FileSegmentCollection.cs b/Source/TailBlazer.Domain/FileHandling/FileSegmentCollection.cs index b9cd4080..8ca36466 100644 --- a/Source/TailBlazer.Domain/FileHandling/FileSegmentCollection.cs +++ b/Source/TailBlazer.Domain/FileHandling/FileSegmentCollection.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; @@ -6,22 +7,22 @@ namespace TailBlazer.Domain.FileHandling { public class FileSegmentCollection : IEquatable { - private long sizeDiff; - public FileInfo Info { get; } public FileSegment[] Segments { get; } public long TailStartsAt { get; } public int Count { get; } public FileSegmentChangedReason Reason { get; } public FileSegment Tail => Segments[Count - 1]; + public FileSegmentCollection Link { get; private set; } public long FileLength => Tail.End; + public bool IsFirst { get; set; } public long FileSize { get; } public long SizeDiff { get; } - public FileSegmentCollection(FileInfo fileInfo, FileSegment[] segments, long sizeDiff) + public FileSegmentCollection(FileInfo fileInfo, FileSegment[] segments, long sizeDiff, bool isfirst) { if (segments.Length == 0) throw new ArgumentException("Argument is empty collection", nameof(segments)); @@ -33,27 +34,22 @@ public FileSegmentCollection(FileInfo fileInfo, FileSegment[] segments, long siz FileSize = TailStartsAt; SizeDiff = sizeDiff; Reason = FileSegmentChangedReason.Loaded; + IsFirst = isfirst; } - public FileSegmentCollection(long newLength, FileSegmentCollection previous) + public FileSegmentCollection(FileSegmentCollection previous, FileInfo fileInfo, FileSegment[] segments, + long sizeDiff, bool isfirst) + : this(fileInfo, segments, sizeDiff, isfirst) { - SizeDiff = newLength - previous.FileLength; - - //All this assumes it is the tail which has changed, but that may not be so - Reason = FileSegmentChangedReason.Tailed; - Info = previous.Info; - - var last = previous.Tail; - TailStartsAt = last.End; - - var segments = previous.Segments; - segments[segments.Length-1] = new FileSegment(last, newLength); - Segments = segments; - Count = Segments.Length; - FileSize = newLength; + Link = previous; + } + public FileSegmentCollection(FileSegmentCollection fileSegmentCollection) + : this(fileSegmentCollection.Info, fileSegmentCollection.Segments, fileSegmentCollection.SizeDiff, fileSegmentCollection.IsFirst) + { + Link = fileSegmentCollection.Link; } - + #region Equality public bool Equals(FileSegmentCollection other) diff --git a/Source/TailBlazer.Domain/FileHandling/FileSegmentEx.cs b/Source/TailBlazer.Domain/FileHandling/FileSegmentEx.cs index ab36cd4a..d64af2ff 100644 --- a/Source/TailBlazer.Domain/FileHandling/FileSegmentEx.cs +++ b/Source/TailBlazer.Domain/FileHandling/FileSegmentEx.cs @@ -1,5 +1,8 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Reactive.Linq; +using TailBlazer.Domain.Infrastructure; namespace TailBlazer.Domain.FileHandling { diff --git a/Source/TailBlazer.Domain/FileHandling/FileSegmenter.cs b/Source/TailBlazer.Domain/FileHandling/FileSegmenter.cs index ec345da8..afa02aed 100644 --- a/Source/TailBlazer.Domain/FileHandling/FileSegmenter.cs +++ b/Source/TailBlazer.Domain/FileHandling/FileSegmenter.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Reactive.Disposables; using System.Reactive.Linq; namespace TailBlazer.Domain.FileHandling @@ -19,58 +20,51 @@ Should resize as files grow [Not implemented yet] public sealed class FileSegmenter { - private FileInfo _info; + private FileInfo _info; private readonly int _initialTail; private readonly int _segmentSize; public IObservable Segments { get; } - public FileSegmenter(IObservable notifications, - int initialTail= 100000, - int segmentSize=25000000) + public FileSegmenter(IObservable notifications, + int initialTail = 100000, + int segmentSize = 25000000) { if (notifications == null) throw new ArgumentNullException(nameof(notifications)); _initialTail = initialTail; _segmentSize = segmentSize; - - - //TODO: Re-segment as file grows + account for rollover Segments = notifications - //.notifications() - .Scan((FileSegmentCollection) null, (previous, current) => - { - if (previous == null || previous.FileLength == 0) - { - _info =(FileInfo) current; + .Scan((FileSegmentCollection)null, Accumulator) + .Replay(1).RefCount(); - var segments = LoadSegments().ToArray(); - return new FileSegmentCollection(_info, segments, current.Size); - } - var newLength = _info.Length; + } - if (newLength < previous.FileLength) - { - var sizeDiff = newLength - previous.FileLength; - var segments = LoadSegments().ToArray(); - return new FileSegmentCollection(_info, segments, sizeDiff); - } + private FileSegmentCollection Accumulator(FileSegmentCollection previous, FileNotification current) + { + if (previous == null || previous.FileLength == 0) + { + _info = (FileInfo)current; + + var fileSegments = LoadSegments().ToArray(); + return new FileSegmentCollection(_info, fileSegments, current.Size, true); + } - return new FileSegmentCollection(newLength, previous); - }).Replay(1).RefCount(); + _info = (FileInfo)current; + return new FileSegmentCollection(previous, _info, LoadSegments().ToArray(), current.Size, false); } public IEnumerable LoadSegments() { - using (var stream = File.Open(_info.FullName, FileMode.Open, FileAccess.Read,FileShare.Delete | FileShare.ReadWrite)) + using (var stream = File.Open(_info.FullName, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite)) { var fileLength = stream.Length; stream.Seek(0, SeekOrigin.Begin); using (var reader = new StreamReaderExtended(stream, true)) { - if (reader.EndOfStream || fileLength == 0) + if (reader.EndOfStream || fileLength == 0) { yield return new FileSegment(0, 0, 0, FileSegmentType.Tail); yield break; @@ -104,7 +98,7 @@ public IEnumerable LoadSegments() } while (true); - index ++; + index++; yield return new FileSegment(index, headStartsAt, fileLength, FileSegmentType.Tail); } } diff --git a/Source/TailBlazer.Domain/FileHandling/FilesWatcher.cs b/Source/TailBlazer.Domain/FileHandling/FilesWatcher.cs new file mode 100644 index 00000000..7a09f24c --- /dev/null +++ b/Source/TailBlazer.Domain/FileHandling/FilesWatcher.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Reactive.Concurrency; +using System.Reactive.Disposables; + +namespace TailBlazer.Domain.FileHandling +{ + public class FilesWatcher : IList + { + public IList List { get; } = new List(); + + #region Implementation of IEnumerable + public IEnumerator GetEnumerator() + { + return List.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + #endregion + + #region Implementation of ICollection + public void Add(FileWatcher item) + { + List.Add(item); + } + + public void Clear() + { + List.Clear(); + } + + public bool Contains(FileWatcher item) + { + return List.Contains(item); + } + + public void CopyTo(FileWatcher[] array, int arrayIndex) + { + List.CopyTo(array, arrayIndex); + } + + public bool Remove(FileWatcher item) + { + return List.Remove(item); + } + + public int Count => List.Count; + public bool IsReadOnly => List.IsReadOnly; + + public int IndexOf(FileWatcher item) + { + return List.IndexOf(item); + } + + public void Insert(int index, FileWatcher item) + { + List.Insert(index, item); + } + + public void RemoveAt(int index) + { + List.RemoveAt(index); + } + + public FileWatcher this[int index] + { + get { return List[index]; } + set { List[index] = value; } + } + #endregion + + public FilesWatcher(IEnumerable files, IScheduler scheduler = null) + { + foreach (var fileInfo in files) + { + Add(new FileWatcher(fileInfo, scheduler)); + } + } + } +} \ No newline at end of file diff --git a/Source/TailBlazer.Domain/FileHandling/ILineProvider.cs b/Source/TailBlazer.Domain/FileHandling/ILineProvider.cs index 26c3e0eb..8cbd35b4 100644 --- a/Source/TailBlazer.Domain/FileHandling/ILineProvider.cs +++ b/Source/TailBlazer.Domain/FileHandling/ILineProvider.cs @@ -1,8 +1,9 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace TailBlazer.Domain.FileHandling { - public interface ILineProvider + public interface ILineProvider : IComparable { //bool IsEmpty { get; } diff --git a/Source/TailBlazer.Domain/FileHandling/Index.cs b/Source/TailBlazer.Domain/FileHandling/Index.cs index 045ae70c..94b8cc23 100644 --- a/Source/TailBlazer.Domain/FileHandling/Index.cs +++ b/Source/TailBlazer.Domain/FileHandling/Index.cs @@ -62,7 +62,8 @@ public bool Equals(Index other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; - return Start == other.Start && End == other.End && Compression == other.Compression && LineCount == other.LineCount && Type == other.Type && TimeStamp.Equals(other.TimeStamp); + return Start == other.Start && End == other.End && Compression == other.Compression && + LineCount == other.LineCount && Type == other.Type && TimeStamp.Equals(other.TimeStamp); } public override bool Equals(object obj) diff --git a/Source/TailBlazer.Domain/FileHandling/IndexCollection.cs b/Source/TailBlazer.Domain/FileHandling/IndexCollection.cs index f29b4f7a..f4916b33 100644 --- a/Source/TailBlazer.Domain/FileHandling/IndexCollection.cs +++ b/Source/TailBlazer.Domain/FileHandling/IndexCollection.cs @@ -1,33 +1,26 @@ using System; +using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using Microsoft.SqlServer.Server; namespace TailBlazer.Domain.FileHandling { - public class IndexCollection: ILineProvider + public class IndexCollection : ILineProvider { - public int Count { get; } - public int Diff { get; } - public bool IsEmpty => Count != 0; - private LinesChangedReason ChangedReason { get; } - private Index[] Indicies { get; } - private FileInfo Info { get; } - private Encoding Encoding { get; } - private TailInfo TailInfo { get; } - public IndexCollection(IReadOnlyCollection latest, - IndexCollection previous, - FileInfo info, - Encoding encoding) + IndexCollection previous, + FileInfo info, + Encoding encoding) { Info = info; Encoding = encoding; Count = latest.Select(idx => idx.LineCount).Sum(); Indicies = latest.ToArray(); Diff = Count - (previous?.Count ?? 0); - + //need to check whether if (previous == null) { @@ -38,15 +31,38 @@ public IndexCollection(IReadOnlyCollection latest, { var mostRecent = latest.OrderByDescending(l => l.TimeStamp).First(); ChangedReason = mostRecent.Type == IndexType.Tail - ? LinesChangedReason.Tailed - : LinesChangedReason.Paged; + ? LinesChangedReason.Tailed + : LinesChangedReason.Paged; - TailInfo = new TailInfo(previous.Indicies.Max(idx => idx.End)); + TailInfo = new TailInfo(previous.Indicies.Max(idx => idx.End)); + Next = previous; } } + public IndexCollection(IndexCollection indexCollection) + { + Info = indexCollection.Info; + Encoding = indexCollection.Encoding; + Count = indexCollection.Count; + Indicies = indexCollection.Indicies; + Diff = indexCollection.Diff; + ChangedReason = indexCollection.ChangedReason; + TailInfo = indexCollection.TailInfo; + Next = indexCollection.Next; + } + + public int Diff { get; } + public bool IsEmpty => Count != 0; + private LinesChangedReason ChangedReason { get; } + public Index[] Indicies { get; } + public FileInfo Info { get; } + private Encoding Encoding { get; } + public TailInfo TailInfo { get; } + public IndexCollection Next { get; private set; } + public int Count { get; } + /// - /// Reads the lines. + /// Reads the lines. /// /// The scroll. /// @@ -59,116 +75,163 @@ public IEnumerable ReadLines(ScrollRequest scroll) } else { + foreach (var line in ReadLinesByIndex(scroll)) yield return line; } } - private IEnumerable ReadLinesByIndex(ScrollRequest scroll) + struct LastValueWrapper { + public long LastEndPosition { get; set; } + public int LastPageIndex { get; set; } + } - var page = GetPage(scroll); - - var relativeIndex = CalculateRelativeIndex(page.Start); - if (relativeIndex == null) yield break; - - var offset = relativeIndex.LinesOffset; - - using (var stream = File.Open(Info.FullName, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite)) + private IEnumerable ReadLinesByIndex(ScrollRequest scroll) + { + var current = this; + LastValueWrapper lastValueWrapper = new LastValueWrapper(); + var iterationCounter = 0; + var page = GetPage(scroll, current); + var relativeIndex = CalculateRelativeIndex(page.Start, ref current, lastValueWrapper); + + while (relativeIndex != null && current != null) { - using (var reader = new StreamReaderExtended(stream, Encoding, false)) + if (current.Indicies.Length > 0 && current.Indicies.Any(t => t.Indicies.Count == 0)) + { + yield break; + } + if (lastValueWrapper.LastPageIndex == page.Start + page.Size) { - //go to starting point - stream.Seek(relativeIndex.Start, SeekOrigin.Begin); - if (offset > 0) + yield break; + } + var offset = relativeIndex.LinesOffset; + using ( + var stream = File.Open(current.Info.FullName, FileMode.Open, FileAccess.Read, + FileShare.Delete | FileShare.ReadWrite)) + { + using (var reader = new StreamReaderExtended(stream, current.Encoding, false)) { - //skip number of lines offset - for (int i = 0; i < offset; i++) + //go to starting point + stream.Seek((iterationCounter > 0)? 0 : relativeIndex.Start, SeekOrigin.Begin); + if (iterationCounter == 0 && offset > 0) + { + //skip number of lines offset + for (var i = 0; i < offset; i++) + { + reader.ReadLine(); + } + } + + //if estimate move to the next start of line + if (iterationCounter == 0 && relativeIndex.IsEstimate && relativeIndex.Start != 0) + { reader.ReadLine(); - } - - //if estimate move to the next start of line - if (relativeIndex.IsEstimate && relativeIndex.Start != 0) - reader.ReadLine(); - - foreach (var i in Enumerable.Range(page.Start, page.Size)) - { - var startPosition = reader.AbsolutePosition(); - var line = reader.ReadLine(); - var endPosition = reader.AbsolutePosition(); - var info = new LineInfo(i + 1, i, startPosition, endPosition); - - var ontail = startPosition >= TailInfo.TailStartsAt && DateTime.Now.Subtract(TailInfo.LastTail).TotalSeconds < 1 - ? DateTime.Now - : (DateTime?)null; - - yield return new Line(info, line, ontail); + } + + foreach (var i in Enumerable.Range((iterationCounter > 0) ? lastValueWrapper.LastPageIndex : page.Start, page.Size)) + { + if (i == page.Start + page.Size) + { + lastValueWrapper.LastPageIndex = i; + yield break; + } + var startPosition = reader.AbsolutePosition() + lastValueWrapper.LastEndPosition; + var line = reader.ReadLine(); + var endPosition = reader.AbsolutePosition() + lastValueWrapper.LastEndPosition; + + var info = new LineInfo(i + 1, i, startPosition, endPosition); + + var ontail = startPosition >= current.TailInfo.TailStartsAt && + DateTime.Now.Subtract(current.TailInfo.LastTail).TotalSeconds < 1 + ? DateTime.Now + : (DateTime?)null; + + yield return new Line(info, line, ontail); + + lastValueWrapper.LastPageIndex = i + 1; + + if (reader.EndOfStream) + { + lastValueWrapper.LastEndPosition += endPosition + 1; + break; + } + } } } + iterationCounter++; + current = current.Next; } } private IEnumerable ReadLinesByPosition(ScrollRequest scroll) { - //TODO: Calculate initial index of first item. - + //scroll from specified position - using (var stream = File.Open(Info.FullName, FileMode.Open, FileAccess.Read,FileShare.Delete | FileShare.ReadWrite)) + using ( + var stream = File.Open(Info.FullName, FileMode.Open, FileAccess.Read, + FileShare.Delete | FileShare.ReadWrite)) { - int taken = 0; + var taken = 0; using (var reader = new StreamReaderExtended(stream, Encoding, false)) { - var startPosition = scroll.Position; - var first = (int)CalculateIndexByPositon(startPosition); + var first = (int) CalculateIndexByPositon(startPosition); reader.BaseStream.Seek(startPosition, SeekOrigin.Begin); do { - var line = reader.ReadLine(); - if (line==null) yield break; + if (line == null) yield break; var endPosition = reader.AbsolutePosition(); var info = new LineInfo(first + taken + 1, first + taken, startPosition, endPosition); - var ontail = endPosition >= TailInfo.TailStartsAt && DateTime.Now.Subtract(TailInfo.LastTail).TotalSeconds < 1 + var ontail = endPosition >= TailInfo.TailStartsAt && + DateTime.Now.Subtract(TailInfo.LastTail).TotalSeconds < 1 ? DateTime.Now - : (DateTime?)null; + : (DateTime?) null; yield return new Line(info, line, ontail); startPosition = endPosition; taken++; - } while (taken < scroll.PageSize); } } } - private Page GetPage(ScrollRequest scroll) + private Page GetPage(ScrollRequest scroll, IndexCollection indexCollection) { var first = scroll.FirstIndex; var size = scroll.PageSize; - + var indexCollectionsCount = 0; + //collect files line count + while (indexCollection != null) + { + if (indexCollection.Indicies.Length > 0 && indexCollection.Indicies.Any(t => t.Indicies.Count == 0)) + { + indexCollection = indexCollection.Next; + continue; + } + indexCollectionsCount += indexCollection.Count; + indexCollection = indexCollection.Next; + } if (scroll.Mode == ScrollReason.Tail) { - first = size > Count ? 0 : Count - size; + first = size > indexCollectionsCount ? 0 : indexCollectionsCount - size; } - else + else if (scroll.FirstIndex + size >= indexCollectionsCount) { - - if (scroll.FirstIndex + size >= Count) - first = Count - size; - + first = indexCollectionsCount - size; } first = Math.Max(0, first); - size = Math.Min(size, Count); + size = Math.Min(size, indexCollectionsCount); return new Page(first, size); } @@ -187,32 +250,32 @@ private long CalculateIndexByPositon(long position) { var lines = sparseIndex.LineCount; var bytes = sparseIndex.End - sparseIndex.Start; - var bytesPerLine = bytes / lines; + var bytesPerLine = bytes/lines; - return position / bytesPerLine; + return position/bytesPerLine; } if (sparseIndex.Compression == 1) { - return firstLineInContainer + sparseIndex.Indicies.IndexOf(position); + return firstLineInContainer + sparseIndex.Indicies.IndexOf(position); } - + //find nearest, then work out offset var nearest = sparseIndex.Indicies.Data - .Select((value,index)=>new {value,index}) - .OrderByDescending(x=>x.value) + .Select((value, index) => new {value, index}) + .OrderByDescending(x => x.value) .FirstOrDefault(i => i.value <= position); if (nearest != null) { //index depends of how far in container - var relativeIndex = nearest.index * sparseIndex.Compression; + var relativeIndex = nearest.index*sparseIndex.Compression; //remaining size var size = (sparseIndex.End - sparseIndex.Start); - var offset = (position - nearest.value); - var estimateOffset = (offset/size) * sparseIndex.Compression; + var offset = (position - nearest.value); + var estimateOffset = (offset/size)*sparseIndex.Compression; return firstLineInContainer + relativeIndex + estimateOffset; } else @@ -223,61 +286,65 @@ private long CalculateIndexByPositon(long position) //remaining size var size = (sparseIndex.End - sparseIndex.Start); var offset = position; - var estimateOffset = (offset / size) * sparseIndex.Compression; - return firstLineInContainer + relativeIndex + estimateOffset; + var estimateOffset = (offset/size)*sparseIndex.Compression; + return firstLineInContainer + relativeIndex + estimateOffset; } } firstLineInContainer = firstLineInContainer + sparseIndex.LineCount; } return -1; } - private RelativeIndex CalculateRelativeIndex(int index) + + private RelativeIndex CalculateRelativeIndex(int index, ref IndexCollection indexCollection, LastValueWrapper lastValueWrapper) { - int firstLineInContainer = 0; - int lastLineInContainer = 0; + var firstLineInContainer = 0; + var lastLineInContainer = 0; - foreach (var sparseIndex in Indicies) + while (indexCollection != null) { - lastLineInContainer += sparseIndex.LineCount; - if (index < lastLineInContainer) + foreach (var sparseIndex in indexCollection.Indicies) { - //It could be that the user is scrolling into a part of the file - //which is still being indexed [or will never be indexed]. - //In this case we need to estimate where to scroll to - if (sparseIndex.LineCount != 0 && sparseIndex.Indicies.Count == 0) + lastLineInContainer += sparseIndex.LineCount; + if (index < lastLineInContainer) { - //return estimate here! - var lines = sparseIndex.LineCount; - var bytes = sparseIndex.End - sparseIndex.Start; - var bytesPerLine = bytes/lines; - var estimate = index*bytesPerLine; - - - return new RelativeIndex(index, estimate, 0,true); + //It could be that the user is scrolling into a part of the file + //which is still being indexed [or will never be indexed]. + //In this case we need to estimate where to scroll to + if (sparseIndex.LineCount != 0 && sparseIndex.Indicies.Count == 0) + { + //return estimate here! + var lines = sparseIndex.LineCount; + var bytes = sparseIndex.End - sparseIndex.Start; + var bytesPerLine = bytes / lines; + var estimate = index * bytesPerLine; + + + return new RelativeIndex(index, estimate, 0, true); + } + + var relativePosition = (index - firstLineInContainer); + var relativeIndex = relativePosition / sparseIndex.Compression; + var offset = relativePosition % sparseIndex.Compression; + + if (relativeIndex >= sparseIndex.IndexCount) + relativeIndex = sparseIndex.IndexCount - 1; + var start = relativeIndex == 0 ? 0 : sparseIndex.Indicies[relativeIndex - 1]; + return new RelativeIndex(index, start, offset, false); } - - var relativePosition = (index - firstLineInContainer); - var relativeIndex = relativePosition / sparseIndex.Compression; - var offset = relativePosition % sparseIndex.Compression; - - if (relativeIndex >= sparseIndex.IndexCount) - relativeIndex = sparseIndex.IndexCount - 1; - var start = relativeIndex == 0 ? 0 : sparseIndex.Indicies[relativeIndex - 1]; - return new RelativeIndex(index, start, offset,false); + firstLineInContainer = firstLineInContainer + sparseIndex.LineCount; } - firstLineInContainer = firstLineInContainer + sparseIndex.LineCount; + lastValueWrapper.LastEndPosition += indexCollection.Indicies + .Where(localIndex => localIndex.IndexCount > 0) + .Sum(localIndex => localIndex.Indicies[localIndex.IndexCount - 1]); + + indexCollection = indexCollection.Next; } + return null; } private class RelativeIndex { - public long Index { get; } - public long Start { get; } - public int LinesOffset { get; } - public bool IsEstimate { get; } - - public RelativeIndex(long index, long start, int linesOffset, bool isEstimate) { Index = index; @@ -285,6 +352,30 @@ public RelativeIndex(long index, long start, int linesOffset, bool isEstimate) LinesOffset = linesOffset; IsEstimate = isEstimate; } + + public long Index { get; } + public long Start { get; } + public int LinesOffset { get; } + public bool IsEstimate { get; } + } + + public int CompareTo(object obj) + { + var it = this; + int counter = 0; + while (it != null) + { + counter++; + it = it.Next; + } + var ic = obj as IndexCollection; + int objCounter = 0; + while (ic != null) + { + objCounter++; + ic = ic.Next; + } + return counter.CompareTo(objCounter); } } } \ No newline at end of file diff --git a/Source/TailBlazer.Domain/FileHandling/IndexEx.cs b/Source/TailBlazer.Domain/FileHandling/IndexEx.cs index a6d56e26..157215c8 100644 --- a/Source/TailBlazer.Domain/FileHandling/IndexEx.cs +++ b/Source/TailBlazer.Domain/FileHandling/IndexEx.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Reactive.Disposables; using System.Reactive.Linq; @@ -34,7 +36,10 @@ public static IObservable Index(this IObservable Index(this IEnumerable> source) + { + return source.Merge().WithSegments().Index(); + } } } \ No newline at end of file diff --git a/Source/TailBlazer.Domain/FileHandling/Indexer.cs b/Source/TailBlazer.Domain/FileHandling/Indexer.cs index 25f0dd96..1f24eaac 100644 --- a/Source/TailBlazer.Domain/FileHandling/Indexer.cs +++ b/Source/TailBlazer.Domain/FileHandling/Indexer.cs @@ -5,7 +5,6 @@ using System.Reactive.Concurrency; using System.Reactive.Disposables; using System.Reactive.Linq; -using System.Text; using DynamicData; using DynamicData.Binding; using TailBlazer.Domain.Annotations; @@ -25,21 +24,16 @@ 4. Ensure Tail is initally small and can be returned to the consumer very quickl An alternative solution to what I got now is to do a triple index (as per point 3). In doing so it would make the rx easier and get rid of the need for the observable list */ + public class Indexer : IDisposable { private readonly IDisposable _cleanUp; private readonly ISourceList _indicies = new SourceList(); - public Encoding Encoding { get; private set; } - public FileInfo Info { get; private set; } - - public IObservable Result { get; } - public Indexer([NotNull] IObservable fileSegments, int compression = 10, int tailSize = 1000000, - int sizeOfFileAtWhichThereIsAbsolutelyNoPointInIndexing= 250000000, - Encoding encoding = null, + int sizeOfFileAtWhichThereIsAbsolutelyNoPointInIndexing = 250000000, IScheduler scheduler = null) { if (fileSegments == null) throw new ArgumentNullException(nameof(fileSegments)); @@ -49,38 +43,39 @@ public Indexer([NotNull] IObservable fileSegments, scheduler = scheduler ?? Scheduler.Default; var shared = fileSegments.Replay(1).RefCount(); - + //1. Get information from segment info - var infoSubscriber = shared.Select(segments => segments.Info) - .Take(1) - .Subscribe(info => - { - Info = info; - Encoding = encoding ?? info.GetEncoding(); - }); - + var infoSubscriber = shared + .Select(segments => segments.Info) + .Subscribe(info => { Info = info; }); + //2. create a resulting index object from the collection of index fragments Result = _indicies .Connect() .Sort(SortExpressionComparer.Ascending(si => si.Start)) .ToCollection() - .Scan((IndexCollection)null, (previous, notification) => new IndexCollection(notification, previous, Info, Encoding)) + .Scan((IndexCollection) null, + (previous, notification) => new IndexCollection(notification, previous, Info, Info.GetEncoding())) .Replay(1).RefCount(); //3. Scan the tail so results can be returned quickly - var tailScanner= shared.Select(segments => segments.Tail).DistinctUntilChanged() - .Scan((Index)null, (previous, current) => - { - if (previous == null) + FileInfo lastFileInfo = null; + var tailScanner = shared.Select(segments => segments.Tail) + .DistinctUntilChanged() + .Scan((Index) null, (previous, current) => + { + if (previous == null || (lastFileInfo != null && !lastFileInfo.Equals(Info))) { var initial = Scan(current.Start, -1, 1); - return initial ?? new Index(0, 0,0,0,IndexType.Tail); + lastFileInfo = Info; + return initial ?? new Index(0, 0, 0, 0, IndexType.Tail); } - var latest=Scan(previous.End , -1, 1); - return latest == null ? null : new Index(latest,previous); + var latest = Scan(previous.End, -1, 1); + lastFileInfo = Info; + return latest == null ? null : new Index(latest, previous); }) - .Where(tail=>tail!=null) + .Where(tail => tail != null) .Replay(1).RefCount(); //4. estimate = @@ -94,9 +89,9 @@ public Indexer([NotNull] IObservable fileSegments, }); }); - + //Scan the remainer of the file - var headSubscriber = tailScanner.FirstAsync() + var headSubscriber = tailScanner .Subscribe(tail => { if (tail.Start == 0) return; @@ -112,43 +107,53 @@ public Indexer([NotNull] IObservable fileSegments, //todo: index first and last segment for large sized file scheduler.Schedule(() => + { + var actual = Scan(0, tail.Start, compression); + _indicies.Edit(innerList => { - var actual = Scan(0, tail.Start, compression); - _indicies.Edit(innerList => - { - innerList.Remove(estimate); - innerList.Add(actual); - }); + innerList.Remove(estimate); + innerList.Add(actual); }); + }); }); - _cleanUp = new CompositeDisposable(infoSubscriber,_indicies, tailSubscriber, tailSubscriber, headSubscriber); + _cleanUp = new CompositeDisposable(infoSubscriber, _indicies, tailSubscriber, tailSubscriber, headSubscriber); + } + + public FileInfo Info { get; private set; } + public IObservable Result { get; } + + public void Dispose() + { + _cleanUp.Dispose(); } private int EstimateNumberOfLines(Index tail, FileInfo info) { //Calculate estimate line count - var averageLineLength = tail.Size / tail.LineCount; - var estimatedLines = (info.Length - tail.Size) / averageLineLength; - return (int)estimatedLines; + var averageLineLength = tail.Size/tail.LineCount; + var estimatedLines = (info.Length - tail.Size)/averageLineLength; + return (int) estimatedLines; } - private Index Scan( long start, long end, int compression) + private Index Scan(long start, long end, int compression) { - int count = 0; + var count = 0; long lastPosition = 0; - using (var stream = File.Open(Info.FullName, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite)) + using ( + var stream = File.Open(Info.FullName, FileMode.Open, FileAccess.Read, + FileShare.Delete | FileShare.ReadWrite)) { long[] lines; - using (var reader = new StreamReaderExtended(stream, Encoding, false)) + using (var reader = new StreamReaderExtended(stream, Info.GetEncoding(), false)) { var currentPosition = reader.AbsolutePosition(); - if (currentPosition!= start) + if (currentPosition != start) stream.Seek(start, SeekOrigin.Begin); if (reader.EndOfStream) return null; - lines = ScanLines(reader,compression, i => i, (line, position) => + lines = ScanLines(reader, compression, i => i, (line, position) => { var shouldBreak = end != -1 && lastPosition >= end; if (!shouldBreak) @@ -158,28 +163,27 @@ private Index Scan( long start, long end, int compression) count++; } return shouldBreak; - }).ToArray(); } - if (end != -1 && lastPosition> end) + if (end != -1 && lastPosition > end) { count--; lastPosition = end; lines = lines.Take(lines.Length - 1).ToArray(); } - return new Index(start, lastPosition, lines, compression, count, end == -1 ? IndexType.Tail : IndexType.Page); + return new Index(start, lastPosition, lines, compression, count, + end == -1 ? IndexType.Tail : IndexType.Page); } } - private static IEnumerable ScanLines( StreamReaderExtended source, - int compression, - Func selector, - Func shouldBreak) + private static IEnumerable ScanLines(StreamReaderExtended source, + int compression, + Func selector, + Func shouldBreak) { - - int i = 0; + var i = 0; if (source.EndOfStream) yield break; string line; @@ -195,15 +199,8 @@ private static IEnumerable ScanLines( StreamReaderExtended source, { yield return selector(position); i = 0; - }; - - + } } } - - public void Dispose() - { - _cleanUp.Dispose(); - } } } \ No newline at end of file diff --git a/Source/TailBlazer.Domain/FileHandling/LineScroller.cs b/Source/TailBlazer.Domain/FileHandling/LineScroller.cs index c98d0d49..9159a860 100644 --- a/Source/TailBlazer.Domain/FileHandling/LineScroller.cs +++ b/Source/TailBlazer.Domain/FileHandling/LineScroller.cs @@ -1,10 +1,17 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; +using System.Reactive; using System.Reactive.Concurrency; using System.Reactive.Disposables; using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Runtime.CompilerServices; +using System.Threading; using DynamicData; +using DynamicData.Aggregation; +using DynamicData.Binding; using TailBlazer.Domain.Annotations; using TailBlazer.Domain.Infrastructure; @@ -13,16 +20,13 @@ namespace TailBlazer.Domain.FileHandling public class LineScroller : ILineScroller { private readonly IDisposable _cleanUp; - - public IObservableCache Lines { get; } - [Obsolete("USE OTHER OVERLOAD")] public LineScroller(FileInfo file, - IObservable latest, - IObservable scrollRequest, - ILogger logger, - IScheduler scheduler = null) + IObservable latest, + IObservable scrollRequest, + ILogger logger, + IScheduler scheduler = null) { if (file == null) throw new ArgumentNullException(nameof(file)); if (latest == null) throw new ArgumentNullException(nameof(latest)); @@ -30,18 +34,19 @@ public LineScroller(FileInfo file, logger.Info($"Constructing file tailer for {file.FullName}"); - var lines = new SourceCache(l=>l.Key); + var lines = new SourceCache(l => l.Key); Lines = lines.AsObservableCache(); var locker = new object(); scrollRequest = scrollRequest.Synchronize(locker); - var aggregator = latest.CombineLatest(scrollRequest, (currentLines, scroll) => currentLines.ReadLines(scroll).ToArray()) + var aggregator = latest.CombineLatest(scrollRequest, + (currentLines, scroll) => currentLines.ReadLines(scroll).ToArray()) .Subscribe(currentPage => { var previous = lines.Items.ToArray(); - var added = currentPage.Except(previous,Line.TextStartComparer).ToArray(); + var added = currentPage.Except(previous, Line.TextStartComparer).ToArray(); var removed = previous.Except(currentPage, Line.TextStartComparer).ToArray(); lines.Edit(innerCache => @@ -54,27 +59,41 @@ public LineScroller(FileInfo file, _cleanUp = new CompositeDisposable(Lines, lines, aggregator); } - - public LineScroller([NotNull] IObservable latest, [NotNull] IObservable scrollRequest) + public LineScroller([NotNull] IObservable latest, + [NotNull] IObservable scrollRequest) { if (latest == null) throw new ArgumentNullException(nameof(latest)); if (scrollRequest == null) throw new ArgumentNullException(nameof(scrollRequest)); var lines = new SourceCache(l => l.Key); - Lines = lines.Connect().IgnoreUpdateWhen((current,previous)=> current.Key==previous.Key).AsObservableCache(); + Lines = + lines.Connect().IgnoreUpdateWhen((current, previous) => current.Key == previous.Key).AsObservableCache(); var locker = new object(); scrollRequest = scrollRequest.Synchronize(locker); latest = latest.Synchronize(locker); + var aggregator = latest - .CombineLatest(scrollRequest, (currentLines, scroll) => new { currentLines, scroll}) + .MaxSequenceOfSource( + provider => + { + var ic = provider as IndexCollection; + int summarizedCounter = 0; + while (ic != null) + { + summarizedCounter += ic.Count; + ic = ic.Next; + } + return summarizedCounter; + }) + .CombineLatest(scrollRequest, (currentLines, scroll) => new { currentLines, scroll }) .Sample(TimeSpan.FromMilliseconds(50)) .Select(x => { - if (x.scroll== ScrollRequest.None || x.scroll.PageSize == 0 || x.currentLines.Count == 0) + if (x.scroll == ScrollRequest.None || x.scroll.PageSize == 0 || x.currentLines.Count == 0) return new Line[0]; return x.currentLines.ReadLines(x.scroll).ToArray(); @@ -96,9 +115,11 @@ public LineScroller([NotNull] IObservable latest, [NotNull] IObse _cleanUp = new CompositeDisposable(Lines, lines, aggregator); } + public IObservableCache Lines { get; } + public void Dispose() { _cleanUp.Dispose(); } } -} +} \ No newline at end of file diff --git a/Source/TailBlazer.Domain/FileHandling/Search/ISearchInfoCollection.cs b/Source/TailBlazer.Domain/FileHandling/Search/ISearchInfoCollection.cs index 3fe9db8c..9022bef7 100644 --- a/Source/TailBlazer.Domain/FileHandling/Search/ISearchInfoCollection.cs +++ b/Source/TailBlazer.Domain/FileHandling/Search/ISearchInfoCollection.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using DynamicData; +using DynamicData.Binding; namespace TailBlazer.Domain.FileHandling.Search { diff --git a/Source/TailBlazer.Domain/FileHandling/Search/SearchInfo.cs b/Source/TailBlazer.Domain/FileHandling/Search/SearchInfo.cs index 5c4a5915..7240513e 100644 --- a/Source/TailBlazer.Domain/FileHandling/Search/SearchInfo.cs +++ b/Source/TailBlazer.Domain/FileHandling/Search/SearchInfo.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using DynamicData.Binding; using TailBlazer.Domain.Annotations; namespace TailBlazer.Domain.FileHandling.Search diff --git a/Source/TailBlazer.Domain/FileHandling/Search/SearchInfoCollection.cs b/Source/TailBlazer.Domain/FileHandling/Search/SearchInfoCollection.cs index 6dc1365f..d271b93f 100644 --- a/Source/TailBlazer.Domain/FileHandling/Search/SearchInfoCollection.cs +++ b/Source/TailBlazer.Domain/FileHandling/Search/SearchInfoCollection.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Reactive.Disposables; using System.Reactive.Linq; using DynamicData; @@ -9,63 +11,67 @@ namespace TailBlazer.Domain.FileHandling.Search { public sealed class SearchInfoCollection : ISearchInfoCollection { - private readonly ISearchMetadataCollection _metadataCollection; - private readonly ISearchMetadataFactory _searchMetadataFactory; + private readonly IDisposable _cleanUp; private readonly IColourProvider _colourProvider; - private readonly IFileWatcher _fileWatcher; private readonly IDefaultIconSelector _defaultIconSelector; - private readonly IDisposable _cleanUp; + private readonly IEnumerable _filesWatcher; + private readonly ISearchMetadataCollection _metadataCollection; + private readonly ISearchMetadataFactory _searchMetadataFactory; - public IObservableCache Searches { get; } - - public IObservable All { get; } - public SearchInfoCollection(ISearchMetadataCollection searchMetadataCollection, ISearchMetadataFactory searchMetadataFactory, IColourProvider colourProvider, - IFileWatcher fileWatcher, + IEnumerable filesWatcher, IDefaultIconSelector defaultIconSelector) { _metadataCollection = searchMetadataCollection; _searchMetadataFactory = searchMetadataFactory; _colourProvider = colourProvider; - _fileWatcher = fileWatcher; + _filesWatcher = filesWatcher; _defaultIconSelector = defaultIconSelector; //Add a complete file display - All = fileWatcher.Latest.Index().Replay(1).RefCount(); + All = _filesWatcher + .Select(t => t.Latest) + .Index() + .Replay(1) + .RefCount(); //create a collection with 1 item, which is used to show entire file var systemSearches = new SourceCache(t => t.SearchText); systemSearches.AddOrUpdate(new SearchInfo("", All, SearchType.All)); - + //create a collection of all possible user filters var userSearches = searchMetadataCollection.Metadata .Connect(meta => meta.Filter) - .IgnoreUpdateWhen((current,previous)=> SearchMetadata.EffectsFilterComparer.Equals(current, previous)) + .IgnoreUpdateWhen((current, previous) => SearchMetadata.EffectsFilterComparer.Equals(current, previous)) .Transform(meta => { - var latest = _fileWatcher.Latest - .Search(meta.BuildPredicate()) - .Replay(1).RefCount(); + var latest = _filesWatcher + .Select(t => t.Latest + .Search(meta.BuildPredicate())) + .Merge().Replay(1).RefCount(); return new SearchInfo(meta.SearchText, latest, SearchType.User); }); //combine te results into a single collection Searches = systemSearches.Connect() - .Or(userSearches) - .AsObservableCache(); + .Or(userSearches) + .AsObservableCache(); _cleanUp = new CompositeDisposable(Searches, systemSearches); } + public IObservableCache Searches { get; } + public IObservable All { get; } + public void Add([NotNull] string searchText, bool useRegex) { if (searchText == null) throw new ArgumentNullException(nameof(searchText)); var index = _metadataCollection.NextIndex(); - var metatdata = _searchMetadataFactory.Create(searchText, useRegex, index,true); + var metatdata = _searchMetadataFactory.Create(searchText, useRegex, index, true); _metadataCollection.AddorUpdate(metatdata); } @@ -79,4 +85,4 @@ public void Dispose() _cleanUp.Dispose(); } } -} +} \ No newline at end of file diff --git a/Source/TailBlazer.Domain/FileHandling/StreamReaderExtended.cs b/Source/TailBlazer.Domain/FileHandling/StreamReaderExtended.cs index 16b4cc08..175a72f0 100644 --- a/Source/TailBlazer.Domain/FileHandling/StreamReaderExtended.cs +++ b/Source/TailBlazer.Domain/FileHandling/StreamReaderExtended.cs @@ -29,18 +29,18 @@ public class StreamReaderExtended : TextReader private bool _closable; // For Console.In. We should consider exposing a Closable bit perhaps on stream at some point. - private Stream stream; - private Encoding encoding; - private Decoder decoder; - private byte[] byteBuffer; - private char[] charBuffer; + private Stream _stream; + private Encoding _encoding; + private Decoder _decoder; + private byte[] _byteBuffer; + private char[] _charBuffer; private byte[] _preamble; // Encoding's preamble, which identifies this encoding. - private int charPos; - private int charLen; + private int _charPos; + private int _charLen; // Record the number of valid bytes in the byteBuffer, for a few checks. - private int byteLen; + private int _byteLen; // This is used only for preamble detection - private int bytePos; + private int _bytePos; // This is the maximum number of chars we can get from one call to // ReadBuffer. Used so ReadBuffer can tell when to copy data into @@ -126,7 +126,7 @@ internal StreamReaderExtended(Stream stream, Encoding encoding, bool detectEncod [SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] - public StreamReaderExtended(String path) + public StreamReaderExtended(string path) : this(path, true) { } @@ -134,7 +134,7 @@ public StreamReaderExtended(String path) [SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] - public StreamReaderExtended(String path, bool detectEncodingFromByteOrderMarks) + public StreamReaderExtended(string path, bool detectEncodingFromByteOrderMarks) : this(path, Encoding.UTF8, detectEncodingFromByteOrderMarks, DefaultBufferSize) { } @@ -142,7 +142,7 @@ public StreamReaderExtended(String path, bool detectEncodingFromByteOrderMarks) [SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] - public StreamReaderExtended(String path, Encoding encoding) + public StreamReaderExtended(string path, Encoding encoding) : this(path, encoding, true, DefaultBufferSize) { } @@ -150,7 +150,7 @@ public StreamReaderExtended(String path, Encoding encoding) [SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] - public StreamReaderExtended(String path, Encoding encoding, bool detectEncodingFromByteOrderMarks) + public StreamReaderExtended(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks) : this(path, encoding, detectEncodingFromByteOrderMarks, DefaultBufferSize) { } @@ -158,7 +158,7 @@ public StreamReaderExtended(String path, Encoding encoding, bool detectEncodingF [SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] - public StreamReaderExtended(String path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize) + public StreamReaderExtended(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize) { // Don't open a Stream before checking for invalid arguments, // or we'll create a FileStream on disk and we won't close it until @@ -168,23 +168,23 @@ public StreamReaderExtended(String path, Encoding encoding, bool detectEncodingF if (path.Length == 0) throw new ArgumentException("Path is empty"); if (bufferSize <= 0) - throw new ArgumentOutOfRangeException("bufferSize"); + throw new ArgumentOutOfRangeException(nameof(bufferSize)); - Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, DefaultFileStreamBufferSize, FileOptions.SequentialScan); - Init(stream, encoding, detectEncodingFromByteOrderMarks, bufferSize); + Stream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, DefaultFileStreamBufferSize, FileOptions.SequentialScan); + Init(fileStream, encoding, detectEncodingFromByteOrderMarks, bufferSize); } private void Init(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize) { - this.stream = stream; - this.encoding = encoding; - decoder = encoding.GetDecoder(); + _stream = stream; + _encoding = encoding; + _decoder = encoding.GetDecoder(); if (bufferSize < MinBufferSize) bufferSize = MinBufferSize; - byteBuffer = new byte[bufferSize]; + _byteBuffer = new byte[bufferSize]; _maxCharsPerBuffer = encoding.GetMaxCharCount(bufferSize); - charBuffer = new char[_maxCharsPerBuffer]; - byteLen = 0; - bytePos = 0; + _charBuffer = new char[_maxCharsPerBuffer]; + _byteLen = 0; + _bytePos = 0; _detectEncoding = detectEncodingFromByteOrderMarks; _preamble = encoding.GetPreamble(); _checkPreamble = (_preamble.Length > 0); @@ -195,7 +195,7 @@ private void Init(Stream stream, Encoding encoding, bool detectEncodingFromByteO // Init used by NullStreamReader, to delay load encoding internal void Init(Stream stream) { - this.stream = stream; + _stream = stream; _closable = true; } @@ -212,20 +212,20 @@ protected override void Dispose(bool disposing) { // Note that Stream.Close() can potentially throw here. So we need to // ensure cleaning up internal resources, inside the finally block. - if (Closable && disposing && (stream != null)) - stream.Close(); + if (Closable && disposing && (_stream != null)) + _stream.Close(); } finally { - if (Closable && (stream != null)) + if (Closable && (_stream != null)) { - stream = null; - encoding = null; - decoder = null; - byteBuffer = null; - charBuffer = null; - charPos = 0; - charLen = 0; + _stream = null; + _encoding = null; + _decoder = null; + _byteBuffer = null; + _charBuffer = null; + _charPos = 0; + _charLen = 0; base.Dispose(disposing); } } @@ -233,12 +233,12 @@ protected override void Dispose(bool disposing) public virtual Encoding CurrentEncoding { - get { return encoding; } + get { return _encoding; } } public virtual Stream BaseStream { - get { return stream; } + get { return _stream; } } internal bool Closable @@ -256,14 +256,14 @@ internal bool Closable // users need to re-read the contents of a StreamReader a second time. public void DiscardBufferedData() { - byteLen = 0; - charLen = 0; - charPos = 0; + _byteLen = 0; + _charLen = 0; + _charPos = 0; // in general we'd like to have an invariant that encoding isn't null. However, // for startup improvements for NullStreamReader, we want to delay load encoding. - if (encoding != null) + if (_encoding != null) { - decoder = encoding.GetDecoder(); + _decoder = _encoding.GetDecoder(); } _isBlocked = false; } @@ -274,7 +274,7 @@ public bool EndOfStream get { - if (charPos < charLen) + if (_charPos < _charLen) return false; // This may block on pipes! @@ -288,23 +288,23 @@ public bool EndOfStream public override int Peek() { - if (charPos == charLen) + if (_charPos == _charLen) { if (_isBlocked || ReadBuffer() == 0) return -1; } - return charBuffer[charPos]; + return _charBuffer[_charPos]; } [SecuritySafeCritical] // auto-generated public override int Read() { - if (charPos == charLen) + if (_charPos == _charLen) { if (ReadBuffer() == 0) return -1; } - int result = charBuffer[charPos]; - charPos++; + int result = _charBuffer[_charPos]; + _charPos++; return result; } @@ -324,14 +324,14 @@ public override int Read([In, Out] char[] buffer, int index, int count) bool readToUserBuffer = false; while (count > 0) { - int n = charLen - charPos; + int n = _charLen - _charPos; if (n == 0) n = ReadBuffer(buffer, index + charsRead, count, out readToUserBuffer); if (n == 0) break; // We're at EOF if (n > count) n = count; if (!readToUserBuffer) { - Buffer.BlockCopy(charBuffer, charPos * 2, buffer, (index + charsRead) * 2, n * 2); - charPos += n; + Buffer.BlockCopy(_charBuffer, _charPos * 2, buffer, (index + charsRead) * 2, n * 2); + _charPos += n; } charsRead += n; count -= n; @@ -345,17 +345,17 @@ public override int Read([In, Out] char[] buffer, int index, int count) } [SecuritySafeCritical] // auto-generated - public override String ReadToEnd() + public override string ReadToEnd() { // Call ReadBuffer, then pull data out of charBuffer. - var sb = new StringBuilder(charLen - charPos); + var sb = new StringBuilder(_charLen - _charPos); do { - sb.Append(charBuffer, charPos, charLen - charPos); - charPos = charLen; // Note we consumed these characters + sb.Append(_charBuffer, _charPos, _charLen - _charPos); + _charPos = _charLen; // Note we consumed these characters ReadBuffer(); - } while (charLen > 0); + } while (_charLen > 0); return sb.ToString(); } @@ -364,32 +364,32 @@ public override String ReadToEnd() // Trims n bytes from the front of the buffer. private void CompressBuffer(int n) { - Contract.Assert(byteLen >= n, "CompressBuffer was called with a number of bytes greater than the current buffer length. Are two threads using this StreamReader at the same time?"); - Buffer.BlockCopy(byteBuffer, n, byteBuffer, 0, byteLen - n); - byteLen -= n; + Contract.Assert(_byteLen >= n, "CompressBuffer was called with a number of bytes greater than the current buffer length. Are two threads using this StreamReader at the same time?"); + Buffer.BlockCopy(_byteBuffer, n, _byteBuffer, 0, _byteLen - n); + _byteLen -= n; } private void DetectEncoding() { - if (byteLen < 2) + if (_byteLen < 2) return; _detectEncoding = false; bool changedEncoding = false; - if (byteBuffer[0] == 0xFE && byteBuffer[1] == 0xFF) + if (_byteBuffer[0] == 0xFE && _byteBuffer[1] == 0xFF) { // Big Endian Unicode - encoding = new UnicodeEncoding(true, true); + _encoding = new UnicodeEncoding(true, true); CompressBuffer(2); changedEncoding = true; } - else if (byteBuffer[0] == 0xFF && byteBuffer[1] == 0xFE) + else if (_byteBuffer[0] == 0xFF && _byteBuffer[1] == 0xFE) { // Little Endian Unicode, or possibly little endian UTF32 - if (byteLen < 4 || byteBuffer[2] != 0 || byteBuffer[3] != 0) + if (_byteLen < 4 || _byteBuffer[2] != 0 || _byteBuffer[3] != 0) { - encoding = new UnicodeEncoding(false, true); + _encoding = new UnicodeEncoding(false, true); CompressBuffer(2); changedEncoding = true; } @@ -402,10 +402,10 @@ private void DetectEncoding() #endif } - else if (byteLen >= 3 && byteBuffer[0] == 0xEF && byteBuffer[1] == 0xBB && byteBuffer[2] == 0xBF) + else if (_byteLen >= 3 && _byteBuffer[0] == 0xEF && _byteBuffer[1] == 0xBB && _byteBuffer[2] == 0xBF) { // UTF-8 - encoding = Encoding.UTF8; + _encoding = Encoding.UTF8; CompressBuffer(3); changedEncoding = true; } @@ -418,15 +418,15 @@ private void DetectEncoding() changedEncoding = true; } #endif - else _detectEncoding |= byteLen == 2; + else _detectEncoding |= _byteLen == 2; // Note: in the future, if we change this algorithm significantly, // we can support checking for the preamble of the given encoding. if (changedEncoding) { - decoder = encoding.GetDecoder(); - _maxCharsPerBuffer = encoding.GetMaxCharCount(byteBuffer.Length); - charBuffer = new char[_maxCharsPerBuffer]; + _decoder = _encoding.GetDecoder(); + _maxCharsPerBuffer = _encoding.GetMaxCharCount(_byteBuffer.Length); + _charBuffer = new char[_maxCharsPerBuffer]; } } @@ -440,28 +440,28 @@ private bool IsPreamble() if (!_checkPreamble) return _checkPreamble; - Contract.Assert(bytePos <= _preamble.Length, "_compressPreamble was called with the current bytePos greater than the preamble buffer length. Are two threads using this StreamReader at the same time?"); - int len = (byteLen >= (_preamble.Length)) ? (_preamble.Length - bytePos) : (byteLen - bytePos); + Contract.Assert(_bytePos <= _preamble.Length, "_compressPreamble was called with the current bytePos greater than the preamble buffer length. Are two threads using this StreamReader at the same time?"); + int len = (_byteLen >= (_preamble.Length)) ? (_preamble.Length - _bytePos) : (_byteLen - _bytePos); - for (int i = 0; i < len; i++, bytePos++) + for (int i = 0; i < len; i++, _bytePos++) { - if (byteBuffer[bytePos] != _preamble[bytePos]) + if (_byteBuffer[_bytePos] != _preamble[_bytePos]) { - bytePos = 0; + _bytePos = 0; _checkPreamble = false; break; } } - Contract.Assert(bytePos <= _preamble.Length, "possible bug in _compressPreamble. Are two threads using this StreamReader at the same time?"); + Contract.Assert(_bytePos <= _preamble.Length, "possible bug in _compressPreamble. Are two threads using this StreamReader at the same time?"); if (_checkPreamble) { - if (bytePos == _preamble.Length) + if (_bytePos == _preamble.Length) { // We have a match CompressBuffer(_preamble.Length); - bytePos = 0; + _bytePos = 0; _checkPreamble = false; _detectEncoding = false; } @@ -472,45 +472,45 @@ private bool IsPreamble() internal virtual int ReadBuffer() { - charLen = 0; - charPos = 0; + _charLen = 0; + _charPos = 0; if (!_checkPreamble) - byteLen = 0; + _byteLen = 0; do { if (_checkPreamble) { - Contract.Assert(bytePos <= _preamble.Length, "possible bug in _compressPreamble. Are two threads using this StreamReader at the same time?"); - int len = stream.Read(byteBuffer, bytePos, byteBuffer.Length - bytePos); + Contract.Assert(_bytePos <= _preamble.Length, "possible bug in _compressPreamble. Are two threads using this StreamReader at the same time?"); + int len = _stream.Read(_byteBuffer, _bytePos, _byteBuffer.Length - _bytePos); Contract.Assert(len >= 0, "Stream.Read returned a negative number! This is a bug in your stream class."); if (len == 0) { // EOF but we might have buffered bytes from previous // attempts to detecting preamble that needs to decoded now - if (byteLen > 0) - charLen += decoder.GetChars(byteBuffer, 0, byteLen, charBuffer, charLen); + if (_byteLen > 0) + _charLen += _decoder.GetChars(_byteBuffer, 0, _byteLen, _charBuffer, _charLen); - return charLen; + return _charLen; } - byteLen += len; + _byteLen += len; } else { - Contract.Assert(bytePos == 0, "bytePos can be non zero only when we are trying to _checkPreamble. Are two threads using this StreamReader at the same time?"); - byteLen = stream.Read(byteBuffer, 0, byteBuffer.Length); - Contract.Assert(byteLen >= 0, "Stream.Read returned a negative number! This is a bug in your stream class."); + Contract.Assert(_bytePos == 0, "bytePos can be non zero only when we are trying to _checkPreamble. Are two threads using this StreamReader at the same time?"); + _byteLen = _stream.Read(_byteBuffer, 0, _byteBuffer.Length); + Contract.Assert(_byteLen >= 0, "Stream.Read returned a negative number! This is a bug in your stream class."); - if (byteLen == 0) // We're at EOF - return charLen; + if (_byteLen == 0) // We're at EOF + return _charLen; } // _isBlocked == whether we read fewer bytes than we asked for. // Note we must check it here because CompressBuffer or // DetectEncoding will change byteLen. - _isBlocked = (byteLen < byteBuffer.Length); + _isBlocked = (_byteLen < _byteBuffer.Length); // Check for preamble before detect encoding. This is not to override the // user suppplied Encoding for the one we implicitly detect. The user could @@ -520,13 +520,13 @@ internal virtual int ReadBuffer() // If we're supposed to detect the encoding and haven't done so yet, // do it. Note this may need to be called more than once. - if (_detectEncoding && byteLen >= 2) + if (_detectEncoding && _byteLen >= 2) DetectEncoding(); - charLen += decoder.GetChars(byteBuffer, 0, byteLen, charBuffer, charLen); - } while (charLen == 0); + _charLen += _decoder.GetChars(_byteBuffer, 0, _byteLen, _charBuffer, _charLen); + } while (_charLen == 0); //Console.WriteLine("ReadBuffer called. chars: "+charLen); - return charLen; + return _charLen; } @@ -539,11 +539,11 @@ internal virtual int ReadBuffer() // this on the first call to ReadBuffer. private int ReadBuffer(char[] userBuffer, int userOffset, int desiredChars, out bool readToUserBuffer) { - charLen = 0; - charPos = 0; + _charLen = 0; + _charPos = 0; if (!_checkPreamble) - byteLen = 0; + _byteLen = 0; int charsRead = 0; @@ -564,46 +564,46 @@ private int ReadBuffer(char[] userBuffer, int userOffset, int desiredChars, out { if (_checkPreamble) { - Contract.Assert(bytePos <= _preamble.Length, "possible bug in _compressPreamble. Are two threads using this StreamReader at the same time?"); - int len = stream.Read(byteBuffer, bytePos, byteBuffer.Length - bytePos); + Contract.Assert(_bytePos <= _preamble.Length, "possible bug in _compressPreamble. Are two threads using this StreamReader at the same time?"); + int len = _stream.Read(_byteBuffer, _bytePos, _byteBuffer.Length - _bytePos); Contract.Assert(len >= 0, "Stream.Read returned a negative number! This is a bug in your stream class."); if (len == 0) { // EOF but we might have buffered bytes from previous // attempts to detecting preamble that needs to decoded now - if (byteLen > 0) + if (_byteLen > 0) { if (readToUserBuffer) { - charsRead += decoder.GetChars(byteBuffer, 0, byteLen, userBuffer, userOffset + charsRead); - charLen = 0; // StreamReader's buffer is empty. + charsRead += _decoder.GetChars(_byteBuffer, 0, _byteLen, userBuffer, userOffset + charsRead); + _charLen = 0; // StreamReader's buffer is empty. } else { - charsRead = decoder.GetChars(byteBuffer, 0, byteLen, charBuffer, charsRead); - charLen += charsRead; // Number of chars in StreamReader's buffer. + charsRead = _decoder.GetChars(_byteBuffer, 0, _byteLen, _charBuffer, charsRead); + _charLen += charsRead; // Number of chars in StreamReader's buffer. } } return charsRead; } - byteLen += len; + _byteLen += len; } else { - Contract.Assert(bytePos == 0, "bytePos can be non zero only when we are trying to _checkPreamble. Are two threads using this StreamReader at the same time?"); - byteLen = stream.Read(byteBuffer, 0, byteBuffer.Length); - Contract.Assert(byteLen >= 0, "Stream.Read returned a negative number! This is a bug in your stream class."); + Contract.Assert(_bytePos == 0, "bytePos can be non zero only when we are trying to _checkPreamble. Are two threads using this StreamReader at the same time?"); + _byteLen = _stream.Read(_byteBuffer, 0, _byteBuffer.Length); + Contract.Assert(_byteLen >= 0, "Stream.Read returned a negative number! This is a bug in your stream class."); - if (byteLen == 0) // EOF + if (_byteLen == 0) // EOF return charsRead; } // _isBlocked == whether we read fewer bytes than we asked for. // Note we must check it here because CompressBuffer or // DetectEncoding will change byteLen. - _isBlocked = (byteLen < byteBuffer.Length); + _isBlocked = (_byteLen < _byteBuffer.Length); // Check for preamble before detect encoding. This is not to override the // user suppplied Encoding for the one we implicitly detect. The user could @@ -614,23 +614,23 @@ private int ReadBuffer(char[] userBuffer, int userOffset, int desiredChars, out continue; // On the first call to ReadBuffer, if we're supposed to detect the encoding, do it. - if (_detectEncoding && byteLen >= 2) + if (_detectEncoding && _byteLen >= 2) { DetectEncoding(); // DetectEncoding changes some buffer state. Recompute this. readToUserBuffer = desiredChars >= _maxCharsPerBuffer; } - charPos = 0; + _charPos = 0; if (readToUserBuffer) { - charsRead += decoder.GetChars(byteBuffer, 0, byteLen, userBuffer, userOffset + charsRead); - charLen = 0; // StreamReader's buffer is empty. + charsRead += _decoder.GetChars(_byteBuffer, 0, _byteLen, userBuffer, userOffset + charsRead); + _charLen = 0; // StreamReader's buffer is empty. } else { - charsRead = decoder.GetChars(byteBuffer, 0, byteLen, charBuffer, charsRead); - charLen += charsRead; // Number of chars in StreamReader's buffer. + charsRead = _decoder.GetChars(_byteBuffer, 0, _byteLen, _charBuffer, charsRead); + _charLen += charsRead; // Number of chars in StreamReader's buffer. } } while (charsRead == 0); @@ -648,48 +648,48 @@ private int ReadBuffer(char[] userBuffer, int userOffset, int desiredChars, out // value is null if the end of the input stream has been reached. // [SecuritySafeCritical] // auto-generated - public override String ReadLine() + public override string ReadLine() { //if (stream == null) // __Error.ReaderClosed(); - if (charPos == charLen) + if (_charPos == _charLen) { if (ReadBuffer() == 0) return null; } StringBuilder sb = null; do { - int i = charPos; + int i = _charPos; do { - char ch = charBuffer[i]; + char ch = _charBuffer[i]; // Note the following common line feed chars: // \n - UNIX \r\n - DOS \r - Mac if (ch == '\r' || ch == '\n') { - String s; + string s; if (sb != null) { - sb.Append(charBuffer, charPos, i - charPos); + sb.Append(_charBuffer, _charPos, i - _charPos); s = sb.ToString(); } else { - s = new String(charBuffer, charPos, i - charPos); + s = new string(_charBuffer, _charPos, i - _charPos); } - charPos = i + 1; - if (ch == '\r' && (charPos < charLen || ReadBuffer() > 0)) + _charPos = i + 1; + if (ch == '\r' && (_charPos < _charLen || ReadBuffer() > 0)) { - if (charBuffer[charPos] == '\n') charPos++; + if (_charBuffer[_charPos] == '\n') _charPos++; } return s; } i++; - } while (i < charLen); - i = charLen - charPos; + } while (i < _charLen); + i = _charLen - _charPos; if (sb == null) sb = new StringBuilder(i + 80); - sb.Append(charBuffer, charPos, i); + sb.Append(_charBuffer, _charPos, i); } while (ReadBuffer() > 0); return sb.ToString(); } @@ -697,9 +697,9 @@ public override String ReadLine() public long AbsolutePosition() { // The number of bytes that the already-read characters need when encoded. - int numReadBytes = CurrentEncoding.GetByteCount(charBuffer, 0, charPos); + int numReadBytes = CurrentEncoding.GetByteCount(_charBuffer, 0, _charPos); - return BaseStream.Position - byteLen + numReadBytes; + return BaseStream.Position - _byteLen + numReadBytes; } } diff --git a/Source/TailBlazer.Domain/FileHandling/TailInfo.cs b/Source/TailBlazer.Domain/FileHandling/TailInfo.cs index 83bc0d4e..aab8fe42 100644 --- a/Source/TailBlazer.Domain/FileHandling/TailInfo.cs +++ b/Source/TailBlazer.Domain/FileHandling/TailInfo.cs @@ -2,7 +2,7 @@ namespace TailBlazer.Domain.FileHandling { - public class TailInfo + public class TailInfo : IComparable { public static readonly TailInfo None = new TailInfo(); @@ -20,5 +20,11 @@ public TailInfo(long tailStartsAt) private TailInfo() { } + + public int CompareTo(object obj) + { + var other = obj as TailInfo; + return LastTail.CompareTo(other?.LastTail); + } } } \ No newline at end of file diff --git a/Source/TailBlazer.Domain/Infrastructure/ImmutableList.cs b/Source/TailBlazer.Domain/Infrastructure/ImmutableList.cs index 13e87aae..d17211a0 100644 --- a/Source/TailBlazer.Domain/Infrastructure/ImmutableList.cs +++ b/Source/TailBlazer.Domain/Infrastructure/ImmutableList.cs @@ -1,10 +1,11 @@ -using System.Collections.Generic; +using System.Collections; +using System.Collections.Generic; using System.Collections.ObjectModel; using DynamicData; namespace TailBlazer.Domain.Infrastructure { - public class ImmutableList + public class ImmutableList : IEnumerable { public static readonly ImmutableList Empty = new ImmutableList(); @@ -85,5 +86,15 @@ public int IndexOf(T value) { return _data.IndexOf(value); } + + public IEnumerator GetEnumerator() + { + return _data.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } } } \ No newline at end of file diff --git a/Source/TailBlazer.Domain/Infrastructure/ReactiveEx.cs b/Source/TailBlazer.Domain/Infrastructure/ReactiveEx.cs index 81e422cd..5f5ac4c1 100644 --- a/Source/TailBlazer.Domain/Infrastructure/ReactiveEx.cs +++ b/Source/TailBlazer.Domain/Infrastructure/ReactiveEx.cs @@ -1,8 +1,11 @@ using System; +using System.Collections.Generic; using System.Reactive; using System.Reactive.Disposables; using System.Reactive.Linq; using System.Reactive.Subjects; +using System.Reactive.Threading.Tasks; +using static System.Reactive.Linq.Observable; namespace TailBlazer.Domain.Infrastructure { @@ -14,14 +17,114 @@ public enum PropertyType public static class ReactiveEx { + public static IObservable MaxSequenceOfSource(this IObservable source, Func selector) + where TKey : IComparable, IEquatable + { + return Create(observer => + { + var lastKey = default(TKey); + var largestT = default(T); + int counter = 1; + int countOfTailedFile = 0; + return source + .GroupBy(t => t) + .Select(t => + { + if (typeof(TExceptedType).IsEquivalentTo(t.Key.GetType())) + { + countOfTailedFile++; + return new {t.Key, Counter = countOfTailedFile}; + } + return null; + }) + .Where(t => t != null) + .Subscribe(obj => + { + var key = selector(obj.Key); + if ((key.CompareTo(lastKey)) == 1) + { + largestT = obj.Key; + } + + if (obj.Counter == counter) + { + observer.OnNext(largestT); + } + + counter++; + lastKey = key; + + }); + }); + + } + + public static IObservable Sort(this IObservable source, + Func keySelector, + TKey firstKey, + Func nextKeyFunc) + { + return Create(o => + { + var nextKey = firstKey; + var buffer = new Dictionary(); + return source.Subscribe(i => + { + if (keySelector(i).Equals(nextKey)) + { + nextKey = nextKeyFunc(nextKey); + o.OnNext(i); + TSource nextValue; + while (buffer.TryGetValue(nextKey, out nextValue)) + { + buffer.Remove(nextKey); + o.OnNext(nextValue); + nextKey = nextKeyFunc(nextKey); + } + } + else + { + var key = keySelector(i); + if (!buffer.ContainsKey(key)) + { + buffer.Add(key, i); + } + } + }); + }); + } + + public static IObservable OrderedCollectUsingMerge(this IObservable left, + IObservable right, + Func keySelector, + TKey firstKey, + Func nextKeyFunc, + Func resultSelector) + { + Func, IObservable> curriedSort = + events => events.Sort(keySelector, firstKey, nextKeyFunc); + + return curriedSort(left).Zip(curriedSort(right), resultSelector); + } + + public static IObservable OrderedCollectUsingZip(this IObservable left, + IObservable right, + Func keySelector, + TKey firstKey, + Func nextKeyFunc, + Func resultSelector) + { + return left.Sort(keySelector, firstKey, nextKeyFunc).Zip(right.Sort(keySelector, firstKey, nextKeyFunc), + resultSelector); + } public static IDisposable SetAsComplete(this ISubject source) { return Disposable.Create(source.OnCompleted); } - - public static IProperty ForBinding(this IObservable source, PropertyType type = PropertyType.EagerSubscription) + public static IProperty ForBinding(this IObservable source, + PropertyType type = PropertyType.EagerSubscription) { return new HungryProperty(source); } @@ -31,24 +134,12 @@ public static IObservable Previous(this IObservable s return source.PairWithPrevious().Select(pair => pair.Previous); } - - public static IObservable> PairWithPrevious(this IObservable source) + public static IObservable> PairWithPrevious( + this IObservable source) { return source.Scan(Tuple.Create(default(TSource), default(TSource)), (acc, current) => Tuple.Create(acc.Item2, current)) - .Select(pair=>new CurrentAndPrevious(pair.Item1,pair.Item2)); - } - - public class CurrentAndPrevious - { - public T Currrent { get; } - public T Previous { get; } - - public CurrentAndPrevious(T currrent, T previous) - { - Currrent = currrent; - Previous = previous; - } + .Select(pair => new CurrentAndPrevious(pair.Item1, pair.Item2)); } public static IObservable ToUnit(this IObservable source) @@ -70,7 +161,7 @@ public static void Once(this ISubject source) } /// - /// from here http://haacked.com/archive/2012/10/08/writing-a-continueafter-method-for-rx.aspx/ + /// from here http://haacked.com/archive/2012/10/08/writing-a-continueafter-method-for-rx.aspx/ /// /// /// @@ -78,14 +169,14 @@ public static void Once(this ISubject source) /// /// public static IObservable WithContinuation( - this IObservable observable, Func> selector) + this IObservable observable, Func> selector) { return observable.AsCompletion().SelectMany(_ => selector()); } public static IObservable AsCompletion(this IObservable observable) { - return Observable.Create(observer => + return Create(observer => { Action onCompleted = () => { @@ -96,6 +187,16 @@ public static IObservable AsCompletion(this IObservable observable) }); } + public class CurrentAndPrevious + { + public CurrentAndPrevious(T currrent, T previous) + { + Currrent = currrent; + Previous = previous; + } + public T Currrent { get; } + public T Previous { get; } + } } -} +} \ No newline at end of file diff --git a/Source/TailBlazer.Domain/TailBlazer.Domain.csproj b/Source/TailBlazer.Domain/TailBlazer.Domain.csproj index bf73a3de..d5f02aa4 100644 --- a/Source/TailBlazer.Domain/TailBlazer.Domain.csproj +++ b/Source/TailBlazer.Domain/TailBlazer.Domain.csproj @@ -85,6 +85,7 @@ + diff --git a/Source/TailBlazer.Fixtures/FileSegmentFixture.cs b/Source/TailBlazer.Fixtures/FileSegmentFixture.cs index a137a10a..61645ff1 100644 --- a/Source/TailBlazer.Fixtures/FileSegmentFixture.cs +++ b/Source/TailBlazer.Fixtures/FileSegmentFixture.cs @@ -1,7 +1,10 @@ using System; +using System.Collections; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Reactive; +using System.Reactive.Linq; using System.Reactive.Subjects; using FluentAssertions; using TailBlazer.Domain.FileHandling; @@ -12,6 +15,44 @@ namespace TailBlazer.Fixtures { public class FileSegmentFixture { + [Fact] + public void MoreFileSegmentation() + { + TestFileCollection testFileCollection = new TestFileCollection(); + + for (int i = 0; i < 10; i++) + { + testFileCollection.Add(new TestFile()); + testFileCollection[i].Append( + Enumerable.Range(1, 1000).Select(j => $"This is line number {j.ToString("00000000")}").ToArray()); + } + + var refresher = new Subject(); + var segmenter = new FileSegmenter(testFileCollection.Select(t => t.Info.WatchFile(refresher)).Merge(), 1000); + FileSegmentCollection result = null; + + using (var indexer = segmenter.Segments.Subscribe(segment => result = segment)) + { + result.Should().NotBeNull(); + var current = new FileSegmentCollection( result ); + int depthOfLink = 0; + while (current != null) + { + depthOfLink++; + current = current.Link; + } + depthOfLink.Should().Be(10); + result.Segments.Select(fs => fs.Type).Should().Contain(FileSegmentType.Head); + result.Segments.Select(fs => fs.Type).Should().Contain(FileSegmentType.Tail); + + testFileCollection.ForEach(t => t.Delete()); + } + + testFileCollection.ForEach(t => t.Delete()); + + } + + [Fact] public void FileChanged() { diff --git a/Source/TailBlazer.Fixtures/IndexerFixture.cs b/Source/TailBlazer.Fixtures/IndexerFixture.cs index a611d207..55839016 100644 --- a/Source/TailBlazer.Fixtures/IndexerFixture.cs +++ b/Source/TailBlazer.Fixtures/IndexerFixture.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Reactive; +using System.Reactive.Linq; using System.Reactive.Subjects; using FluentAssertions; using Microsoft.Reactive.Testing; @@ -12,6 +13,50 @@ namespace TailBlazer.Fixtures { public class IndexerFixture { + [Fact] + public void CanReadIndiciesBack_MoreSmallFile() + { + var pulse = new Subject(); + var scheduler = new TestScheduler(); + + var testFiles = new TestFileCollection(); + for (int i = 0; i < 10; i++) + { + testFiles.Add(new TestFile()); + testFiles[i].Append(Enumerable.Range(1, 100).Select(j => $"This is line number {j.ToString("00000000")}").ToArray()); + } + + using ( + var indexer = new Indexer(testFiles.Select(t => t.Info.WatchFile(pulse)).Merge().WithSegments(), + scheduler: scheduler)) + { + IndexCollection result = null; + using (indexer.Result.Subscribe(indicies => result = indicies)) + + { + pulse.Once(); + + var head = result.ReadLines(new ScrollRequest(10, 0)); + var headText = head.Select(l => l.Text).ToArray(); + var headExpected = + Enumerable.Range(1, 10).Select(i => $"This is line number {i.ToString("00000000")}"); + headText.ShouldAllBeEquivalentTo(headExpected); + + var tail = result.ReadLines(new ScrollRequest(10)); + var tailText = tail.Select(l => l.Text).ToArray(); + var tailExpected = + Enumerable.Range(91, 10).Select(i => $"This is line number {i.ToString("00000000")}").ToArray(); + tailText.ShouldAllBeEquivalentTo(tailExpected); + + var mid = result.ReadLines(new ScrollRequest(10, 20)); + var midText = mid.Select(l => l.Text).ToArray(); + var midExpected = + Enumerable.Range(21, 10).Select(i => $"This is line number {i.ToString("00000000")}").ToArray(); + midText.ShouldAllBeEquivalentTo(midExpected); + } + } + } + [Fact] public void CanReadIndiciesBack_SmallFile() { @@ -51,7 +96,7 @@ public void CanReadIndiciesBack_SmallFile() [Fact] public void CanReadIndiciesBack_LargeFile() - { + { var pulse = new Subject(); var scheduler = new TestScheduler(); @@ -59,7 +104,7 @@ public void CanReadIndiciesBack_LargeFile() { file.Append(Enumerable.Range(1, 10000).Select(i => $"This is line number {i.ToString("00000000")}").ToArray()); - using (var indexer = new Indexer(file.Info.WatchFile(pulse).WithSegments(), tailSize: 1000,scheduler: scheduler)) + using (var indexer = new Indexer(file.Info.WatchFile(pulse).WithSegments(), tailSize: 1000, scheduler: scheduler)) { IndexCollection result = null; @@ -70,18 +115,18 @@ public void CanReadIndiciesBack_LargeFile() scheduler.AdvanceBy(1); var head = result.ReadLines(new ScrollRequest(10, 0)); - var headText =head.Select(l=>l.Text).ToArray(); - var headExpected =Enumerable.Range(1, 10).Select(i => $"This is line number {i.ToString("00000000")}"); + var headText = head.Select(l => l.Text).ToArray(); + var headExpected = Enumerable.Range(1, 10).Select(i => $"This is line number {i.ToString("00000000")}"); headText.ShouldAllBeEquivalentTo(headExpected); var tail = result.ReadLines(new ScrollRequest(10)); var tailText = tail.Select(l => l.Text).ToArray(); - var tailExpected =Enumerable.Range(9991, 10).Select(i => $"This is line number {i.ToString("00000000")}").ToArray(); + var tailExpected = Enumerable.Range(9991, 10).Select(i => $"This is line number {i.ToString("00000000")}").ToArray(); tailText.ShouldAllBeEquivalentTo(tailExpected); var mid = result.ReadLines(new ScrollRequest(10, 100)); var midText = mid.Select(l => l.Text).ToArray(); - var midExpected =Enumerable.Range(101, 10).Select(i => $"This is line number {i.ToString("00000000")}").ToArray(); + var midExpected = Enumerable.Range(101, 10).Select(i => $"This is line number {i.ToString("00000000")}").ToArray(); midText.ShouldAllBeEquivalentTo(midExpected); } } @@ -103,7 +148,7 @@ public void CanProduceIndices() .Select(i => $"This is line number {i.ToString("00000000")}") .ToArray(); file.Append(lines); - // scheduler.AdvanceBy(1); + // scheduler.AdvanceBy(1); pulse.Once(); IndexCollection result = null; using (indexer.Result.Subscribe(indicies => result = indicies)) diff --git a/Source/TailBlazer.Fixtures/ReorderingEventsTests.cs b/Source/TailBlazer.Fixtures/ReorderingEventsTests.cs new file mode 100644 index 00000000..49fabb8c --- /dev/null +++ b/Source/TailBlazer.Fixtures/ReorderingEventsTests.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Reactive.Testing; +using TailBlazer.Domain.Infrastructure; +using Xunit; + +namespace TailBlazer.Fixtures +{ + public class ReorderingEventsTests : ReactiveTest + { + [Fact] + public void ReorderingTest1() + { + var scheduler = new TestScheduler(); + + var s1 = scheduler.CreateColdObservable( + OnNext(100, 1), + OnNext(200, 2), + OnNext(400, 3), + OnNext(500, 4)); + + var s2 = scheduler.CreateColdObservable( + OnNext(100, 1), + OnNext(200, 3), + OnNext(300, 2), + OnNext(500, 4)); + + var results = scheduler.CreateObserver(); + + s1.OrderedCollectUsingMerge( + right: s2, + keySelector: i => i, + firstKey: 1, + nextKeyFunc: i => i + 1, + resultSelector: (left, right) => left).Subscribe(results); + + scheduler.Start(); + + results.Messages.AssertEqual( + OnNext(100, 1), + OnNext(300, 2), + OnNext(400, 3), + OnNext(500, 4)); + } + + [Fact] + public void ReorderingTest2() + { + var scheduler = new TestScheduler(); + + var s1 = scheduler.CreateColdObservable( + OnNext(100, 1), + OnNext(200, 2), + OnNext(300, 3), + OnNext(400, 4)); + + var s2 = scheduler.CreateColdObservable( + OnNext(100, 4), + OnNext(200, 3), + OnNext(300, 2), + OnNext(400, 1)); + + var results = scheduler.CreateObserver(); + + s1.OrderedCollectUsingZip( + right: s2, + keySelector: i => i, + firstKey: 1, + nextKeyFunc: i => i + 1, + resultSelector: (left, right) => left).Subscribe(results); + + scheduler.Start(); + + results.Messages.AssertEqual( + OnNext(400, 1), + OnNext(400, 2), + OnNext(400, 3), + OnNext(400, 4)); + } + + [Fact] + public void SortTest() + { + var scheduler = new TestScheduler(); + + var s1 = scheduler.CreateColdObservable( + OnNext(55, 1), + OnNext(49, 2), + OnNext(13, 3), + OnNext(77, 4)); + + var results1 = scheduler.CreateObserver(); + + s1.Sort( + keySelector: t => t, + firstKey: 0, + nextKeyFunc: i => i + 1 + ).Subscribe(results1); + + var s2 = scheduler.CreateColdObservable( + OnNext(55, 1), + OnNext(49, 2), + OnNext(13, 3), + OnNext(77, 4)); + + var results2 = scheduler.CreateObserver(); + + s2.Sort( + keySelector: t => t, + firstKey: 0, + nextKeyFunc: i => i + 1 + ).Subscribe(results2); + + scheduler.Start(); + + results1.Messages.AssertEqual(results2.Messages); + } + } +} diff --git a/Source/TailBlazer.Fixtures/TailBlazer.Fixtures.csproj b/Source/TailBlazer.Fixtures/TailBlazer.Fixtures.csproj index 0e3546c6..a04e1096 100644 --- a/Source/TailBlazer.Fixtures/TailBlazer.Fixtures.csproj +++ b/Source/TailBlazer.Fixtures/TailBlazer.Fixtures.csproj @@ -110,12 +110,14 @@ + + diff --git a/Source/TailBlazer.Fixtures/TestFileCollection.cs b/Source/TailBlazer.Fixtures/TestFileCollection.cs new file mode 100644 index 00000000..22fb2f56 --- /dev/null +++ b/Source/TailBlazer.Fixtures/TestFileCollection.cs @@ -0,0 +1,74 @@ +using System.Collections; +using System.Collections.Generic; + +namespace TailBlazer.Fixtures +{ + public class TestFileCollection : IList + { + private readonly List _list; + + public TestFileCollection() + { + _list = new List(); + } + + public IEnumerator GetEnumerator() + { + return _list.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void Add(TestFile item) + { + _list.Add(item); + } + + public void Clear() + { + _list.Clear(); + } + + public bool Contains(TestFile item) + { + return _list.Contains(item); + } + + public void CopyTo(TestFile[] array, int arrayIndex) + { + _list.CopyTo(array, arrayIndex); + } + + public bool Remove(TestFile item) + { + return _list.Remove(item); + } + + public int Count => _list.Count; + public bool IsReadOnly => true; + + public int IndexOf(TestFile item) + { + return _list.IndexOf(item); + } + + public void Insert(int index, TestFile item) + { + _list.Insert(index, item); + } + + public void RemoveAt(int index) + { + _list.RemoveAt(index); + } + + public TestFile this[int index] + { + get { return _list[index]; } + set { _list[index] = value; } + } + } +} \ No newline at end of file diff --git a/Source/TailBlazer/Infrastucture/DebugConverter.cs b/Source/TailBlazer/Infrastucture/DebugConverter.cs new file mode 100644 index 00000000..b8da0992 --- /dev/null +++ b/Source/TailBlazer/Infrastucture/DebugConverter.cs @@ -0,0 +1,26 @@ +using System; +using System.Diagnostics; +using System.Globalization; +using System.Windows.Data; + +namespace TailBlazer.Infrastucture +{ + internal class DebugConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { +#if DEBUG + Debugger.Break(); +#endif + return value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { +#if DEBUG + Debugger.Break(); +#endif + return value; + } + } +} diff --git a/Source/TailBlazer/Infrastucture/FilesHeader.cs b/Source/TailBlazer/Infrastucture/FilesHeader.cs new file mode 100644 index 00000000..036433f2 --- /dev/null +++ b/Source/TailBlazer/Infrastucture/FilesHeader.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DynamicData.Binding; + +namespace TailBlazer.Infrastucture +{ + public class FilesHeader : AbstractNotifyPropertyChanged + { + private string _displayName; + + public string FullName { get; } + + public FilesHeader(IEnumerable info) + { + _displayName = "Tailed files ("+info.Count()+")"; + foreach (var fileInfo in info) + { + FullName += fileInfo.FullName + Environment.NewLine; + } + } + + public string DisplayName + { + get { return _displayName; } + set { SetAndRaise(ref _displayName, value); } + } + } +} diff --git a/Source/TailBlazer/Infrastucture/FilesNameConverter.cs b/Source/TailBlazer/Infrastucture/FilesNameConverter.cs new file mode 100644 index 00000000..eaa7ba55 --- /dev/null +++ b/Source/TailBlazer/Infrastucture/FilesNameConverter.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; + +namespace TailBlazer.Infrastucture +{ + public class FilesNameConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + var s = value as IEnumerable; + if (s == null) + { + throw new ArgumentException(nameof(value)); + } + if (s.Count() == 1) + { + return s.ElementAt(0); + } + return "Tailed files"; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Source/TailBlazer/MainWindow.xaml b/Source/TailBlazer/MainWindow.xaml index b246497e..2f4aff95 100644 --- a/Source/TailBlazer/MainWindow.xaml +++ b/Source/TailBlazer/MainWindow.xaml @@ -51,6 +51,15 @@ + + + + + diff --git a/Source/TailBlazer/TailBlazer.csproj b/Source/TailBlazer/TailBlazer.csproj index e9c5d0ed..9292a1be 100644 --- a/Source/TailBlazer/TailBlazer.csproj +++ b/Source/TailBlazer/TailBlazer.csproj @@ -17,6 +17,21 @@ + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true AnyCPU @@ -140,8 +155,11 @@ + + + @@ -363,7 +381,18 @@ - + + + False + Microsoft .NET Framework 4.5 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + diff --git a/Source/TailBlazer/Views/FileDrop/FileDropMonitor.cs b/Source/TailBlazer/Views/FileDrop/FileDropMonitor.cs index 3a5dd072..0ac5b7d5 100644 --- a/Source/TailBlazer/Views/FileDrop/FileDropMonitor.cs +++ b/Source/TailBlazer/Views/FileDrop/FileDropMonitor.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Reactive.Disposables; @@ -16,7 +17,7 @@ namespace TailBlazer.Views.FileDrop public class FileDropMonitor : IDependencyObjectReceiver, IDisposable { private readonly SerialDisposable _cleanUp = new SerialDisposable(); - private readonly ISubject _fileDropped = new Subject(); + private readonly ISubject> _fileDropped = new Subject>(); public void Receive(DependencyObject value) { @@ -56,7 +57,7 @@ public void Receive(DependencyObject value) var dropped = Observable.FromEventPattern (h => control.Drop += h, h => control.Drop -= h) .Select(ev => ev.EventArgs) - .SelectMany(e => + .Select(e => { if (!e.Data.GetDataPresent(DataFormats.FileDrop)) return Enumerable.Empty(); @@ -78,7 +79,7 @@ public void Receive(DependencyObject value) }); } - public IObservable Dropped => _fileDropped; + public IObservable> Dropped => _fileDropped; /// /// Taken shamelessly from https://github.com/punker76/gong-wpf-dragdrop diff --git a/Source/TailBlazer/Views/Searching/SearchCollection.cs b/Source/TailBlazer/Views/Searching/SearchCollection.cs index 5d8a274b..1cd0878f 100644 --- a/Source/TailBlazer/Views/Searching/SearchCollection.cs +++ b/Source/TailBlazer/Views/Searching/SearchCollection.cs @@ -31,13 +31,13 @@ public SearchCollection(ISearchInfoCollection searchInfoCollection, ISchedulerPr })) .DisposeMany() .AsObservableCache(); - + var shared = viewModels.Connect();//.Publish(); var binderLoader = shared .Sort(SortExpressionComparer - .Ascending(tvm => tvm.SearchType== SearchType.All ? 1:2) - .ThenByAscending(tvm => tvm.Text)) + .Ascending(tvm => tvm.SearchType == SearchType.All ? 1 : 2) + .ThenByAscending(tvm => tvm.Text)) .ObserveOn(schedulerProvider.MainThread) .Bind(out _items) .Subscribe(); diff --git a/Source/TailBlazer/Views/Tail/TailView.xaml b/Source/TailBlazer/Views/Tail/TailView.xaml index 5aeb5c75..bfe7b4f8 100644 --- a/Source/TailBlazer/Views/Tail/TailView.xaml +++ b/Source/TailBlazer/Views/Tail/TailView.xaml @@ -38,10 +38,11 @@ - + + 0 1 @@ -375,7 +376,7 @@ PopupMode="Click" PlacementMode="TopAndAlignLeftEdges"> - + @@ -433,7 +434,7 @@ - + _data; - private readonly ISubject _userScrollRequested = new ReplaySubject(1); private readonly IPersistentStateProvider _stateProvider; - - private bool _autoTail=true; + private readonly ISubject _userScrollRequested = new ReplaySubject(1); + private bool _autoTail = true; private int _firstIndex; private int _pageSize; private LineProxy _selectedLine; private bool _showInline; - public ReadOnlyObservableCollection Lines => _data; - - public Guid Id { get; }= Guid.NewGuid(); - public ICommand CopyToClipboardCommand { get; } - public ICommand OpenFileCommand { get; } - public ICommand OpenFolderCommand { get; } - - public ISelectionMonitor SelectionMonitor { get; } - public SearchOptionsViewModel SearchOptions { get; } - public SearchHints SearchHints { get; } - public SearchCollection SearchCollection { get; } - public InlineViewer InlineViewer { get; } - public IProperty Count { get; } - public IProperty CountText { get; } - public IProperty LatestCount { get; } - public IProperty FileSizeText { get; } - public IProperty FileStatus { get; } - public IProperty InlineViewerVisible { get; } - public IProperty CanViewInline { get; } - public IProperty HighlightTail { get; } - public IProperty UsingDarkTheme { get; } - public IProperty HighlightDuration { get; } - - public ICommand OpenSearchOptionsCommand => new Command(OpenSearchOptions); - - public string Name { get; } - public TailViewModel([NotNull] ILogger logger, [NotNull] ISchedulerProvider schedulerProvider, - [NotNull] IFileWatcher fileWatcher, - [NotNull] ISelectionMonitor selectionMonitor, - [NotNull] IClipboardHandler clipboardHandler, - [NotNull] ISearchInfoCollection searchInfoCollection, - [NotNull] IInlineViewerFactory inlineViewerFactory, + [NotNull] IEnumerable fileWatcher, + [NotNull] ISelectionMonitor selectionMonitor, + [NotNull] IClipboardHandler clipboardHandler, + [NotNull] ISearchInfoCollection searchInfoCollection, + [NotNull] IInlineViewerFactory inlineViewerFactory, [NotNull] ISetting generalOptions, [NotNull] ISearchMetadataCollection searchMetadataCollection, [NotNull] SearchOptionsViewModel searchOptionsViewModel, @@ -90,20 +63,22 @@ public TailViewModel([NotNull] ILogger logger, _stateProvider = new TailViewPersister(this); - Name = fileWatcher.FullName; + var enumerable = fileWatcher as IFileWatcher[] ?? fileWatcher.ToArray(); + Names = enumerable.Select(t => t.FullName); SelectionMonitor = selectionMonitor; SearchOptions = searchOptionsViewModel; SearchHints = searchHints; SearchCollection = new SearchCollection(searchInfoCollection, schedulerProvider); - CopyToClipboardCommand = new Command(() => clipboardHandler.WriteToClipboard(selectionMonitor.GetSelectedText())); - OpenFileCommand = new Command(() => Process.Start(fileWatcher.FullName)); - OpenFolderCommand = new Command(() => Process.Start(fileWatcher.Folder)); - + CopyToClipboardCommand = + new Command(() => clipboardHandler.WriteToClipboard(selectionMonitor.GetSelectedText())); + OpenFileCommand = new Command(() => Process.Start(enumerable[0].FullName)); + OpenFolderCommand = new Command(() => Process.Start(enumerable[0].Folder)); + UsingDarkTheme = generalOptions.Value - .ObserveOn(schedulerProvider.MainThread) - .Select(options => options.Theme== Theme.Dark) - .ForBinding(); + .ObserveOn(schedulerProvider.MainThread) + .Select(options => options.Theme == Theme.Dark) + .ForBinding(); HighlightTail = generalOptions.Value .ObserveOn(schedulerProvider.MainThread) @@ -118,48 +93,67 @@ public TailViewModel([NotNull] ILogger logger, //An observable which acts as a scroll command var autoChanged = this.WhenValueChanged(vm => vm.AutoTail); var scroller = _userScrollRequested.CombineLatest(autoChanged, (user, auto) => - { - var mode = AutoTail ? ScrollReason.Tail : ScrollReason.User; - return new ScrollRequest(mode, user.PageSize, user.FirstIndex); - }) - .Do(x=>logger.Info("Scrolling to {0}/{1}", x.FirstIndex,x.PageSize)) - .DistinctUntilChanged(); - - FileStatus = fileWatcher.Status.ForBinding(); + { + var mode = AutoTail ? ScrollReason.Tail : ScrollReason.User; + return new ScrollRequest(mode, user.PageSize, user.FirstIndex); + }) + .Do(x => logger.Info("Scrolling to {0}/{1}", x.FirstIndex, x.PageSize)) + .DistinctUntilChanged(); + + FileStatus = enumerable + .Select(t => t.Status) + .Merge() + .Scan(default(FileStatus), (status, fileStatus) => status | fileStatus) + .ForBinding(); //command to add the current search to the tail collection - var searchInvoker = SearchHints.SearchRequested.Subscribe(request => - { - searchInfoCollection.Add(request.Text, request.UseRegEx); - }); + var searchInvoker = + SearchHints.SearchRequested.Subscribe( + request => { searchInfoCollection.Add(request.Text, request.UseRegEx); }); //User feedback to show file size - FileSizeText = fileWatcher.Latest.Select(fn=>fn.Size) - .Select(size => size.FormatWithAbbreviation()) + FileSizeText = enumerable + .Select(t => t.Latest) + .Merge() + .Select(t => t.Size) + .Scan(0f, (previousSize, currentSize) => previousSize + currentSize/2f) + .Select(t => ((long)t).FormatWithAbbreviation()) .DistinctUntilChanged() .ForBinding(); + //tailer is the main object used to tail, scroll and filter in a file - var lineScroller = new LineScroller(SearchCollection.Latest.ObserveOn(schedulerProvider.Background), scroller); + var lineScroller = new LineScroller(SearchCollection.Latest.ObserveOn(schedulerProvider.Background), + scroller); //load lines into observable collection - var lineProxyFactory = new LineProxyFactory(new TextFormatter(searchMetadataCollection),new LineMatches(searchMetadataCollection)); + var lineProxyFactory = new LineProxyFactory(new TextFormatter(searchMetadataCollection), + new LineMatches(searchMetadataCollection)); + var loader = lineScroller.Lines.Connect() - .RecordChanges(logger, "Received") .Transform(lineProxyFactory.Create, new ParallelisationOptions(ParallelType.Ordered, 3)) .Sort(SortExpressionComparer.Ascending(proxy => proxy)) .ObserveOn(schedulerProvider.MainThread) - .Bind(out _data,100) + .Bind(out _data, 100) .DisposeMany() .LogErrors(logger) .Subscribe(); //monitor matching lines and start index, - Count = searchInfoCollection.All.Select(latest=>latest.Count).ForBinding(); - CountText = searchInfoCollection.All.Select(latest => $"{latest.Count.ToString("##,###")} lines").ForBinding(); - LatestCount = SearchCollection.Latest.Select(latest => latest.Count).ForBinding(); + Count = searchInfoCollection.All + .GroupBy(t => t) + .Scan(0, (i, provider) => i + provider.Key.Count) + .ForBinding(); + CountText = searchInfoCollection.All + .GroupBy(t => t) + .Scan(0L, (i, provider) => i + provider.Key.Count) + .Select(latestCount => $"{latestCount.ToString("##,###")} lines").ForBinding(); + LatestCount = SearchCollection.Latest + .GroupBy(t => t) + .Scan(0, (i, provider) => i + provider.Key.Count) + .ForBinding(); ////track first visible index var firstIndexMonitor = lineScroller.Lines.Connect() @@ -167,35 +161,35 @@ public TailViewModel([NotNull] ILogger logger, .ToCollection() .Select(lines => lines.Count == 0 ? 0 : lines.Select(l => l.Index).Max() - lines.Count + 1) .ObserveOn(schedulerProvider.MainThread) - .Subscribe(first => - { - FirstIndex = first; - }); + .Subscribe(first => { FirstIndex = first; }); //Create objects required for inline viewing var isUserDefinedChanged = SearchCollection.WhenValueChanged(sc => sc.Selected) - .Where(selected=> selected!=null) + .Where(selected => selected != null) .Select(selected => selected.IsUserDefined) .DistinctUntilChanged() .Replay(1) .RefCount(); - + var inlineViewerVisible = isUserDefinedChanged.CombineLatest(this.WhenValueChanged(vm => vm.ShowInline), - (userDefined, showInline) => userDefined && showInline); - + (userDefined, showInline) => userDefined && showInline); + CanViewInline = isUserDefinedChanged.ForBinding(); InlineViewerVisible = inlineViewerVisible.ForBinding(); //return an empty line provider unless user is viewing inline - this saves needless trips to the file - var inline = searchInfoCollection.All.CombineLatest(inlineViewerVisible, (index, ud) => ud ? index : new EmptyLineProvider()); + + var inline = searchInfoCollection.All.CombineLatest(inlineViewerVisible, + (index, ud) => ud ? index : new EmptyLineProvider()); var firstVisibleRow = _data.ToObservableChangeSet().ToCollection() - .Select(collection => collection.FirstOrDefault()); + .Select(collection => collection.FirstOrDefault()); //var itemToSelect = this.WhenValueChanged(vm => vm.SelectedItem) // .CombineLatest(firstVisibleRow, (selected, first) => selected ?? first); //// - InlineViewer = inlineViewerFactory.Create(inline, this.WhenValueChanged(vm => vm.SelectedItem), lineProxyFactory); + InlineViewer = inlineViewerFactory.Create(inline, this.WhenValueChanged(vm => vm.SelectedItem), + lineProxyFactory); _cleanUp = new CompositeDisposable(lineScroller, loader, @@ -219,13 +213,26 @@ public TailViewModel([NotNull] ILogger logger, searchInvoker, _userScrollRequested.SetAsComplete()); } - - private async void OpenSearchOptions() - { - await DialogHost.Show(SearchOptions, Id); - } - + public Guid Id { get; } = Guid.NewGuid(); + public ICommand OpenFileCommand { get; } + public ICommand OpenFolderCommand { get; } + public SearchOptionsViewModel SearchOptions { get; } + public SearchHints SearchHints { get; } + public SearchCollection SearchCollection { get; } + public InlineViewer InlineViewer { get; } + public IProperty CountText { get; } + public IProperty LatestCount { get; } + public IProperty FileSizeText { get; private set; } + public IProperty FileStatus { get; private set; } + public IProperty InlineViewerVisible { get; } + public IProperty CanViewInline { get; } + public IProperty HighlightTail { get; } + public IProperty UsingDarkTheme { get; } + public IProperty HighlightDuration { get; } + public ICommand OpenSearchOptionsCommand => new Command(OpenSearchOptions); + public IEnumerable Names { get; } + public LineProxy SelectedItem { get { return _selectedLine; } @@ -237,7 +244,18 @@ public bool AutoTail get { return _autoTail; } set { SetAndRaise(ref _autoTail, value); } } - + + public bool ShowInline + { + get { return _showInline; } + set { SetAndRaise(ref _showInline, value); } + } + + public ReadOnlyObservableCollection Lines => _data; + public ICommand CopyToClipboardCommand { get; } + public ISelectionMonitor SelectionMonitor { get; } + public IProperty Count { get; } + public int PageSize { get { return _pageSize; } @@ -250,14 +268,17 @@ public int FirstIndex set { SetAndRaise(ref _firstIndex, value); } } - public bool ShowInline + public void Dispose() { - get { return _showInline; } - set { SetAndRaise(ref _showInline, value); } + _cleanUp.Dispose(); } - #region Interact with scroll panel + private async void OpenSearchOptions() + { + await DialogHost.Show(SearchOptions, Id); + } + #region Interact with scroll panel void IScrollReceiver.ScrollBoundsChanged(ScrollBoundsArgs boundsArgs) { @@ -273,7 +294,6 @@ I need to get rid of this subject as I prefer functional over imperative. each time I have tried to remove it all hell has broken loose */ _userScrollRequested.OnNext(new ScrollRequest(mode, boundsArgs.PageSize, boundsArgs.FirstIndex)); - } void IScrollReceiver.ScrollChanged(ScrollChangedArgs scrollChangedArgs) @@ -301,11 +321,5 @@ void IPersistentStateProvider.Restore(State state) } #endregion - - - public void Dispose() - { - _cleanUp.Dispose(); - } } -} +} \ No newline at end of file diff --git a/Source/TailBlazer/Views/Tail/TailViewModelFactory.cs b/Source/TailBlazer/Views/Tail/TailViewModelFactory.cs index 6bad97ad..4538c4e5 100644 --- a/Source/TailBlazer/Views/Tail/TailViewModelFactory.cs +++ b/Source/TailBlazer/Views/Tail/TailViewModelFactory.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.IO; +using System.Linq; using TailBlazer.Domain.FileHandling; using TailBlazer.Domain.FileHandling.Search; using TailBlazer.Domain.Formatting; @@ -11,13 +13,13 @@ namespace TailBlazer.Views.Tail { public class TailViewModelFactory { + private readonly IColourProvider _colourProvider; + private readonly IIconProvider _iconProvider; private readonly IObjectProvider _objectProvider; private readonly ISchedulerProvider _schedulerProvider; - private readonly IColourProvider _colourProvider; private readonly ISearchMetadataFactory _searchMetadataFactory; - private readonly IIconProvider _iconProvider; - public TailViewModelFactory(IObjectProvider objectProvider, + public TailViewModelFactory(IObjectProvider objectProvider, ISchedulerProvider schedulerProvider, IColourProvider colourProvider, ISearchMetadataFactory searchMetadataFactory, @@ -30,6 +32,40 @@ public TailViewModelFactory(IObjectProvider objectProvider, _iconProvider = iconProvider; } + public TailViewModel Create(IEnumerable filesInfo) + { + if (filesInfo == null) throw new ArgumentNullException(nameof(filesInfo)); + if (!filesInfo.Any()) throw new ArgumentException(nameof(filesInfo)); + + var filesWatcher = _objectProvider.Get(new[] + { + new ExplictArg("files", filesInfo), + new ExplictArg("scheduler", _schedulerProvider.Background) + }); + + var searchMetadataCollection = _objectProvider.Get(); + var searchHints = _objectProvider.Get(); + var searchOptionsViewModel = new SearchOptionsViewModel(searchMetadataCollection, _searchMetadataFactory, + _schedulerProvider, _colourProvider, _iconProvider, searchHints); + + var searchInfo = _objectProvider.Get + ( + new[] + { + new ExplictArg("filesWatcher", filesWatcher.List), + new ExplictArg("searchMetadataCollection", searchMetadataCollection) + } + ); + + return _objectProvider.Get(new[] + { + new ExplictArg("fileWatcher", filesWatcher), + new ExplictArg("searchInfoCollection", searchInfo), + new ExplictArg("searchMetadataCollection", searchMetadataCollection), + new ExplictArg("searchOptionsViewModel", searchOptionsViewModel) + }); + } + public TailViewModel Create(FileInfo fileInfo) { if (fileInfo == null) throw new ArgumentNullException(nameof(fileInfo)); @@ -37,28 +73,29 @@ public TailViewModel Create(FileInfo fileInfo) var fileWatcher = _objectProvider.Get(new[] { new ExplictArg("fileInfo", fileInfo), - new ExplictArg("scheduler",_schedulerProvider.Background) + new ExplictArg("scheduler", _schedulerProvider.Background) }); var searchMetadataCollection = _objectProvider.Get(); var searchHints = _objectProvider.Get(); - var searchOptionsViewModel = new SearchOptionsViewModel(searchMetadataCollection, _searchMetadataFactory, _schedulerProvider, _colourProvider, _iconProvider, searchHints); - + var searchOptionsViewModel = new SearchOptionsViewModel(searchMetadataCollection, _searchMetadataFactory, + _schedulerProvider, _colourProvider, _iconProvider, searchHints); + var searchInfo = _objectProvider.Get ( new[] { - new ExplictArg("fileWatcher", fileWatcher), + new ExplictArg("filesWatcher", new[] {fileWatcher}), new ExplictArg("searchMetadataCollection", searchMetadataCollection) } ); - + //I hate explicity specify named args - so fragile but hey ho. return _objectProvider.Get(new[] { - new ExplictArg("fileWatcher", fileWatcher), + new ExplictArg("fileWatcher", new [] { fileWatcher }), new ExplictArg("searchInfoCollection", searchInfo), new ExplictArg("searchMetadataCollection", searchMetadataCollection), new ExplictArg("searchOptionsViewModel", searchOptionsViewModel) diff --git a/Source/TailBlazer/Views/Tail/TailViewPersister.cs b/Source/TailBlazer/Views/Tail/TailViewPersister.cs index c9a46773..90201253 100644 --- a/Source/TailBlazer/Views/Tail/TailViewPersister.cs +++ b/Source/TailBlazer/Views/Tail/TailViewPersister.cs @@ -29,7 +29,7 @@ public State CaptureState() search.IgnoreCase )); - var tailViewState = new TailViewState(_tailView.Name,_tailView.SearchCollection.Selected.Text, searchItems); + var tailViewState = new TailViewState(_tailView.Names,_tailView.SearchCollection.Selected.Text, searchItems); var converter = new TailViewToStateConverter(); return converter.Convert(tailViewState); } @@ -107,7 +107,10 @@ public State Convert(TailViewState state) return State.Empty; var root = new XElement(new XElement(Structure.Root)); - root.Add(new XElement(Structure.FileName, state.FileName)); + foreach (var fileName in state.FilesName) + { + root.Add(new XElement(Structure.FileName, fileName)); + } root.Add(new XElement(Structure.SelectedFilter, state.SelectedSearch)); var list = new XElement(Structure.SearchList); diff --git a/Source/TailBlazer/Views/Tail/TailViewState.cs b/Source/TailBlazer/Views/Tail/TailViewState.cs index 94cba94b..80dd8e64 100644 --- a/Source/TailBlazer/Views/Tail/TailViewState.cs +++ b/Source/TailBlazer/Views/Tail/TailViewState.cs @@ -6,14 +6,14 @@ public sealed class TailViewState { public static readonly TailViewState Empty = new TailViewState(); - public string FileName { get; } + public IEnumerable FilesName { get; } public string SelectedSearch { get; } public IEnumerable SearchItems { get; } - public TailViewState(string fileName, string selectedSearch, IEnumerable searchItems) + public TailViewState(IEnumerable filesName, string selectedSearch, IEnumerable searchItems) { - FileName = fileName; + FilesName = filesName; SelectedSearch = selectedSearch; SearchItems = searchItems; } diff --git a/Source/TailBlazer/Views/WindowManagement/WindowViewModel.cs b/Source/TailBlazer/Views/WindowManagement/WindowViewModel.cs index fdb0091a..3b3c7b61 100644 --- a/Source/TailBlazer/Views/WindowManagement/WindowViewModel.cs +++ b/Source/TailBlazer/Views/WindowManagement/WindowViewModel.cs @@ -49,6 +49,8 @@ public class WindowViewModel: AbstractNotifyPropertyChanged, IDisposable public FileDropMonitor DropMonitor { get; } = new FileDropMonitor(); + public static int OpenedFileCount { get; set; } + public WindowViewModel(IObjectProvider objectProvider, IWindowFactory windowFactory, ILogger logger, @@ -127,6 +129,52 @@ public void OpenFiles(IEnumerable files=null) OpenFile(new FileInfo(file)); } + private void OpenFile(IEnumerable files) + { + OpenedFileCount = files.Count(); + if (OpenedFileCount > 1) + { + var msgResult = MessageBox.Show("Would you like to tail these files?", "Tail files", + MessageBoxButton.YesNo); + if (msgResult == MessageBoxResult.Yes) + { + _schedulerProvider.Background.Schedule(() => + { + try + { + _logger.Info($"Attempting to open '{files.Count()}' files"); + + var factory = _objectProvider.Get(); + var viewModel = factory.Create(files); + + var newItem = new ViewContainer(new FilesHeader(files), viewModel); + + _windowsController.Register(newItem); + + //_logger.Info($"Objects for '{file.FullName}' has been created."); + //do the work on the ui thread + _schedulerProvider.MainThread.Schedule(() => + { + + Views.Add(newItem); + _logger.Info($"Opened '{files.Count()}' files"); + Selected = newItem; + }); + } + catch + { + // ignored + } + }); + return; + } + } + foreach (var fileInfo in files) + { + OpenFile(fileInfo); + } + } + private void OpenFile(FileInfo file) { _schedulerProvider.Background.Schedule(() => diff --git a/Source/TailBlazer/packages.config b/Source/TailBlazer/packages.config index 03676ea3..5fc525df 100644 --- a/Source/TailBlazer/packages.config +++ b/Source/TailBlazer/packages.config @@ -57,4 +57,12 @@ + + + + + + + + \ No newline at end of file From 284ecec8ef3dbfb67133a3a9d4d7c3a0822d3cd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Set=C3=A9nyi?= Date: Sun, 3 Apr 2016 16:59:58 +0200 Subject: [PATCH 03/11] Added some unit test --- Source/TailBlazer.Fixtures/MyUnitTest.cs | 123 ++++++++++++++++++ .../TailBlazer.Fixtures/SettingsConversion.cs | 2 +- .../TailBlazer.Fixtures.csproj | 1 + 3 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 Source/TailBlazer.Fixtures/MyUnitTest.cs diff --git a/Source/TailBlazer.Fixtures/MyUnitTest.cs b/Source/TailBlazer.Fixtures/MyUnitTest.cs new file mode 100644 index 00000000..040b1d46 --- /dev/null +++ b/Source/TailBlazer.Fixtures/MyUnitTest.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using FluentAssertions; +using TailBlazer.Domain.FileHandling; +using Xunit; +using System.Reactive; +using System.Reactive.Subjects; +using System.IO; +using System.Diagnostics; +using TailBlazer.Domain.Infrastructure; + +namespace TailBlazer.Fixtures +{ + public class MyUnitTest + { + [Fact] + public void ScrollRequest_Test() + { + ScrollRequest sreq = new ScrollRequest(ScrollReason.Tail, 10, 100); + sreq.Mode.ShouldBeEquivalentTo(ScrollReason.Tail); + } + + [Fact] + public void GetHashCode_Test() + { + ScrollRequest sreq = new ScrollRequest(ScrollReason.Tail, 10, 100); + ScrollRequest sreq2 = new ScrollRequest(ScrollReason.User, 10, 100); + sreq.GetHashCode().Should().NotBe(sreq2.GetHashCode()); + } + + [Fact] + public void GetEncoding_Test() + { + var file = new TestFile(); + Encoding original = null; + Encoding encode = file.Info.GetEncoding(); + + using (var stream = File.Open(file.Info.FullName, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite)) + { + using (var reader = new StreamReaderExtended(stream, true)) + { + var something = reader.Peek(); + original = reader.CurrentEncoding; + } + } + + encode.Should().Be(original); + } + + [Fact] + public void GetFileLength_Test() + { + var file = new TestFile(); + long length = file.Info.GetFileLength(); + long original = 0; + + using (var stream = File.Open(file.Info.FullName, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite)) + { + original = stream.Length; + } + } + + [Fact] + public void FileSegment_Test() + { + var fs = new FileSegment(1, 2, 10, FileSegmentType.Tail); + var fs2 = new FileSegment(fs, 15); + + fs2.Index.ShouldBeEquivalentTo(fs.Index); + fs2.Start.ShouldBeEquivalentTo(fs.Start); + fs2.End.ShouldBeEquivalentTo(15); + fs2.Type.ShouldBeEquivalentTo(fs.Type); + fs2.Key.Should().Be(fs.Key); + fs2.Size.Should().Be(13); + } + + [Fact] + public void TailInfo_Test() + { + var tailinfo = new TailInfo(1000000); + tailinfo.LastTail.ToShortDateString().Should().Be(DateTime.Now.ToShortDateString()); + } + + [Fact] + public void ParseInt_Test() + { + String text = "1516"; + int number = (int)text.ParseInt(); + String newtext = number.ToString(); + text.Should().Be(newtext); + } + + [Fact] + public void ParseBool_Test() + { + String text = "True"; + bool truth = (bool)text.ParseBool(); + String newtext = truth.ToString(); + text.Should().Be(newtext); + } + + [Fact] + public void PrseDeciaml_Test() + { + String text = "10"; + decimal deci = (decimal)text.ParseDecimal(); + String newtext = deci.ToString(); + text.Should().Be(newtext); + } + + [Fact] + public void ParseDouble_Test() + { + String text = "10865902"; + double num = (double)text.ParseDouble(); + String newtext = num.ToString(); + text.Should().Be(newtext); + } + } +} diff --git a/Source/TailBlazer.Fixtures/SettingsConversion.cs b/Source/TailBlazer.Fixtures/SettingsConversion.cs index 71f37230..cfd5371d 100644 --- a/Source/TailBlazer.Fixtures/SettingsConversion.cs +++ b/Source/TailBlazer.Fixtures/SettingsConversion.cs @@ -28,7 +28,7 @@ public void RecentFiles() public void GeneralOptions() { - var original = new GeneralOptions(Theme.Dark, false,0.5,125); + var original = new GeneralOptions(Theme.Dark, false,5,125); var converter = new GeneralOptionsConverter(); var state = converter.Convert(original); var restored = converter.Convert(state); diff --git a/Source/TailBlazer.Fixtures/TailBlazer.Fixtures.csproj b/Source/TailBlazer.Fixtures/TailBlazer.Fixtures.csproj index 0e3546c6..9414e022 100644 --- a/Source/TailBlazer.Fixtures/TailBlazer.Fixtures.csproj +++ b/Source/TailBlazer.Fixtures/TailBlazer.Fixtures.csproj @@ -109,6 +109,7 @@ + From f6786a0ca32f68f874d220cc27a438aa38865d66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Set=C3=A9nyi?= Date: Wed, 13 Apr 2016 16:35:48 +0200 Subject: [PATCH 04/11] New dialog window added + pinning feature implementation in progress --- Source/TailBlazer/App.xaml | 5 ++ Source/TailBlazer/Infrastucture/FileHeader.cs | 6 ++ Source/TailBlazer/MainWindow.xaml | 52 +++++++++++++- Source/TailBlazer/MainWindow.xaml.cs | 17 +++++ Source/TailBlazer/TailBlazer.csproj | 9 +++ .../TailBlazer/Views/Dialog/DialogView.xaml | 60 ++++++++++++++++ .../Views/Dialog/DialogView.xaml.cs | 28 ++++++++ .../Views/Dialog/DialogViewModel.cs | 47 ++++++++++++ .../Views/WindowManagement/WindowViewModel.cs | 72 +++++++++++++++++-- 9 files changed, 289 insertions(+), 7 deletions(-) create mode 100644 Source/TailBlazer/Views/Dialog/DialogView.xaml create mode 100644 Source/TailBlazer/Views/Dialog/DialogView.xaml.cs create mode 100644 Source/TailBlazer/Views/Dialog/DialogViewModel.cs diff --git a/Source/TailBlazer/App.xaml b/Source/TailBlazer/App.xaml index b48457a1..3ad5d60b 100644 --- a/Source/TailBlazer/App.xaml +++ b/Source/TailBlazer/App.xaml @@ -5,6 +5,7 @@ xmlns:fileDrop="clr-namespace:TailBlazer.Views.FileDrop" xmlns:tail="clr-namespace:TailBlazer.Views.Tail" xmlns:searching="clr-namespace:TailBlazer.Views.Searching" + xmlns:dialog="clr-namespace:TailBlazer.Views.Dialog" xmlns:settings="clr-namespace:TailBlazer.Settings"> @@ -17,6 +18,10 @@ + + + + diff --git a/Source/TailBlazer/Infrastucture/FileHeader.cs b/Source/TailBlazer/Infrastucture/FileHeader.cs index 0a4677c9..5c283a65 100644 --- a/Source/TailBlazer/Infrastucture/FileHeader.cs +++ b/Source/TailBlazer/Infrastucture/FileHeader.cs @@ -7,6 +7,12 @@ public class FileHeader: AbstractNotifyPropertyChanged { private readonly FileInfo _info; private string _displayName; + private bool _isPinned = false; + + public bool IsPinned { + get { return _isPinned; } + set { SetAndRaise(ref _isPinned, value); } + } public string FullName => _info.FullName; diff --git a/Source/TailBlazer/MainWindow.xaml b/Source/TailBlazer/MainWindow.xaml index 2f4aff95..d52e7c25 100644 --- a/Source/TailBlazer/MainWindow.xaml +++ b/Source/TailBlazer/MainWindow.xaml @@ -13,6 +13,7 @@ xmlns:recent="clr-namespace:TailBlazer.Views.Recent" xmlns:options="clr-namespace:TailBlazer.Views.Options" xmlns:windowManagement="clr-namespace:TailBlazer.Views.WindowManagement" + xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" mc:Ignorable="d" TextElement.Foreground="{DynamicResource MaterialDesignBody}" Background="{DynamicResource MaterialDesignPaper}" @@ -43,13 +44,60 @@ - + + + + + + + + - + + + + + + + DialogView.xaml + + @@ -288,6 +292,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -393,6 +401,7 @@ false + diff --git a/Source/TailBlazer/Views/Dialog/DialogView.xaml b/Source/TailBlazer/Views/Dialog/DialogView.xaml new file mode 100644 index 00000000..411ff769 --- /dev/null +++ b/Source/TailBlazer/Views/Dialog/DialogView.xaml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + diff --git a/Source/TailBlazer/Views/Dialog/DialogView.xaml.cs b/Source/TailBlazer/Views/Dialog/DialogView.xaml.cs new file mode 100644 index 00000000..5469750f --- /dev/null +++ b/Source/TailBlazer/Views/Dialog/DialogView.xaml.cs @@ -0,0 +1,28 @@ +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; + +namespace TailBlazer.Views.Dialog +{ + /// + /// Interaction logic for DialogView.xaml + /// + public partial class DialogView + { + public DialogView() + { + InitializeComponent(); + } + } +} diff --git a/Source/TailBlazer/Views/Dialog/DialogViewModel.cs b/Source/TailBlazer/Views/Dialog/DialogViewModel.cs new file mode 100644 index 00000000..d09ca305 --- /dev/null +++ b/Source/TailBlazer/Views/Dialog/DialogViewModel.cs @@ -0,0 +1,47 @@ +using DynamicData.Binding; +using Microsoft.Expression.Interactivity.Core; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace TailBlazer.Views.Dialog +{ + //This class is responsible for displaying custom dialog windows + public class DialogViewModel : AbstractNotifyPropertyChanged, IDisposable + { + //The text of the dialog window + public String text { get; set; } + public ICommand ButtonClickEvent { get; set; } + public bool Button { get; set; } + + public DialogViewModel() + { + //This can be triggered from the DialogView.xaml + ButtonClickEvent = new ActionCommand(o => + { + var content = o as string; + + //Here we can test the content of the pushed button + if (!string.IsNullOrEmpty(content)) + { + if (content == "Yes") + { + Button = true; + } + else if (content == "No") + { + Button = false; + } + } + }); + } + + public void Dispose() + { + throw new NotImplementedException(); + } + } +} diff --git a/Source/TailBlazer/Views/WindowManagement/WindowViewModel.cs b/Source/TailBlazer/Views/WindowManagement/WindowViewModel.cs index 3b3c7b61..3fa2940f 100644 --- a/Source/TailBlazer/Views/WindowManagement/WindowViewModel.cs +++ b/Source/TailBlazer/Views/WindowManagement/WindowViewModel.cs @@ -22,6 +22,9 @@ using TailBlazer.Views.Options; using TailBlazer.Views.Recent; using TailBlazer.Views.Tail; +using TailBlazer.Views.Dialog; +using MaterialDesignThemes.Wpf; +using Microsoft.Expression.Interactivity.Core; namespace TailBlazer.Views.WindowManagement { @@ -35,6 +38,7 @@ public class WindowViewModel: AbstractNotifyPropertyChanged, IDisposable private ViewContainer _selected; private bool _isEmpty; private bool _menuIsOpen; + public ICommand Pinning { get; set; } public ObservableCollection Views { get; } = new ObservableCollection(); public RecentFilesViewModel RecentFiles { get; } public GeneralOptionsViewModel GeneralOptions { get; } @@ -51,25 +55,36 @@ public class WindowViewModel: AbstractNotifyPropertyChanged, IDisposable public static int OpenedFileCount { get; set; } + public DialogViewModel Dialog { get; set; } + public WindowViewModel(IObjectProvider objectProvider, IWindowFactory windowFactory, ILogger logger, IWindowsController windowsController, RecentFilesViewModel recentFilesViewModel, GeneralOptionsViewModel generalOptionsViewModel, - ISchedulerProvider schedulerProvider) + ISchedulerProvider schedulerProvider, + DialogViewModel dialogviewmodel) { + Pinning = new ActionCommand(o => + { + var content = o as string; + + }); _logger = logger; _windowsController = windowsController; RecentFiles = recentFilesViewModel; GeneralOptions = generalOptionsViewModel; + Dialog = dialogviewmodel; _schedulerProvider = schedulerProvider; _objectProvider = objectProvider; InterTabClient = new InterTabClient(windowFactory); OpenFileCommand = new Command(OpenFile); ShowInGitHubCommand = new Command(()=> Process.Start("https://github.com/RolandPheasant")); - ZoomOutCommand= new Command(()=> { GeneralOptions.Scale = GeneralOptions.Scale + 5; }); + Views.CollectionChanged += Views_CollectionChanged; + + ZoomOutCommand = new Command(()=> { GeneralOptions.Scale = GeneralOptions.Scale + 5; }); ZoomInCommand = new Command(() => { GeneralOptions.Scale = GeneralOptions.Scale - 5; }); SaveLayoutCommand = new Command(WalkTheLayout); ExitCommmand = new Command(() => Application.Current.Shutdown()); @@ -104,6 +119,7 @@ public WindowViewModel(IObjectProvider objectProvider, })); } + private void WalkTheLayout() { var analyser = new LayoutAnalyser(); @@ -129,12 +145,52 @@ public void OpenFiles(IEnumerable files=null) OpenFile(new FileInfo(file)); } - private void OpenFile(IEnumerable files) + private async void OpenFile(IEnumerable files) { OpenedFileCount = files.Count(); if (OpenedFileCount > 1) { - var msgResult = MessageBox.Show("Would you like to tail these files?", "Tail files", + //Here we can set the dialog window's message + Dialog.text = "Would you like to tail these files?"; + //Showing the dialog window + var msgResult = await DialogHost.Show(Dialog, DialogNames.EntireWindow); + //Testing the pushed button + if (Dialog.Button) + { + //Tailing multiple files + _schedulerProvider.Background.Schedule(() => + { + try + { + _logger.Info($"Attempting to open '{files.Count()}' files"); + + var factory = _objectProvider.Get(); + var viewModel = factory.Create(files); + + var newItem = new ViewContainer(new FilesHeader(files), viewModel); + + _windowsController.Register(newItem); + + //_logger.Info($"Objects for '{file.FullName}' has been created."); + //do the work on the ui thread + _schedulerProvider.MainThread.Schedule(() => + { + + Views.Add(newItem); + _logger.Info($"Opened '{files.Count()}' files"); + Selected = newItem; + }); + } + catch + { + // ignored + } + + }); + return; + } + //The OLD method + /*MessageBox.Show("Would you like to tail these files?", "Tail files", MessageBoxButton.YesNo); if (msgResult == MessageBoxResult.Yes) { @@ -167,14 +223,20 @@ private void OpenFile(IEnumerable files) } }); return; - } + }*/ } + //Simple file opening foreach (var fileInfo in files) { OpenFile(fileInfo); } } + private void Views_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + //throw new NotImplementedException(); + } + private void OpenFile(FileInfo file) { _schedulerProvider.Background.Schedule(() => From 6bb24ca9ba36d4c48d2225a892abef8c3990d06d Mon Sep 17 00:00:00 2001 From: miskotam Date: Thu, 14 Apr 2016 20:17:11 +0200 Subject: [PATCH 05/11] MaterialDesigned FileOpen has been implemented --- Source/TailBlazer.Fixtures/FileOpenFixture.cs | 173 ++++++++++++++++ Source/TailBlazer.Fixtures/IndexerFixture.cs | 2 +- .../TailBlazer.Fixtures.csproj | 2 + Source/TailBlazer.Fixtures/TestDirectory.cs | 53 +++++ Source/TailBlazer.Fixtures/TestFile.cs | 52 ++++- Source/TailBlazer/App.xaml | 8 +- Source/TailBlazer/MainWindow.xaml | 2 +- Source/TailBlazer/Resources/diskdrive.png | Bin 0 -> 27174 bytes Source/TailBlazer/Resources/folder.png | Bin 0 -> 28431 bytes Source/TailBlazer/TailBlazer.csproj | 16 ++ .../Views/FileOpen/FileInfoWithIcon.cs | 14 ++ .../Views/FileOpen/FileOpenView.xaml | 99 ++++++++++ .../Views/FileOpen/FileOpenView.xaml.cs | 79 ++++++++ .../Views/FileOpen/FileOpenViewModel.cs | 186 ++++++++++++++++++ .../Views/FileOpen/HeaderToImageConverter.cs | 34 ++++ .../Views/WindowManagement/WindowViewModel.cs | 54 ++--- 16 files changed, 741 insertions(+), 33 deletions(-) create mode 100644 Source/TailBlazer.Fixtures/FileOpenFixture.cs create mode 100644 Source/TailBlazer.Fixtures/TestDirectory.cs create mode 100644 Source/TailBlazer/Resources/diskdrive.png create mode 100644 Source/TailBlazer/Resources/folder.png create mode 100644 Source/TailBlazer/Views/FileOpen/FileInfoWithIcon.cs create mode 100644 Source/TailBlazer/Views/FileOpen/FileOpenView.xaml create mode 100644 Source/TailBlazer/Views/FileOpen/FileOpenView.xaml.cs create mode 100644 Source/TailBlazer/Views/FileOpen/FileOpenViewModel.cs create mode 100644 Source/TailBlazer/Views/FileOpen/HeaderToImageConverter.cs diff --git a/Source/TailBlazer.Fixtures/FileOpenFixture.cs b/Source/TailBlazer.Fixtures/FileOpenFixture.cs new file mode 100644 index 00000000..5e63946a --- /dev/null +++ b/Source/TailBlazer.Fixtures/FileOpenFixture.cs @@ -0,0 +1,173 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using FluentAssertions; +using FluentAssertions.Common; +using TailBlazer.Infrastucture; +using TailBlazer.Views.FileOpen; +using TailBlazer.Views.WindowManagement; +using Xunit; + +namespace TailBlazer.Fixtures +{ + public class FileOpenFixture + { + [Fact] + public void OpenFile() + { + using (var file = new TestFile()) + { + file.Append("testLine"); + + new FileOpenViewModel(null).FileAndDirectoryValidator(file.Info.FullName).Select(f => f.FullName).First().Should().Be(file.Info.FullName); + } + } + + [Fact] + public void OpenEmptyFile() + { + using (var file = new TestFile()) + { + new FileOpenViewModel(null).FileAndDirectoryValidator(file.Info.FullName).Select(f => f.FullName).First().Should().Be(file.Info.FullName); + } + } + + [Fact] + public void OpenNotExistingFile() + { + using (var file = new TestFile()) + { + file.Delete(); + new FileOpenViewModel(null).FileAndDirectoryValidator(file.Info.FullName).Should().BeNull(); + } + } + + [Fact] + public void OpenReadOnlyFile() + { + using (var file = new TestFile()) + { + file.SetAttributeReadOnlyTrue(); + + new FileOpenViewModel(null).FileAndDirectoryValidator(file.Info.FullName).Select(f => f.FullName).First().Should().Be(file.Info.FullName); + } + } + + [Fact] + public void OpenHiddenFile() + { + using (var file = new TestFile()) + { + file.SetAttributeHiddenTrue(); + + new FileOpenViewModel(null).FileAndDirectoryValidator(file.Info.FullName).Select(f => f.FullName).First().Should().Be(file.Info.FullName); + } + } + + [Fact] + public void OpenSystemFile() + { + using (var file = new TestFile()) + { + file.SetAttributeSystemTrue(); + + new FileOpenViewModel(null).FileAndDirectoryValidator(file.Info.FullName).Select(f => f.FullName).First().Should().Be(file.Info.FullName); + } + } + + [Fact] + public void OpenEmptyDirectory() + { + using (var directory = new TestDirectory()) + { + Assert.Empty(new FileOpenViewModel(null).FileAndDirectoryValidator(directory.Info.FullName)); + } + } + + [Fact] + public void OpenNotExistingFolder() + { + using (var directory = new TestDirectory()) + { + directory.Delete(); + new FileOpenViewModel(null).FileAndDirectoryValidator(directory.Info.FullName).Should().BeNull(); + } + } + + [Fact] + public void CheckNumberOfOpenedFilesFromDirectoryWithOneFile() + { + using (var directory = new TestDirectory()) + using (var file = new TestFile()) + { + directory.CopyTestFileToDirectory(file); + new FileOpenViewModel(null).FileAndDirectoryValidator(directory.Info.FullName).Length.Should().Be(1); + } + } + + [Fact] + public void CheckNumberOfOpenedFilesFromDirectoryWithMultipleFiles() + { + using (var directory = new TestDirectory()) + using (var file1 = new TestFile()) + using (var file2 = new TestFile()) + using (var file3 = new TestFile()) + { + directory.CopyTestFileToDirectory(file1); + directory.CopyTestFileToDirectory(file2); + directory.CopyTestFileToDirectory(file3); + new FileOpenViewModel(null).FileAndDirectoryValidator(directory.Info.FullName).Select(f => f.FullName).Count().Should().Be(3); + } + } + + [Fact] + public void OpenDirectoryWithOneFileInIt() + { + using (var directory = new TestDirectory()) + using (var file = new TestFile()) + { + directory.CopyTestFileToDirectory(file); + + var expected = directory.GetFiles().OrderBy(t => t.FullName); + var actual = new FileOpenViewModel(null).FileAndDirectoryValidator(directory.Info.FullName).OrderBy(t => t.FullName); + + for (int i = 0; i < expected.Count(); i++) + { + expected.ElementAt(i).FullName.ShouldBeEquivalentTo(actual.ElementAt(i).FullName); + expected.ElementAt(i).Length.ShouldBeEquivalentTo(actual.ElementAt(i).Length); + } + } + } + + [Fact] + public void OpenDirectoryWithMultipleFilesInIt() + { + using (var directory = new TestDirectory()) + using (var file1 = new TestFile()) + using (var file2 = new TestFile()) + using (var file3 = new TestFile()) + { + + directory.CopyTestFileToDirectory(file1); + directory.CopyTestFileToDirectory(file2); + directory.CopyTestFileToDirectory(file3); + + var expected = directory.GetFiles().OrderBy(t => t.FullName); + var actual = new FileOpenViewModel(null).FileAndDirectoryValidator(directory.Info.FullName).OrderBy(t => t.FullName); + + for (int i = 0; i < expected.Count(); i++) + { + expected.ElementAt(i).FullName.ShouldBeEquivalentTo(actual.ElementAt(i).FullName); + expected.ElementAt(i).Length.ShouldBeEquivalentTo(actual.ElementAt(i).Length); + } + } + + + + } + } +} diff --git a/Source/TailBlazer.Fixtures/IndexerFixture.cs b/Source/TailBlazer.Fixtures/IndexerFixture.cs index 55839016..19333139 100644 --- a/Source/TailBlazer.Fixtures/IndexerFixture.cs +++ b/Source/TailBlazer.Fixtures/IndexerFixture.cs @@ -62,7 +62,7 @@ public void CanReadIndiciesBack_SmallFile() { var pulse = new Subject(); var scheduler = new TestScheduler(); - + using (var file = new TestFile()) { file.Append(Enumerable.Range(1, 100).Select(i => $"This is line number {i.ToString("00000000")}").ToArray()); diff --git a/Source/TailBlazer.Fixtures/TailBlazer.Fixtures.csproj b/Source/TailBlazer.Fixtures/TailBlazer.Fixtures.csproj index aa7fd156..281bbd75 100644 --- a/Source/TailBlazer.Fixtures/TailBlazer.Fixtures.csproj +++ b/Source/TailBlazer.Fixtures/TailBlazer.Fixtures.csproj @@ -101,6 +101,7 @@ + @@ -117,6 +118,7 @@ + diff --git a/Source/TailBlazer.Fixtures/TestDirectory.cs b/Source/TailBlazer.Fixtures/TestDirectory.cs new file mode 100644 index 00000000..63d2fcf0 --- /dev/null +++ b/Source/TailBlazer.Fixtures/TestDirectory.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace TailBlazer.Fixtures +{ + public class TestDirectory : IDisposable + { + public string FullName { get; } + public DirectoryInfo Info { get; } + + public TestDirectory() + { + + FullName = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + while (Directory.Exists(FullName)) + { + FullName = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + } + + Directory.CreateDirectory(FullName); + Info = new DirectoryInfo(FullName); + } + + public void CopyTestFileToDirectory(TestFile testFile) + { + File.Copy(Path.Combine(testFile.Info.Directory.FullName, testFile.Info.Name), Path.Combine(FullName, testFile.Info.Name)); + } + + public FileInfo[] GetFiles() + { + return new DirectoryInfo(FullName).GetFiles(); + } + + public void Delete() + { + if (Directory.Exists(FullName)) + { + Directory.Delete(FullName, true); + } + } + + public void Create() + { + Directory.CreateDirectory(FullName); + } + + public void Dispose() + { + Delete(); + } + } +} diff --git a/Source/TailBlazer.Fixtures/TestFile.cs b/Source/TailBlazer.Fixtures/TestFile.cs index eb6ec97b..3663739f 100644 --- a/Source/TailBlazer.Fixtures/TestFile.cs +++ b/Source/TailBlazer.Fixtures/TestFile.cs @@ -6,39 +6,75 @@ namespace TailBlazer.Fixtures { public class TestFile: IDisposable { - public string Name { get; } + public string FullName { get; } public FileInfo Info { get; } public TestFile() { - Name = Path.GetTempFileName(); - Info = new FileInfo(Name); + FullName = Path.GetTempFileName(); + Info = new FileInfo(FullName); } public void Append(IEnumerable lines) { - File.AppendAllLines(Name,lines); + File.AppendAllLines(FullName,lines); } public void Append(string line) { - File.AppendAllLines(Name, new[]{line}); + File.AppendAllLines(FullName, new[]{line}); } public void Delete() { - File.Delete(Name); + if (File.Exists(FullName)) + { + if (Info.IsReadOnly) + { + SetAttributeReadOnlyFale(); + } + if ((Info.Attributes & FileAttributes.Hidden) != 0) + { + SetAttributeSystemFalse(); + } + File.Delete(FullName); + } } public void Create() { - File.Create(Name); + File.Create(FullName); } public void Dispose() { - File.Delete(Name); + Delete(); + } + + public void SetAttributeReadOnlyTrue() + { + File.SetAttributes(FullName, File.GetAttributes(FullName) | FileAttributes.ReadOnly); + } + + private void SetAttributeReadOnlyFale() + { + File.SetAttributes(FullName, File.GetAttributes(FullName) & ~FileAttributes.ReadOnly); + } + + public void SetAttributeHiddenTrue() + { + File.SetAttributes(FullName, File.GetAttributes(FullName) | FileAttributes.Hidden); + } + + public void SetAttributeSystemTrue() + { + File.SetAttributes(FullName, File.GetAttributes(FullName) | FileAttributes.System); + } + + public void SetAttributeSystemFalse() + { + File.SetAttributes(FullName, File.GetAttributes(FullName) & ~FileAttributes.System); } } } diff --git a/Source/TailBlazer/App.xaml b/Source/TailBlazer/App.xaml index b48457a1..d4e5f0d8 100644 --- a/Source/TailBlazer/App.xaml +++ b/Source/TailBlazer/App.xaml @@ -5,7 +5,9 @@ xmlns:fileDrop="clr-namespace:TailBlazer.Views.FileDrop" xmlns:tail="clr-namespace:TailBlazer.Views.Tail" xmlns:searching="clr-namespace:TailBlazer.Views.Searching" - xmlns:settings="clr-namespace:TailBlazer.Settings"> + xmlns:settings="clr-namespace:TailBlazer.Settings" + xmlns:fileopen ="clr-namespace:TailBlazer.Views.FileOpen"> + @@ -13,6 +15,10 @@ + + + + diff --git a/Source/TailBlazer/MainWindow.xaml b/Source/TailBlazer/MainWindow.xaml index 2f4aff95..7566b706 100644 --- a/Source/TailBlazer/MainWindow.xaml +++ b/Source/TailBlazer/MainWindow.xaml @@ -138,7 +138,7 @@ + + - + - + + + Text="{Binding DisplayName}" /> @@ -232,8 +240,8 @@ - - + - - - + ItemsSource="{Binding Views}" + FixedHeaderCount="{Binding PinnedNumber2}" + > + + diff --git a/Source/TailBlazer/MainWindow.xaml.cs b/Source/TailBlazer/MainWindow.xaml.cs index 28ca47fe..ab6dc412 100644 --- a/Source/TailBlazer/MainWindow.xaml.cs +++ b/Source/TailBlazer/MainWindow.xaml.cs @@ -15,7 +15,6 @@ namespace TailBlazer /// public partial class MainWindow : MetroWindow { - public MainWindow() { InitializeComponent(); diff --git a/Source/TailBlazer/Resources/pin-2.png b/Source/TailBlazer/Resources/pin-2.png new file mode 100644 index 0000000000000000000000000000000000000000..624fbdbc7e77f036df8ad7cdffae177c3eb6a90c GIT binary patch literal 9281 zcmc&aX;{+P*GNzX>EgV2%)x zrDElTjg&3gOpR8fISrYnjoPAFmiC_ev;T+x`|bVo@;p9q?mg$+bI*Pci6X;SOw%>h z#o=(%f&%@ca5y{*{b^5zm0#maI^Z8dx^K{GZTRfc=H&vcvn7z7j?;>ng8sB@i9tgWk3>*wnwwWkJKzeeFf(*K{2-P0=%J+lh3CV8J8>zIUd7i`@+bhq$Pg8uaB z2RTUeE5Hlc3d*?VSQ&ZyR7= z!{O_#yLay%Dtu&)EjZ!zng+VMx|X-s^laFbEGBlDEB485ACw+$!k619_9d0)VqdKk z`{?Bpt03^*R}-s%8}tfWy$!f`3k{HL2ZOj;$L#EpY$o|C{BmX-lFenZka)1N3(3aa zgx50(n}*I;6%Z&cd8L|4%c^~6wdvd~ZnqgLcv^l2EY+FAM~)nc3T9vn*GViDcc8JA zJut`5fUR-@s@%nDgxU@}E!`&Q;3Pk;mdEjQbeh6mNK8uB!H%#YP!vVh81frHzFmwV z%K&*6I}IVfb;0YgPAD@^G~q`<21i?4+l5iDZl2w}DeUoVGcz-HV`JlW_v(pu_hSdN zyyrMMJ2UMi%=AIKu=bjpX<$>|fjQpn8(b|u`(pIBFE3ua&_7YWlO`Er4J@-3I1vVH z75l11vXUnJ0BGq@F8a0vulKa1DNjT{R179 zy%X3~VC;4QyR8_zQ@~CKv2*dl>y=>aN{ofXP>kIJU}uA|>jrjgjLE1D-Fy}zh+HTn z@~qKWec+`3BECLl1WF_U+nfsy=!Zo5Gk~iVV2A`6Heh)RFtj;0ug2l+?I-ok3p=JjjcQUDWNMM(Z z^xTN~&1Hl#U|q#sgp8o10m*uBK$51?jH3T^@yoNOU4_Tx4DhTKV$xYM69 zgj}q#HBCg%g*CoLS4?EWQgovc#F0LVl18HuGJA_NIHy0y(2)JsT}YJmcQ>CnGSJ^I za`2_s1_uYd#&6F`{rXekqg7##mzHKlt_P#3qd=2Z^33O*fB(JrYmRa3r;qoYZ|?fC zY;fnp01{h&ixck`0%eP}p!Ll~W#70ra-$HCWlF9zR=*Ka0)j0S`?3ID58(|Cdf5uE zwEvadHBMUa0JIV@)uew*s$63FHi$ zE`>A*@mn$r2rcEAhbWM!Ac`J{RM|vBX8rOb-%s@AHu!?T$55Jr3#6MXxLS>jOLt#F zW{jie|D{7OSuALESTn(XCCIVBMxMFxJ9(nDf?E#gaVU`jx+$Pr2wJ7eiTj>&$Lqx} z=M2-_C#0!>(`UlzdH*4|P;hO4Jn=u|+Vm1FAiwsVd@Ej$W-HHR%$g9sFqG?~2K2t~ z!hyjm(A`nt0qvgi2lTDBa?hU{TN&}FT)~A4mvenK4&+JKHPuVJuN<1Vbud+NhN`K2 z^6!5bY11oyQ1(@qd}jn!p_zjxq_lq&J%0Q+wa09}8)DXFqd2n#==y7tPcQQF`W8K4 zQHM^Z+6sw8GP9mCcjC}4;2)`}{7HH32r?^pUL;h#5DpPJ#XL75F$a{;*y@M*L@-`Y zmnzQ`N!?Hqj-vr+fxu}Ps0$#7B9c1Re|>+yR$pKLW@*%DU~sRvBP*C%WpYB5{h*QI zET}%8pP!!!MPvMkRh5}}mB}$x_Cd7aW`HC=7{K+hK@yo_$^W*w!h8~v=#W3Mx*wV4 zG7keoF_6S^0V{@Z!X|bNSuTbcII(NMaseZSa5hqr$=B-8O^z%3tmX4jI#ol3JP7_r zV&WWR&;VwKghv za8qe_ka*Z8p&_;>OGm4I(GG9<{5?_BWt z)pO>~-Ak1W^*W3v{vpm_au(}(267nTNR7J*6n?Kr+CsGqL04X2fz*|&(wuF}mA0It zPAp zGn}%2Ii{tOLZpG62CM}O&MW(-k}z#k_0XxqWY&VTUAw+M9Qbys~PL7W5$j*T`O&>{7F?R^bicc z+5D@Z^_ks-%~m4EYz^WvQhWrhY=?Y+LO3g3ku({GtfH7LV8~U$ z5oWVz?@F$YsW-x;J*SKOrO!e^vyyjK{q5R3>@>lQfiYX(>vcw&4)@p^+`G=^+qUgr z?w4;KU)f&s%}O#f-myV<=;HnR_ia<2U(4_qF?jkXyhpzL3M&sU6z;JaDSqS{_Cb2# z!UgD}UL5WG<{So;NiNl(F=keI!UO#)uU{7aMX-)Fp zSFc~c>+_mXgyS6F{TUMCQM&R6 z<_A5zbH3~unYqOnG2E#wJ5FL>v5~*P6kKkrh!5p8A5~_XA^zpoiuiC|bDlEW4M|>l zSQUd4yXk3k-OZ7knd12t{?V`?Ix9)DN%@86&57WRQR;3(N#+702W0IE+>1CHsI3d$z% zfG%t4j!RdQzx<%ge!lG6*AHHuHT|jOg?p$Y#lFi1tob`2giq?_chj{e?HvEyv-j)p zlXc(53LpLbpkBgj$$_3z&!#HRO3pQZxNM~3I=oxdgz&6pf9I*@j0%sEz&&{bxu`WkCyC=G^brB zRB`Z#v#R3iX)05wZ^H2TKDn}jrtE3C(wzoue7=?lL2dxCGkH4n$<|fSUS|RrlZHTB z1j^0j-O0a*traFYO}ZkwGG7_Y*fD^-JVPLO_r9T_VS8!$&UFKh zIfiU{sWPVAIsj0&N?U_@Yr}Y#12u`yib-&C5RxNqWuuY3qh%F=a?FrzAy!j!9R}P- znn)~o4d(b$AV!q;PFjX==Pec+k=PH8D$hOS04T-;iHCY{crgeG`ty zj!CSV4<9~6)Fx+HjvU4>d*s@jaOCh|&y!i&Nq!vlUp2e!B|}#rpLBIbof+&gbD1Fw z*oLlBaa5UCo&4odXJ_Y>mX?-rK8ZcDsr_U3=g*%nb$8C2Ve6asf@6~A^fOIEYg4yE zQ?flOcr)1Jb2b0TuP382(Yw1dV`sCY97^vDe{=XfCG;3ji&_6nmx6(>rlm$I}u?ai z#DSVCeOeCb-IwQRfgKjk%R!dkvt!4n>im2?vAPTB+M)I@t|}%WI+}TvFBD?i0Lm&d z^YYr4l?(1P#YAx=R*H%rkXdc4<#B#$Mnbr_`l>QGh`Z7dDK*rWqy7;}-E1mfBq%zn zIyWCF%A`n{cgToYR%*%r1zYvSR&!u=4ztYEl7AOljlxz7m3d(Zm&)(OR^zbMA7B;X zLP@KK!=Se&vH$hwsMFMp3tdnTQ^~B=5lDe+b`I3_bPmH~ZI^{)s1{z+VFSv(LKC*8 zFBYHAHb8E(ypbV;SAYy!zrBN5e}DP=ubO5vK=8rmKf@4W0O6{#kHg{IIODbn4?ZSB5g5&mciXp z!Ge(mi4Cu^xOC_a3(%sif_1PpariyBQf!#LNR}m%<$&+hfk|>fAMJ)LI-1+%HC;Q} zRJvGTbb`;x*e0S2s+S4X8Wc;V_OO`6$*4h#vxI6YlDl-Kz-Ub{C&L{rdI;5V*rE{pbE(yMo%S3@EeI$;2*6oW&levbL5&w z)n7GZ#+pP{*nn2#(U&h@o-cd^Gcw|+&tun!vQwwVdpi7bvD)!*^v$JjdxCpYUqJyc z-~8*YojX4ZAwr)(9&A1|YvG>vZ5P+nrVpZ*>d0bG&vF0Y-p6&@XS_ZD>1_x;AL>!++Q^x93(t`uektj8Kj^UzP2E6hS+v%o91Jkyr-E z_6%(#E_${d05_MxODUAI5-%j`TY&u?$Y`?=UcjcvbYYR!7tjHFjA_JIE%zS3$HyI=KL!{_|EJW9cIfh6REfrjEL}~_+ z*l6VT*ZpOE-+e@Cn81VP=&@X+2A*ykjzJ2qDhhE<{9Pu1|J=aPwybm-DIq9bI zoO>+rfPvMM_L{Mag^w)jYG+h_IW!nsHL#=mc*35mn@gR4F6=DJ3fT;~@t4h|r#(D8 zzN8E|qDdwcSAM$Fjo;WV-SohI0%fWnhADX6Yiqv#Pibb}hFH@3D= zjM?ZSC1fFS4T-s*9m+%3j7tGM`f#SDeEd#KVks;HZly?((2iV!cUx+g*#by{Wafh+ z6{=8w^e+rsAO+W(Cs3c%p|g%DOCKab!T>#_gGQ%m64P2&U`H2wa~u3}rAd|0*#bR1 zN0ki$d%bT0IfSY(H<#zF44V)H49fB07+v@@!I`8(R~}K)qAyR#B_Xl47z-FTG~a1$ z6fdR=7>DA%gSHANc)A;pVCR@Cyg4u!!PsUm)S*L@$Vh#Uu_ZzRqZcbn58a(0>SRK59mk+$!Cow&!g=yCahv6%4H4% zAAX;}K0#(ZIIN@^Oc?L!VO1QoGWzelCvMa4RyRcz*=RKDlTUli+}&ftPrgNR)`oE! zz>HV6K-bR;?p+YXd44Im{Ua3ox>H$!!aW61qtU^=mwL?pcbE%f`d^vhu9KK&-6caq zP*0E9OCq|>R-IXKOquE3UgIn&^t6+67mn*w7~~10XV0G947Zm+N-W|(k=K_-Wv=UF z7d~JcKys=mR_Z<{!=NQ#u7C)6X>|}MM~;3A(9krxKiVoP4l8ws(ePfdP(XZXz*-%^ z$!W`jeX6y9xB>9}I63YJj&X;5fPFYQH5hCIFqt(Yf|IiigQ0zUY`~fk#>trsi5l|n zJ!o*gL5nu#w`+c^W#L)$adG}J1|`sZ!TE3n%8_nnY~$u4(+dR@?+Pz(CE!^ zh3OanRHIR71b5|ZfsrXBS}H%b(WuKpVV9@W4I{y2-1IfN?+sZqKsXyTrK$urHwcsf z1Lj$HuNks4NX&xMDyoOT=$&T8-SI}F!WGa-35;k<;B+ZnqkGRvQBtVXWf&rMlLcrH9=e>9Q;DvAFNEXs z4Ei!Sore0C_Xf;JPoesCBcq}Z&B!*394hv!;#O;Dt}xyNIM<=#0Q7_aOA#!9{d`s2 z41n)rFziE#+yd|$1h0qvW2(4F4ect73;>4xpHy)!09PRRIl$1p8UWmc;C_I?{SyFw zjo{{7hmt8mb$BBqkn=o%cX0)$VV5?&W?Nd?dvW2TRBJ)T%^G+(XJ%%O&Z;|5$g7Uo z{R+Jl%L_Yy$_hC_j3u6)d#aM#_nwZ*Tmju{Z>)UJf{_AJ zSy|awOnc4gruy@ddo3kUi&o%%dz-DkeUj+clFi@ZG_@aIQvW~-^ICf`dfmfilVN5a zXQ_clGrZWKeUA6#UUnB4k(g^xIU+7FSFrMxx+3YET-ooj;2ujBE&4PHo^`Ba!@g$p zWAq*GDZ^C1!__L7A!`>@q4 zk@VpA(+?atu|5G0B8h1sU}&ML8fhS`1}j_1X{ZB(NvDG14_9X7V4`Rd+F%%6psXxG zO=(jo*Kr?WG!xU^OdZ*AGB9$pM2DJ_g>D-Vqj)$J#urb}WE7r0OJF>MWNF4&l$5AS zEzs@tFl*Sr$Ol}!u@#=pAesoqJchur+Iu_o%{TY359vX?=gD4@tz$4t1we(949e){z3mzrd+V~wq2PEfW31Zta> zhY!Cc2ltZgCGI1|x0YV3tsNQYuspLZRzVY_VP2mAQ%o3gy8zb9?R!|amcw{t@5s@N zOEt-moLW4KvZnkQ&Sku4VMlV7RfO4(y@v>ZbnRPzQt$7!n*L{ynS%!AxJxeFzdy8|zc#5S8rP-hwz5u%0YGV`v%Lr)36K*??)`^C)<$)#h- z6@F^~wRCku&CSfDZ$VqmHUj*hewx?$>~-}VQ=&T#R3Z_K(U#h@;q ze+X?bO$g*%W?3S2>1xZgFm=6~jP3}r>4C0H+>YKdXqMz7?`iA9DiXs`fV=!g(<2yGM$!7m9Zmu9VSN4Y__?P@%TSy7_;3x$%y)8GA|CGmMh zXe-6Ai?flDC*k?ikeJ*RBLQuW0^$dk)(iE_H>*yM{u%N0?E$Z^@le>iJEKbOgI8|b zvuAuTO<%Zp$H!+0`mwv-sTl)vR4#-z)07V7yDM2)SvSj~M#UX#bpLs!i_6rO!S5Qi zxemA;+QMorPzsJa2haD@LpR3pNvt(2E(nNwsshh!-5%yyN1CHcPF!zV5 zjeGMUyLvzI2Cq8o@z+Q2^oC{;k8?9*d6Wt;;-e~4)l^V}mTEevI3D>EZkv^2vg>}h z9?k_PbW`ME+unpWZ5lk|h`324mgO%nH8sLb4douHKzhJIsJc~UV~Bx-Hi9mO2*FLZ z#}E%bIIt|D3!W=CPehGwx%Wlu4>-o=1(6?j=gyr$5IMYb+!_ht5AHb=^sJ@&fe>v& z29L$>6Y0nf+MuYw&D54XSdOtit}VkKMBa{@Ph#bmxFBhGHVWPO(1$tT?DnZ>52hoH zoiV^mz1P4y6TdH8TjraLk?2|~bZeGlhy^MdCj$FcsH#*MVI*9>HiJ??eqVy61j+HZRhWl%u4zucFb{XbNpzjput literal 0 HcmV?d00001 diff --git a/Source/TailBlazer/TailBlazer.csproj b/Source/TailBlazer/TailBlazer.csproj index 8f2bed27..ec91af23 100644 --- a/Source/TailBlazer/TailBlazer.csproj +++ b/Source/TailBlazer/TailBlazer.csproj @@ -401,7 +401,9 @@ false - + + + diff --git a/Source/TailBlazer/Views/WindowManagement/WindowViewModel.cs b/Source/TailBlazer/Views/WindowManagement/WindowViewModel.cs index 3fa2940f..ebfd25af 100644 --- a/Source/TailBlazer/Views/WindowManagement/WindowViewModel.cs +++ b/Source/TailBlazer/Views/WindowManagement/WindowViewModel.cs @@ -39,7 +39,9 @@ public class WindowViewModel: AbstractNotifyPropertyChanged, IDisposable private bool _isEmpty; private bool _menuIsOpen; public ICommand Pinning { get; set; } - public ObservableCollection Views { get; } = new ObservableCollection(); + public int PinnedNumber { get; set; } = -1; + public int PinnedNumber2 { get; set; } = 0; + public ObservableCollection Views { get; set; } = new ObservableCollection(); public RecentFilesViewModel RecentFiles { get; } public GeneralOptionsViewModel GeneralOptions { get; } public IInterTabClient InterTabClient { get; } @@ -68,7 +70,40 @@ public WindowViewModel(IObjectProvider objectProvider, { Pinning = new ActionCommand(o => { - var content = o as string; + var viewsarray = Views.ToList(); + + var pinnedone = Views.FirstOrDefault(c => c.Header.Equals(o)); + var pinnedindex = Views.IndexOf(pinnedone); + ((FileHeader)pinnedone.Header).IsPinned=!((FileHeader)pinnedone.Header).IsPinned; + + if (((FileHeader)pinnedone.Header).IsPinned) + { + PinnedNumber += 1; + PinnedNumber2 += 1; + + var help = Views[pinnedindex]; + var help0 = Views[PinnedNumber]; + + viewsarray.Remove(viewsarray[pinnedindex]); + viewsarray.Insert(PinnedNumber, help); + } + else + { + PinnedNumber -= 1; + PinnedNumber2 -= 1; + + var help = Views[pinnedindex]; + var help0 = Views[PinnedNumber2]; + + viewsarray.Remove(viewsarray[pinnedindex]); + viewsarray.Insert(PinnedNumber2, help); + } + + Views = new ObservableCollection(viewsarray); + + OnPropertyChanged("Views"); + OnPropertyChanged("PinnedNumber2"); + }); _logger = logger; @@ -235,7 +270,9 @@ private async void OpenFile(IEnumerable files) private void Views_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { //throw new NotImplementedException(); + } + private void OpenFile(FileInfo file) { From f7f4b97e623a71f02ef83aff861038d8da884566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Set=C3=A9nyi?= Date: Fri, 15 Apr 2016 20:43:53 +0200 Subject: [PATCH 09/11] Pinning feature finished --- .../TailBlazer/Infrastucture/FilesHeader.cs | 7 +++ Source/TailBlazer/MainWindow.xaml | 59 ++++++++++++++++++- Source/TailBlazer/MainWindow.xaml.cs | 12 ---- .../Views/Dialog/DialogViewModel.cs | 7 ++- .../Views/WindowManagement/WindowViewModel.cs | 30 +++++++--- 5 files changed, 90 insertions(+), 25 deletions(-) diff --git a/Source/TailBlazer/Infrastucture/FilesHeader.cs b/Source/TailBlazer/Infrastucture/FilesHeader.cs index 036433f2..1d43f83c 100644 --- a/Source/TailBlazer/Infrastucture/FilesHeader.cs +++ b/Source/TailBlazer/Infrastucture/FilesHeader.cs @@ -11,6 +11,13 @@ namespace TailBlazer.Infrastucture public class FilesHeader : AbstractNotifyPropertyChanged { private string _displayName; + private bool _isPinned = false; + + public bool IsPinned + { + get { return _isPinned; } + set { SetAndRaise(ref _isPinned, value); } + } public string FullName { get; } diff --git a/Source/TailBlazer/MainWindow.xaml b/Source/TailBlazer/MainWindow.xaml index c2cba0db..982d0ce6 100644 --- a/Source/TailBlazer/MainWindow.xaml +++ b/Source/TailBlazer/MainWindow.xaml @@ -108,11 +108,64 @@ - + + + + + + + Text="{Binding DisplayName}" /> + + + + + + + + + + + + @@ -253,7 +306,7 @@ FixedHeaderCount="{Binding PinnedNumber2}" > - + diff --git a/Source/TailBlazer/MainWindow.xaml.cs b/Source/TailBlazer/MainWindow.xaml.cs index ab6dc412..b8aa0eb5 100644 --- a/Source/TailBlazer/MainWindow.xaml.cs +++ b/Source/TailBlazer/MainWindow.xaml.cs @@ -30,17 +30,5 @@ private void MainWindow_Closing(object sender, CancelEventArgs e) } - private void StackPanel_MouseDown(object sender, MouseButtonEventArgs e) - { - e.Handled = false; - } - - - private void pin_MouseDown(object sender, MouseButtonEventArgs e) - { - e.Handled = true; - } - - } } diff --git a/Source/TailBlazer/Views/Dialog/DialogViewModel.cs b/Source/TailBlazer/Views/Dialog/DialogViewModel.cs index d09ca305..918ab143 100644 --- a/Source/TailBlazer/Views/Dialog/DialogViewModel.cs +++ b/Source/TailBlazer/Views/Dialog/DialogViewModel.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reactive.Disposables; using System.Text; using System.Threading.Tasks; using System.Windows.Input; @@ -15,6 +16,7 @@ public class DialogViewModel : AbstractNotifyPropertyChanged, IDisposable //The text of the dialog window public String text { get; set; } public ICommand ButtonClickEvent { get; set; } + private readonly IDisposable _cleanUp; public bool Button { get; set; } public DialogViewModel() @@ -37,11 +39,14 @@ public DialogViewModel() } } }); + + _cleanUp = new CompositeDisposable(); + } public void Dispose() { - throw new NotImplementedException(); + _cleanUp.Dispose(); } } } diff --git a/Source/TailBlazer/Views/WindowManagement/WindowViewModel.cs b/Source/TailBlazer/Views/WindowManagement/WindowViewModel.cs index 43b56375..41ec4011 100644 --- a/Source/TailBlazer/Views/WindowManagement/WindowViewModel.cs +++ b/Source/TailBlazer/Views/WindowManagement/WindowViewModel.cs @@ -71,35 +71,47 @@ public WindowViewModel(IObjectProvider objectProvider, ISchedulerProvider schedulerProvider, DialogViewModel dialogviewmodel) { + //This function handles the pinning + //If the user decides to pin a tab the function will lock that tab and reorder the effected tabs Pinning = new ActionCommand(o => { var viewsarray = Views.ToList(); - var pinnedone = Views.FirstOrDefault(c => c.Header.Equals(o)); var pinnedindex = Views.IndexOf(pinnedone); - ((FileHeader)pinnedone.Header).IsPinned=!((FileHeader)pinnedone.Header).IsPinned; + bool actualpinned = false; + ViewContainer oldtab = null; + + if (o.GetType().IsEquivalentTo(typeof(FilesHeader))) + { + ((FilesHeader)pinnedone.Header).IsPinned = !((FilesHeader)pinnedone.Header).IsPinned; + actualpinned = ((FilesHeader)pinnedone.Header).IsPinned; + } + else + { + ((FileHeader)pinnedone.Header).IsPinned = !((FileHeader)pinnedone.Header).IsPinned; + actualpinned = ((FileHeader)pinnedone.Header).IsPinned; + } + - if (((FileHeader)pinnedone.Header).IsPinned) + if (actualpinned) { PinnedNumber += 1; PinnedNumber2 += 1; - var help = Views[pinnedindex]; - var help0 = Views[PinnedNumber]; + oldtab = Views[pinnedindex]; viewsarray.Remove(viewsarray[pinnedindex]); - viewsarray.Insert(PinnedNumber, help); + viewsarray.Insert(PinnedNumber, oldtab); } else { PinnedNumber -= 1; PinnedNumber2 -= 1; - var help = Views[pinnedindex]; - var help0 = Views[PinnedNumber2]; + oldtab = Views[pinnedindex]; viewsarray.Remove(viewsarray[pinnedindex]); - viewsarray.Insert(PinnedNumber2, help); + viewsarray.Insert(PinnedNumber2, oldtab); } Views = new ObservableCollection(viewsarray); From 6f7b114de5093427cdc56c9ed6a2515f5f372915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Miskolczi?= Date: Fri, 15 Apr 2016 21:52:32 +0200 Subject: [PATCH 10/11] File open bug fixed. --- Source/TailBlazer.Fixtures/FileOpenFixture.cs | 1 - Source/TailBlazer.Fixtures/TestFile.cs | 3 +- .../TailBlazer/Views/Dialog/DialogView.xaml | 4 +- .../Views/Dialog/DialogViewModel.cs | 1 + .../Views/FileOpen/FileOpenView.xaml | 4 +- .../Views/FileOpen/FileOpenViewModel.cs | 44 ++++++++++++++----- .../Views/WindowManagement/WindowViewModel.cs | 14 ++++-- 7 files changed, 50 insertions(+), 21 deletions(-) diff --git a/Source/TailBlazer.Fixtures/FileOpenFixture.cs b/Source/TailBlazer.Fixtures/FileOpenFixture.cs index 5e63946a..01ff8e00 100644 --- a/Source/TailBlazer.Fixtures/FileOpenFixture.cs +++ b/Source/TailBlazer.Fixtures/FileOpenFixture.cs @@ -22,7 +22,6 @@ public void OpenFile() using (var file = new TestFile()) { file.Append("testLine"); - new FileOpenViewModel(null).FileAndDirectoryValidator(file.Info.FullName).Select(f => f.FullName).First().Should().Be(file.Info.FullName); } } diff --git a/Source/TailBlazer.Fixtures/TestFile.cs b/Source/TailBlazer.Fixtures/TestFile.cs index 3663739f..b7bb4426 100644 --- a/Source/TailBlazer.Fixtures/TestFile.cs +++ b/Source/TailBlazer.Fixtures/TestFile.cs @@ -8,10 +8,9 @@ public class TestFile: IDisposable { public string FullName { get; } public FileInfo Info { get; } - + public TestFile() { - FullName = Path.GetTempFileName(); Info = new FileInfo(FullName); } diff --git a/Source/TailBlazer/Views/Dialog/DialogView.xaml b/Source/TailBlazer/Views/Dialog/DialogView.xaml index 411ff769..3d23bac2 100644 --- a/Source/TailBlazer/Views/Dialog/DialogView.xaml +++ b/Source/TailBlazer/Views/Dialog/DialogView.xaml @@ -9,7 +9,9 @@ mc:Ignorable="d" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" d:DesignHeight="300" d:DesignWidth="300" - d:DataContext="{d:DesignInstance dialog:DialogViewModel}"> + d:DataContext="{d:DesignInstance dialog:DialogViewModel}" + Identifier="{Binding Id}" + > diff --git a/Source/TailBlazer/Views/Dialog/DialogViewModel.cs b/Source/TailBlazer/Views/Dialog/DialogViewModel.cs index d09ca305..e2c7608b 100644 --- a/Source/TailBlazer/Views/Dialog/DialogViewModel.cs +++ b/Source/TailBlazer/Views/Dialog/DialogViewModel.cs @@ -12,6 +12,7 @@ namespace TailBlazer.Views.Dialog //This class is responsible for displaying custom dialog windows public class DialogViewModel : AbstractNotifyPropertyChanged, IDisposable { + public Guid Id { get; } = Guid.NewGuid(); //The text of the dialog window public String text { get; set; } public ICommand ButtonClickEvent { get; set; } diff --git a/Source/TailBlazer/Views/FileOpen/FileOpenView.xaml b/Source/TailBlazer/Views/FileOpen/FileOpenView.xaml index 3b9782b1..b2d3d63d 100644 --- a/Source/TailBlazer/Views/FileOpen/FileOpenView.xaml +++ b/Source/TailBlazer/Views/FileOpen/FileOpenView.xaml @@ -11,7 +11,9 @@ xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls" xmlns:tailBlazer="clr-namespace:TailBlazer" mc:Ignorable="d" - d:DataContext="{d:DesignInstance local:FileOpenViewModel}"> + d:DataContext="{d:DesignInstance local:FileOpenViewModel}" + Identifier="{Binding Id}" + > public class FileOpenViewModel : AbstractNotifyPropertyChanged, IDisposable { + public Guid Id { get; } = Guid.NewGuid(); private readonly IDisposable _cleanUp; + private string _selectedTreeViewItemPath; public FileInfoWithIcon SelectedItem { get; set; } /// /// The content of this list will display on the right side of the Open Dialog @@ -28,7 +31,7 @@ public class FileOpenViewModel : AbstractNotifyPropertyChanged, IDisposable public ICommand SelectedItemChangedCommand { get; set; } public ICommand OpenSelectedItemCommand { get; set; } - public FileOpenViewModel(Action> openFile) + public FileOpenViewModel(Func, Task> openFile) { SelectedItemChangedCommand = new ActionCommand(treeview => SelectedItemChangedCommandMethod(treeview as TreeView)); OpenSelectedItemCommand = new ActionCommand(closeCommand => OpenSelectedItemCommandMethod(openFile, closeCommand as RoutedCommand)); @@ -40,10 +43,23 @@ public FileOpenViewModel(Action> openFile) /// /// /// - private void OpenSelectedItemCommandMethod(Action> openFile, RoutedCommand closeCommand) + private async void OpenSelectedItemCommandMethod(Func, Task> openFile, RoutedCommand closeCommand) { - openFile(FileAndDirectoryValidator(SelectedItem.FileInfo.FullName)); - closeCommand?.Execute(null, null); + + if (SelectedItem?.FileInfo?.FullName != null) + { + await openFile(FileAndDirectoryValidator(SelectedItem.FileInfo.FullName)); + closeCommand?.Execute(null, null); + } + else if (!string.IsNullOrEmpty(_selectedTreeViewItemPath)) + { + await openFile(FileAndDirectoryValidator(_selectedTreeViewItemPath)); + closeCommand?.Execute(null, null); + } + else + { + //TODO: Notify user to select a folder or file + } } /// @@ -55,11 +71,11 @@ private void SelectedItemChangedCommandMethod(TreeView tree) var temp = ((TreeViewItem) tree.SelectedItem); if (temp != null) { - var selectedImagePath = GenerateFilePath(temp); + _selectedTreeViewItemPath = GenerateFilePath(temp); FilesAndIcons = new List(); - GetDirecotries(selectedImagePath); - GetFiles(selectedImagePath); + FilesAndIcons.AddRange(GetDirecotries(_selectedTreeViewItemPath)); + FilesAndIcons.AddRange(GetFiles(_selectedTreeViewItemPath)); OnPropertyChanged("FilesAndIcons"); } @@ -69,8 +85,9 @@ private void SelectedItemChangedCommandMethod(TreeView tree) /// Gets all files from the given path. /// /// - private void GetFiles(string selectedImagePath) + private List GetFiles(string selectedImagePath) { + List fiwiList = new List(); foreach (var fileName in new DirectoryInfo(selectedImagePath) .GetFiles() // Skipping hidden and system files. @@ -91,17 +108,19 @@ private void GetFiles(string selectedImagePath) BitmapSizeOptions.FromEmptyOptions()) }; - FilesAndIcons.Add(fai); + fiwiList.Add(fai); } } + return fiwiList; } /// /// Gets all dictionaries from the given path. /// /// - private void GetDirecotries(string selectedImagePath) + private List GetDirecotries(string selectedImagePath) { + List fiwiList = new List(); foreach (var fileName in Directory.GetDirectories(selectedImagePath) .Where(d => !new DirectoryInfo(d).Attributes.HasFlag(FileAttributes.Hidden | FileAttributes.System))) { @@ -114,8 +133,9 @@ private void GetDirecotries(string selectedImagePath) ImageSource = new BitmapImage(uri) }; - FilesAndIcons.Add(fai); + fiwiList.Add(fai); } + return fiwiList; } /// @@ -161,7 +181,7 @@ public FileInfo[] FileAndDirectoryValidator(string fileOrDirectoryPath) try { var attr = File.GetAttributes(fileOrDirectoryPath); - return attr.HasFlag(FileAttributes.Directory) ? new DirectoryInfo(fileOrDirectoryPath).GetFiles() : new[] {new FileInfo(fileOrDirectoryPath)}; + return attr.HasFlag(FileAttributes.Directory) ? GetFiles(fileOrDirectoryPath).Select(t => t.FileInfo).ToArray() : new[] {new FileInfo(fileOrDirectoryPath)}; } catch (Exception ex) { diff --git a/Source/TailBlazer/Views/WindowManagement/WindowViewModel.cs b/Source/TailBlazer/Views/WindowManagement/WindowViewModel.cs index 238374f0..900ce4e5 100644 --- a/Source/TailBlazer/Views/WindowManagement/WindowViewModel.cs +++ b/Source/TailBlazer/Views/WindowManagement/WindowViewModel.cs @@ -9,6 +9,7 @@ using System.Reactive.Disposables; using System.Reactive.Linq; using System.Reflection; +using System.Threading.Tasks; using System.Windows; using System.Windows.Input; using Dragablz; @@ -67,7 +68,8 @@ public WindowViewModel(IObjectProvider objectProvider, RecentFilesViewModel recentFilesViewModel, GeneralOptionsViewModel generalOptionsViewModel, ISchedulerProvider schedulerProvider, - DialogViewModel dialogviewmodel) + DialogViewModel dialogviewmodel, + FileOpenViewModel fileopenviewmodel) { Pinning = new ActionCommand(o => { @@ -96,7 +98,7 @@ public WindowViewModel(IObjectProvider objectProvider, Version = $"v{Assembly.GetEntryAssembly().GetName().Version.ToString(3)}"; - var fileDropped = DropMonitor.Dropped.Subscribe(OpenFile); + var fileDropped = DropMonitor.Dropped.Subscribe(async t => await OpenFile(t)); var isEmptyChecker = Views.ToObservableChangeSet() .ToCollection() .Select(items => items.Count) @@ -144,7 +146,7 @@ public void OpenFiles(IEnumerable files = null) OpenFile(new[] { new FileInfo(file) }); } - private async void OpenFile(IEnumerable files) + private async Task OpenFile(IEnumerable files) { OpenedFileCount = files.Count(); if (OpenedFileCount > 1) @@ -152,13 +154,15 @@ private async void OpenFile(IEnumerable files) //Here we can set the dialog window's message Dialog.text = "Would you like to tail these files?"; //Showing the dialog window - var msgResult = await DialogHost.Show(Dialog, DialogNames.EntireWindow); + await DialogHost.Show(Dialog, FileOpen.Id); + //Testing the pushed button if (Dialog.Button) { //Tailing multiple files _schedulerProvider.Background.Schedule(() => { + //await DialogHost.Show(Dialog, DialogNames.EntireWindow); try { _logger.Info($"Attempting to open '{files.Count()}' files"); @@ -199,6 +203,8 @@ private async void OpenFile(IEnumerable files) { OpenFile(files.ElementAt(0)); } + + return true; } private void Views_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) From 9e29ed48ab6867d93d40706c1b8aa6e9b4465433 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Magyar?= Date: Fri, 15 Apr 2016 22:10:13 +0200 Subject: [PATCH 11/11] Project output type has been changed. --- Source/TailBlazer/TailBlazer.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/TailBlazer/TailBlazer.csproj b/Source/TailBlazer/TailBlazer.csproj index 2841e18e..d6b414c9 100644 --- a/Source/TailBlazer/TailBlazer.csproj +++ b/Source/TailBlazer/TailBlazer.csproj @@ -5,7 +5,7 @@ Debug AnyCPU {EBF74AA2-F4C2-4AE9-A6CF-33F3414893B7} - Exe + WinExe Properties TailBlazer TailBlazer