예제 #1
0
        public SearchInfoCollection(ISearchMetadataCollection searchMetadataCollection,
            ISearchMetadataFactory searchMetadataFactory,
            IFileWatcher fileWatcher)
        {
            _metadataCollection = searchMetadataCollection;
            _searchMetadataFactory = searchMetadataFactory;
            _fileWatcher = fileWatcher;

            //Add a complete file display
            All = _fileWatcher.Latest.Index().Replay(1).RefCount();

            //create a collection with 1 item, which is used to show entire file
            var systemSearches = new SourceCache<SearchInfo, string>(t => t.SearchText);
            systemSearches.AddOrUpdate(new SearchInfo("<All>", 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))
                .Transform(meta =>
                {
                    var latest = _fileWatcher.Latest
                        .Search(meta.BuildPredicate())
                        .Replay(1).RefCount();

                    return new SearchInfo(meta.SearchText, latest, SearchType.User);
                });

            //combine te results into a single collection
            Searches = systemSearches.Connect()
                    .Or(userSearches)
                    .AsObservableCache();

            _cleanUp = new CompositeDisposable(Searches, systemSearches);
        }
예제 #2
0
        public SearchInfoCollection(ISearchMetadataCollection searchMetadataCollection, IFileWatcher fileWatcher)
        {
            _metadataCollection = searchMetadataCollection;
            _fileWatcher        = fileWatcher;

            //Add a complete file display
            All = fileWatcher.Latest.Index().Replay(1).RefCount();

            //create a collection with 1 item, which is used to show entire file
            var systemSearches = new SourceCache <SearchInfo, string>(t => t.SearchText);

            systemSearches.AddOrUpdate(new SearchInfo("<All>", 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))
                               .Transform(meta =>
            {
                var latest = _fileWatcher.Latest
                             .Search(meta.BuildPredicate())
                             .Replay(1).RefCount();

                return(new SearchInfo(meta.SearchText, latest, SearchType.User));
            });

            //combine te results into a single collection
            Searches = systemSearches.Connect()
                       .Or(userSearches)
                       .AsObservableCache();

            _cleanUp = new CompositeDisposable(Searches, systemSearches);
        }
        public SearchInfoCollection(ISearchMetadataCollection searchMetadataCollection, IFileWatcher fileWatcher)
        {
            _metadataCollection = searchMetadataCollection;
            _fileWatcher = fileWatcher;

            //Add a complete file display
            All = fileWatcher.Latest.Index().Replay(1).RefCount();

            //create a collection with 1 item, which is used to show entire file
            var systemSearches = new SourceCache<SearchInfo, CaseInsensitiveString>(t => (CaseInsensitiveString)t.SearchText);
            systemSearches.AddOrUpdate(new SearchInfo("<All>", All, SearchType.All));

            //create a collection of all possible user filters
            var userSearches = searchMetadataCollection.Metadata
                .Connect(meta => meta.Filter)
                .IgnoreUpdateWhen((current,previous)=>current.Filter == previous.Filter)
                .Transform(meta =>
                {
                    var latest = _fileWatcher.Latest
                        .Search(s => s.Contains(meta.SearchText, StringComparison.OrdinalIgnoreCase))
                        .Replay(1).RefCount();

                    return new SearchInfo(meta.SearchText, latest, SearchType.User);
                });

            //combine te results into a single collection
            Searches = systemSearches.Connect()
                    .Or(userSearches)
                    .AsObservableCache();

            _cleanUp = new CompositeDisposable(Searches, systemSearches);
        }
        public CombinedSearchMetadataCollection([NotNull] ISearchMetadataCollection metadataCollection, [NotNull] IGlobalSearchOptions globalSearchOptions)
        {
            if (metadataCollection == null)
            {
                throw new ArgumentNullException(nameof(metadataCollection));
            }
            if (globalSearchOptions == null)
            {
                throw new ArgumentNullException(nameof(globalSearchOptions));
            }

            Local  = metadataCollection;
            Global = globalSearchOptions.Metadata;

            var cache = new SourceCache <SearchMetadata, string>(t => t.SearchText);

            ////Prioritise local before global and renumber
            var localItems = metadataCollection.Metadata.Connect().ToCollection().Select(items => items.ToArray()).StartWith(Enumerable.Empty <SearchMetadata>());

            var globalItems = globalSearchOptions.Metadata.Metadata.Connect().ToCollection().Select(items => items.ToArray()).StartWith(Enumerable.Empty <SearchMetadata>());

            var combiner = localItems.CombineLatest(globalItems, (local, global) => new { local, global }).Select(x => Combine(x.local, x.global)).Subscribe(uppdatedItems =>
            {
                cache.Edit(innerCache =>
                {
                    var toRemove = innerCache.Items.Except(uppdatedItems, SearchMetadata.SearchTextComparer).ToArray();
                    innerCache.Remove(toRemove);
                    innerCache.AddOrUpdate(uppdatedItems);
                });
            });

            Combined = cache.Connect().IgnoreUpdateWhen((current, previous) => current.Equals(previous)).AsObservableCache();

            _cleanUp = new CompositeDisposable(Combined, cache, combiner);
        }
예제 #5
0
        public InlineViewer Create(IObservable<ILineProvider> lineProvider,
            IObservable<LineProxy> selectedChanged, 
            ISearchMetadataCollection searchMetadataCollection)
        {
            var args = new InlineViewerArgs(lineProvider, selectedChanged, searchMetadataCollection);

            return _objectProvider.Get<InlineViewer>(new ExplictArg("args", args));
        }
        public InlineViewer Create(IObservable <ILineProvider> lineProvider,
                                   IObservable <LineProxy> selectedChanged,
                                   ISearchMetadataCollection searchMetadataCollection)
        {
            var args = new InlineViewerArgs(lineProvider, selectedChanged, searchMetadataCollection);

            return(_objectProvider.Get <InlineViewer>(new ExplictArg("args", args)));
        }
        public SearchInfoCollection(ISearchMetadataCollection metadataCollection)
        {
            //var filters = metadataCollection.Metadata
            //                    .Connect(m=>m.Filter)
            //                    .Transform(meta=>new SearchInfo(meta.SearchText,))

            Searches = _searches.AsObservableCache();
            _cleanUp = new CompositeDisposable(_searches, Searches);
        }
예제 #8
0
        public SearchInfoCollection(ISearchMetadataCollection metadataCollection)
        {
            //var filters = metadataCollection.Metadata
            //                    .Connect(m=>m.Filter)
            //                    .Transform(meta=>new SearchInfo(meta.SearchText,))

            Searches = _searches.AsObservableCache();
            _cleanUp = new CompositeDisposable(_searches, Searches);
        }
예제 #9
0
        public ISearchProxyCollection Create([NotNull] ISearchMetadataCollection metadataCollection, Guid id, Action <SearchMetadata> changeScopeAction)
        {
            if (metadataCollection == null)
            {
                throw new ArgumentNullException(nameof(metadataCollection));
            }

            return(new SearchProxyCollection(metadataCollection, id, changeScopeAction, SchedulerProvider, ColourProvider, IconsProvider, TextAssociationCollection, ThemeProvider));
        }
예제 #10
0
 public TextFormatter(ISearchMetadataCollection searchMetadataCollection)
 {
     _strings = searchMetadataCollection.Metadata
         .Connect(meta => meta.Highlight)
         .IgnoreUpdateWhen((current, previous) => SearchMetadata.EffectsHighlightComparer.Equals(current, previous))
         .QueryWhenChanged(query => query.Items.OrderBy(m => m.Position))
         .Replay(1)
         .RefCount();
 }
예제 #11
0
 public TextFormatter(ISearchMetadataCollection searchMetadataCollection)
 {
     _strings = searchMetadataCollection.Metadata
         .Connect(meta => meta.Highlight)
         .IgnoreUpdateWhen((current, previous) => current.Highlight == previous.Highlight)
         .QueryWhenChanged(query => query.Items.Select(si => si.SearchText))
         .Replay(1)
         .RefCount();
 }
예제 #12
0
 public LineMatches(ISearchMetadataCollection searchMetadataCollection)
 {
     _strings = searchMetadataCollection.Metadata
                .Connect()
                .IgnoreUpdateWhen((current, previous) => SearchMetadata.EffectsHighlightComparer.Equals(current, previous))
                .QueryWhenChanged(query => query.Items.OrderBy(si => si.Position))
                .Replay(1)
                .RefCount();
 }
예제 #13
0
 public LineMatches(ISearchMetadataCollection searchMetadataCollection)
 {
     _strings = searchMetadataCollection.Metadata
         .Connect(meta => meta.Filter)
         .IgnoreUpdateWhen((current, previous) => SearchMetadata.EffectsHighlightComparer.Equals(current, previous))
         .QueryWhenChanged(query => query.Items.Select(si => si))
         .Replay(1)
         .RefCount();
 }
예제 #14
0
 public TextFormatter(ISearchMetadataCollection searchMetadataCollection)
 {
     _strings = searchMetadataCollection.Metadata
                .Connect(meta => meta.Highlight)
                .IgnoreUpdateWhen((current, previous) => SearchMetadata.EffectsHighlightComparer.Equals(current, previous))
                .QueryWhenChanged(query => query.Items.OrderBy(m => m.Position))
                .Replay(1)
                .RefCount();
 }
        public SearchOptionsViewModel(ISearchMetadataCollection metadataCollection, ISchedulerProvider schedulerProvider)
        {
            //TODO: options for colour

            var swatches = new SwatchesProvider().Swatches;
            
            ReadOnlyObservableCollection<SearchOptionsProxy> data;

            var userOptions = metadataCollection.Metadata.Connect()
                .WhereReasonsAre(ChangeReason.Add, ChangeReason.Remove) //ignore updates because we update from here
                .Transform(meta => new SearchOptionsProxy(meta, swatches,m => metadataCollection.Remove(m.SearchText)))
                .SubscribeMany(so =>
                {
                    //when a value changes, write the original value back to the cache
                    return so.WhenAnyPropertyChanged()
                        .Subscribe(_ => metadataCollection.Add(new SearchMetadata(so.Text, so.Filter, so.Highlight)));
                })
                .Sort(SortExpressionComparer<SearchOptionsProxy>.Ascending(proxy=>proxy.Text))
                .ObserveOn(schedulerProvider.MainThread)
                .Bind(out data)
                .Subscribe();

            Data = data;

            AddSearchCommand = new Command(() =>
            {
                    metadataCollection.Add(new SearchMetadata(SearchText,false,true));
                    SearchText = string.Empty;

            }, () => SearchText.IsLongerThanOrEqualTo(3) && !metadataCollection.Metadata.Lookup((CaseInsensitiveString)SearchText).HasValue);


            var commandRefresher = this.WhenValueChanged(vm => vm.SearchText)
                                    .Subscribe(_ => ((Command) AddSearchCommand).Refresh());
            
            //User feedback to guide them whilst typing
            SearchHint = this.WhenValueChanged(vm => vm.SearchText)
                            .Select(text =>
                            {
                                if (string.IsNullOrEmpty(text)) return "Type to highlight";
                                return text.Length < 3 ? "Enter at least 3 characters" : "Hit enter for more options";
                            }).ForBinding();
            
            _cleanUp = new CompositeDisposable(commandRefresher, userOptions, SearchHint);
        }
예제 #16
0
        public GlobalSearchOptions(ISearchMetadataCollection metadata,
                                   ISearchStateToMetadataMapper converter,
                                   ISetting <SearchState[]> searchStateSettings)
        {
            Metadata = metadata;

            var loader = searchStateSettings.Value
                         .Take(1)
                         .Select(items => items.Select(state => converter.Map(state, true)))
                         .Subscribe(metadata.Add);

            var writer = metadata.Metadata.Connect()
                         .ToCollection()
                         .Select(metaData => metaData.ToArray())
                         .Throttle(TimeSpan.FromMilliseconds(250))
                         .Select(searchStateItems => searchStateItems.Select(converter.Map).ToArray())
                         .Subscribe(searchStateSettings.Write);

            _cleanUp = new CompositeDisposable(loader, writer);
        }
예제 #17
0
        public GlobalSearchOptions(ISearchMetadataCollection metadata,
            ISearchStateToMetadataMapper converter,
            ISetting<SearchState[]> searchStateSettings)
        {
            Metadata = metadata;

            var loader = searchStateSettings.Value
                .Take(1)
                .Select(items => items.Select(state => converter.Map(state,true)))
                .Subscribe(metadata.Add);

            var writer = metadata.Metadata.Connect()
                .ToCollection()
                .Select(metaData => metaData.ToArray())
                .Throttle(TimeSpan.FromMilliseconds(250))
                .Select(searchStateItems => searchStateItems.Select(converter.Map).ToArray())
                .Subscribe(searchStateSettings.Write);

            _cleanUp = new CompositeDisposable(loader, writer);
        }
예제 #18
0
        public InlineViewerArgs([NotNull] IObservable <ILineProvider> lineProvider,
                                [NotNull] IObservable <LineProxy> selectedChanged,
                                [NotNull] ISearchMetadataCollection searchMetadataCollection)
        {
            if (lineProvider == null)
            {
                throw new ArgumentNullException(nameof(lineProvider));
            }
            if (selectedChanged == null)
            {
                throw new ArgumentNullException(nameof(selectedChanged));
            }
            if (searchMetadataCollection == null)
            {
                throw new ArgumentNullException(nameof(searchMetadataCollection));
            }

            LineProvider             = lineProvider;
            SelectedChanged          = selectedChanged;
            SearchMetadataCollection = searchMetadataCollection;
        }
        public SearchOptionsViewModel(ISearchMetadataCollection metadataCollection, 
            ISchedulerProvider schedulerProvider,
            SearchHints searchHints)
        {
            SearchHints = searchHints;
            //TODO: options for colour

            var swatches = new SwatchesProvider().Swatches;
            
            ReadOnlyObservableCollection<SearchOptionsProxy> data;

            var userOptions = metadataCollection.Metadata.Connect()
                .WhereReasonsAre(ChangeReason.Add, ChangeReason.Remove) //ignore updates because we update from here
                .Transform(meta => new SearchOptionsProxy(meta, swatches,m => metadataCollection.Remove(m.SearchText)))
                .SubscribeMany(so =>
                {
                    //when a value changes, write the original value back to the cache
                    return so.WhenAnyPropertyChanged()
                        .Subscribe(_ => metadataCollection.Add(new SearchMetadata(so.Text, so.Filter, so.Highlight,so.UseRegex,so.IgnoreCase)));
                })
                .Sort(SortExpressionComparer<SearchOptionsProxy>.Ascending(proxy=>proxy.Text))
                .ObserveOn(schedulerProvider.MainThread)
                .Bind(out data)
                .Subscribe();

            Data = data;

            //command to add the current search to the tail collection
            var searchInvoker = SearchHints.SearchRequested.Subscribe(request =>
            {
                metadataCollection.Add(new SearchMetadata(request.Text, false, true, request.UseRegEx, true));
            });

            
            _cleanUp = new CompositeDisposable(searchInvoker, userOptions, searchInvoker);
        }
        public SearchInfoCollection(ICombinedSearchMetadataCollection combinedSearchMetadataCollection,
            ISearchMetadataFactory searchMetadataFactory,
            IFileWatcher fileWatcher)
        {
            _localMetadataCollection = combinedSearchMetadataCollection.Local;
            _combinedSearchMetadataCollection = combinedSearchMetadataCollection;
            _searchMetadataFactory = searchMetadataFactory;
            _fileWatcher = fileWatcher;

            var exclusionPredicate = combinedSearchMetadataCollection.Combined.Connect()
                    .IncludeUpdateWhen((current, previous) => !SearchMetadata.EffectsFilterComparer.Equals(current, previous))
                    .Filter(meta=> meta.IsExclusion)
                    .ToCollection()
                    .Select(searchMetadataItems =>
                    {
                        Func<string, bool> predicate = null;

                        if (searchMetadataItems.Count == 0)
                            return predicate;

                        var predicates = searchMetadataItems.Select(meta => meta.BuildPredicate()).ToArray();
                        predicate = str =>
                        {
                            return !predicates.Any(item => item(str));
                        };
                        return predicate;
                    }).StartWith((Func<string, bool>)null)
                    .Replay(1).RefCount();

            All = exclusionPredicate.Select(predicate =>
            {
                if (predicate==null)
                    return _fileWatcher.Latest.Index();

                return _fileWatcher.Latest.Search(predicate);

            }).Switch().Replay(1).RefCount();

            //create a collection with 1 item, which is used to show entire file
            var systemSearches = new SourceCache<SearchInfo, string>(t => t.SearchText);
            systemSearches.AddOrUpdate(new SearchInfo("<All>", false, All, SearchType.All));

            //create a collection of all possible user filters
            var userSearches = combinedSearchMetadataCollection.Combined
                .Connect(meta => meta.Filter)
                .IgnoreUpdateWhen((current,previous)=> SearchMetadata.EffectsFilterComparer.Equals(current, previous))
                .Transform(meta =>
                {
                    var latest = exclusionPredicate
                                .Select(exclpredicate =>
                                {
                                    Func<string, bool> resultingPredicate;
                                    if (exclpredicate == null)
                                    {
                                        resultingPredicate = meta.BuildPredicate();
                                    }
                                    else
                                    {
                                        var toMatch = meta.BuildPredicate();
                                        resultingPredicate =  str=> toMatch(str) && exclpredicate(str);
                                    }
                                    return _fileWatcher.Latest.Search(resultingPredicate);

                                })
                                .Switch()
                                .Replay(1).RefCount();

                    return new SearchInfo(meta.SearchText, meta.IsGlobal, latest, SearchType.User);
                });

            //combine te results into a single collection
            Searches = systemSearches.Connect()
                    .Or(userSearches)
                    .AsObservableCache();

            _cleanUp = new CompositeDisposable(Searches, systemSearches);
        }
 public GlobalSearchInfoCollection(ISearchMetadataCollection searchMetadataCollection, ILogger logger)
 {
     _searchMetadataCollection = searchMetadataCollection;
 }
예제 #22
0
        public SearchInfoCollection(ICombinedSearchMetadataCollection combinedSearchMetadataCollection,
                                    ISearchMetadataFactory searchMetadataFactory,
                                    IFileWatcher fileWatcher)
        {
            _localMetadataCollection          = combinedSearchMetadataCollection.Local;
            _combinedSearchMetadataCollection = combinedSearchMetadataCollection;
            _searchMetadataFactory            = searchMetadataFactory;
            _fileWatcher = fileWatcher;

            var exclusionPredicate = combinedSearchMetadataCollection.Combined.Connect()
                                     .IncludeUpdateWhen((current, previous) => !SearchMetadata.EffectsFilterComparer.Equals(current, previous))
                                     .Filter(meta => meta.IsExclusion)
                                     .ToCollection()
                                     .Select(searchMetadataItems =>
            {
                Func <string, bool> predicate = null;

                if (searchMetadataItems.Count == 0)
                {
                    return(predicate);
                }

                var predicates = searchMetadataItems.Select(meta => meta.BuildPredicate()).ToArray();
                predicate      = str =>
                {
                    return(!predicates.Any(item => item(str)));
                };
                return(predicate);
            }).StartWith((Func <string, bool>)null)
                                     .Replay(1).RefCount();

            All = exclusionPredicate.Select(predicate =>
            {
                if (predicate == null)
                {
                    return(_fileWatcher.Latest.Index());
                }

                return(_fileWatcher.Latest.Search(predicate));
            }).Switch().Replay(1).RefCount();

            //create a collection with 1 item, which is used to show entire file
            var systemSearches = new SourceCache <SearchInfo, string>(t => t.SearchText);

            systemSearches.AddOrUpdate(new SearchInfo("<All>", false, All, SearchType.All));

            //create a collection of all possible user filters
            var userSearches = combinedSearchMetadataCollection.Combined
                               .Connect(meta => meta.Filter)
                               .IgnoreUpdateWhen((current, previous) => SearchMetadata.EffectsFilterComparer.Equals(current, previous))
                               .Transform(meta =>
            {
                var latest = exclusionPredicate
                             .Select(exclpredicate =>
                {
                    Func <string, bool> resultingPredicate;
                    if (exclpredicate == null)
                    {
                        resultingPredicate = meta.BuildPredicate();
                    }
                    else
                    {
                        var toMatch        = meta.BuildPredicate();
                        resultingPredicate = str => toMatch(str) && exclpredicate(str);
                    }
                    return(_fileWatcher.Latest.Search(resultingPredicate));
                })
                             .Switch()
                             .Replay(1).RefCount();

                return(new SearchInfo(meta.SearchText, meta.IsGlobal, latest, SearchType.User));
            });

            //combine the results into a single collection
            Searches = systemSearches.Connect()
                       .Or(userSearches)
                       .AsObservableCache();

            _cleanUp = new CompositeDisposable(Searches, systemSearches);
        }
예제 #23
0
        public TailViewModel([NotNull] ILogger logger,
                             [NotNull] ISchedulerProvider schedulerProvider,
                             [NotNull] IEnumerable <IFileWatcher> fileWatcher,
                             [NotNull] ISelectionMonitor selectionMonitor,
                             [NotNull] IClipboardHandler clipboardHandler,
                             [NotNull] ISearchInfoCollection searchInfoCollection,
                             [NotNull] IInlineViewerFactory inlineViewerFactory,
                             [NotNull] ISetting <GeneralOptions> generalOptions,
                             [NotNull] ISearchMetadataCollection searchMetadataCollection,
                             [NotNull] SearchOptionsViewModel searchOptionsViewModel,
                             [NotNull] SearchHints searchHints)
        {
            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }
            if (schedulerProvider == null)
            {
                throw new ArgumentNullException(nameof(schedulerProvider));
            }
            if (fileWatcher == null)
            {
                throw new ArgumentNullException(nameof(fileWatcher));
            }
            if (selectionMonitor == null)
            {
                throw new ArgumentNullException(nameof(selectionMonitor));
            }
            if (clipboardHandler == null)
            {
                throw new ArgumentNullException(nameof(clipboardHandler));
            }
            if (searchInfoCollection == null)
            {
                throw new ArgumentNullException(nameof(searchInfoCollection));
            }
            if (inlineViewerFactory == null)
            {
                throw new ArgumentNullException(nameof(inlineViewerFactory));
            }
            if (generalOptions == null)
            {
                throw new ArgumentNullException(nameof(generalOptions));
            }
            if (searchMetadataCollection == null)
            {
                throw new ArgumentNullException(nameof(searchMetadataCollection));
            }
            if (searchOptionsViewModel == null)
            {
                throw new ArgumentNullException(nameof(searchOptionsViewModel));
            }
            if (searchHints == null)
            {
                throw new ArgumentNullException(nameof(searchHints));
            }

            _stateProvider = new TailViewPersister(this);

            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(enumerable[0].FullName));
            OpenFolderCommand = new Command(() => Process.Start(enumerable[0].Folder));

            UsingDarkTheme = generalOptions.Value
                             .ObserveOn(schedulerProvider.MainThread)
                             .Select(options => options.Theme == Theme.Dark)
                             .ForBinding();

            HighlightTail = generalOptions.Value
                            .ObserveOn(schedulerProvider.MainThread)
                            .Select(options => options.HighlightTail)
                            .ForBinding();

            HighlightDuration = generalOptions.Value
                                .ObserveOn(schedulerProvider.MainThread)
                                .Select(options => new Duration(TimeSpan.FromSeconds(options.HighlightDuration)))
                                .ForBinding();

            //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 = 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); });

            //User feedback to show file size
            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);

            //load lines into observable collection
            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 <LineProxy> .Ascending(proxy => proxy))
                         .ObserveOn(schedulerProvider.MainThread)
                         .Bind(out _data, 100)
                         .DisposeMany()
                         .LogErrors(logger)
                         .Subscribe();


            //monitor matching lines and start index,
            Count = searchInfoCollection.All
                    .GroupBy(t => t)
                    .Select(groupedProvider => groupedProvider.Key.Count)
                    .Scan(0, (i, providerCount) => i + providerCount)
                    .ForBinding();
            CountText = searchInfoCollection.All
                        .GroupBy(t => t)
                        .Select(groupedProvider => groupedProvider.Key.Count)
                        .Scan(0, (i, providerCount) => i + providerCount)
                        .Select(latestCount => $"{latestCount.ToString("##,###")} lines")
                        .ForBinding();
            //iterate over every items to evaluate the lines' count
            LatestCount = SearchCollection.Latest
                          .GroupBy(t => t)
                          .Do(Console.WriteLine)
                          .Scan(0, (acc, provider) =>
            {
                if (provider.Key is IndexCollection && provider.Key.NumberOfPreviousProvider == 0)
                {
                    acc = 0;
                }
                else if (provider.Key is FileSearchResult && provider.Key.NumberOfPreviousProvider == 0)
                {
                    acc = 0;
                }
                return(provider.Key.Count + acc);
            })
                          .ForBinding();

            ////track first visible index
            var firstIndexMonitor = lineScroller.Lines.Connect()
                                    .Buffer(TimeSpan.FromMilliseconds(25)).FlattenBufferResult()
                                    .ToCollection()
                                    .Select(lines => lines.Count == 0 ? 0 : lines.Select(l => l.Index).Max() - lines.Count + 1)
                                    .ObserveOn(schedulerProvider.MainThread)
                                    .Subscribe(first => { FirstIndex = first; });

            //Create objects required for inline viewing
            var isUserDefinedChanged = SearchCollection.WhenValueChanged(sc => sc.Selected)
                                       .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);

            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 firstVisibleRow = _data.ToObservableChangeSet().ToCollection()
                                  .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);

            _cleanUp = new CompositeDisposable(lineScroller,
                                               loader,
                                               firstIndexMonitor,
                                               FileStatus,
                                               Count,
                                               LatestCount,
                                               FileSizeText,
                                               CanViewInline,
                                               InlineViewer,
                                               InlineViewerVisible,
                                               SearchCollection,
                                               searchInfoCollection,
                                               HighlightTail,
                                               UsingDarkTheme,
                                               searchHints,
                                               searchMetadataCollection,
                                               searchMetadataCollection,
                                               SelectionMonitor,
                                               SearchOptions,
                                               searchInvoker,
                                               _userScrollRequested.SetAsComplete());
        }
        public SearchOptionsViewModel(ISearchMetadataCollection metadataCollection,
                                      ISearchMetadataFactory searchMetadataFactory,
                                      ISchedulerProvider schedulerProvider,
                                      IColourProvider colourProvider,
                                      IIconProvider iconsProvider,
                                      SearchHints searchHints)
        {
            SearchHints = searchHints;

            var proxyItems = metadataCollection.Metadata.Connect()
                             .WhereReasonsAre(ChangeReason.Add, ChangeReason.Remove) //ignore updates because we update from here
                             .Transform(meta =>
            {
                return(new SearchOptionsProxy(meta,
                                              colourProvider,
                                              new IconSelector(iconsProvider, schedulerProvider),
                                              m => metadataCollection.Remove(m.SearchText),
                                              iconsProvider.DefaultIconSelector,
                                              Id));
            })
                             .SubscribeMany(so =>
            {
                //when a value changes, write the original value back to the cache
                return(so.WhenAnyPropertyChanged()
                       .Select(_ => (SearchMetadata)so)
                       .Subscribe(metadataCollection.AddorUpdate));
            })
                             .AsObservableCache();

            var monitor = MonitorPositionalChanges()
                          .Subscribe(positionChangedArgs =>
            {
                positionChangedArgs.ForEach(metadataCollection.AddorUpdate);
            });


            //load data onto grid
            var collection = new ObservableCollectionExtended <SearchOptionsProxy>();

            var userOptions = proxyItems.Connect()
                              .Sort(SortExpressionComparer <SearchOptionsProxy> .Ascending(proxy => proxy.Position))
                              .ObserveOn(schedulerProvider.MainThread)
                              //force reset for each new or removed item dues to a bug in the underlying dragablz control which inserts in an incorrect position
                              .Bind(collection, new ObservableCollectionAdaptor <SearchOptionsProxy, string>(0))
                              .DisposeMany()
                              .Subscribe();

            Data = new ReadOnlyObservableCollection <SearchOptionsProxy>(collection);

            //command to add the current search to the tail collection
            var searchInvoker = SearchHints.SearchRequested.Subscribe(request =>
            {
                schedulerProvider.Background.Schedule(() =>
                {
                    var meta = searchMetadataFactory.Create(request.Text,
                                                            request.UseRegEx,
                                                            metadataCollection.NextIndex(),
                                                            false);
                    metadataCollection.AddorUpdate(meta);
                });
            });

            _cleanUp = new CompositeDisposable(searchInvoker,
                                               userOptions,
                                               searchInvoker,
                                               monitor,
                                               SearchHints);
        }
예제 #25
0
 public GlobalSearchInfoCollection(ISearchMetadataCollection searchMetadataCollection, ILogger logger)
 {
     _searchMetadataCollection = searchMetadataCollection;
 }
예제 #26
0
        public SearchProxyCollection(ISearchMetadataCollection metadataCollection,
            Guid id,
            Action<SearchMetadata> changeScopeAction,
            ISchedulerProvider schedulerProvider,
            IColourProvider colourProvider,
            IIconProvider iconsProvider,
            ITextAssociationCollection textAssociationCollection,
            IThemeProvider themeProvider)
        {
            var proxyItems = metadataCollection.Metadata.Connect()
                .WhereReasonsAre(ChangeReason.Add, ChangeReason.Remove) //ignore updates because we update from here
                .Transform(meta =>
                {
                    return new SearchOptionsProxy(meta,
                        changeScopeAction,
                        colourProvider,
                        themeProvider,
                        new IconSelector(iconsProvider, schedulerProvider),
                        m => metadataCollection.Remove(m.SearchText),
                        iconsProvider.DefaultIconSelector,
                        id);
                })
                .SubscribeMany(so =>
                {
                    //when a value changes, write the original value back to the metadata collection
                    var anyPropertyHasChanged = so.WhenAnyPropertyChanged()
                        .Select(_ => (SearchMetadata) so)
                        .Subscribe(metadataCollection.AddorUpdate);

                    //when an icon or colour has changed we need to record user choice so
                    //the same choice can be used again
                    var iconChanged = so.WhenValueChanged(proxy => proxy.IconKind, false).ToUnit();
                    var colourChanged = so.WhenValueChanged(proxy => proxy.HighlightHue, false).ToUnit();
                    var ignoreCaseChanged = so.WhenValueChanged(proxy => proxy.CaseSensitive, false).ToUnit();

                    var textAssociationChanged = iconChanged.Merge(colourChanged).Merge(ignoreCaseChanged)
                        .Throttle(TimeSpan.FromMilliseconds(250))
                        .Select(_ => new TextAssociation(so.Text, so.CaseSensitive, so.UseRegex, so.HighlightHue.Swatch,
                            so.IconKind.ToString(), so.HighlightHue.Name, DateTime.UtcNow))
                        .Subscribe(textAssociationCollection.MarkAsChanged);

                    return new CompositeDisposable(anyPropertyHasChanged, textAssociationChanged);
                })
                .AsObservableCache();

            Count = proxyItems.CountChanged.StartWith(0).ForBinding();

            var monitor = MonitorPositionalChanges().Subscribe(metadataCollection.Add);

            //load data onto grid
            var collection = new ObservableCollectionExtended<SearchOptionsProxy>();

            var includedLoader = proxyItems
                .Connect(proxy => !proxy.IsExclusion)
                .Sort(SortExpressionComparer<SearchOptionsProxy>.Ascending(proxy => proxy.Position))
                .ObserveOn(schedulerProvider.MainThread)
                //force reset for each new or removed item dues to a bug in the underlying dragablz control which inserts in an incorrect position
                .Bind(collection, new ObservableCollectionAdaptor<SearchOptionsProxy, string>(0))
                .DisposeMany()
                .Subscribe();

            ReadOnlyObservableCollection<SearchOptionsProxy> excluded;
            var excludedLoader = proxyItems
                .Connect(proxy => proxy.IsExclusion)
                .Sort(SortExpressionComparer<SearchOptionsProxy>.Ascending(proxy => proxy.Text))
                .ObserveOn(schedulerProvider.MainThread)
                //force reset for each new or removed item dues to a bug in the underlying dragablz control which inserts in an incorrect position
                .Bind(out excluded)
                .DisposeMany()
                .Subscribe();

            Excluded = excluded;
            Included = new ReadOnlyObservableCollection<SearchOptionsProxy>(collection);

            _cleanUp = new CompositeDisposable(proxyItems, includedLoader, excludedLoader, monitor);
        }
예제 #27
0
        public SearchProxyCollection(ISearchMetadataCollection metadataCollection,
            Guid id,
            Action<SearchMetadata> changeScopeAction,
            ISchedulerProvider schedulerProvider,
            IColourProvider colourProvider,
            IIconProvider iconsProvider,
            ITextAssociationCollection textAssociationCollection,
            IThemeProvider themeProvider)
        {
            var proxyItems = metadataCollection.Metadata.Connect()
                .WhereReasonsAre(ChangeReason.Add, ChangeReason.Remove) //ignore updates because we update from here
                .Transform(meta =>
                {
                    return new SearchOptionsProxy(meta,
                        changeScopeAction,
                        colourProvider,
                        themeProvider,
                        new IconSelector(iconsProvider, schedulerProvider),
                        m => metadataCollection.Remove(m.SearchText),
                        iconsProvider.DefaultIconSelector,
                        id);
                })
                .SubscribeMany(so =>
                {
                    //when a value changes, write the original value back to the metadata collection
                    var anyPropertyHasChanged = so.WhenAnyPropertyChanged()
                        .Select(_ => (SearchMetadata) so)
                        .Subscribe(metadataCollection.AddorUpdate);

                    //when an icon or colour has changed we need to record user choice so 
                    //the same choice can be used again
                    var iconChanged = so.WhenValueChanged(proxy => proxy.IconKind, false).ToUnit();
                    var colourChanged = so.WhenValueChanged(proxy => proxy.HighlightHue, false).ToUnit();
                    var ignoreCaseChanged = so.WhenValueChanged(proxy => proxy.CaseSensitive, false).ToUnit();

                    var textAssociationChanged = iconChanged.Merge(colourChanged).Merge(ignoreCaseChanged)
                        .Throttle(TimeSpan.FromMilliseconds(250))
                        .Select(_ => new TextAssociation(so.Text, so.CaseSensitive, so.UseRegex, so.HighlightHue.Swatch,
                            so.IconKind.ToString(), so.HighlightHue.Name, DateTime.UtcNow))
                        .Subscribe(textAssociationCollection.MarkAsChanged);

                    return new CompositeDisposable(anyPropertyHasChanged, textAssociationChanged);
                })
                .AsObservableCache();

            Count = proxyItems.CountChanged.StartWith(0).ForBinding();

            var monitor = MonitorPositionalChanges().Subscribe(metadataCollection.Add);
            
            //load data onto grid
            var collection = new ObservableCollectionExtended<SearchOptionsProxy>();

            var includedLoader = proxyItems
                .Connect(proxy => !proxy.IsExclusion)
                .Sort(SortExpressionComparer<SearchOptionsProxy>.Ascending(proxy => proxy.Position))
                .ObserveOn(schedulerProvider.MainThread)
                //force reset for each new or removed item dues to a bug in the underlying dragablz control which inserts in an incorrect position
                .Bind(collection, new ObservableCollectionAdaptor<SearchOptionsProxy, string>(0))
                .DisposeMany()
                .Subscribe();

            var excludedLoader = proxyItems
                .Connect(proxy => proxy.IsExclusion)
                .Sort(SortExpressionComparer<SearchOptionsProxy>.Ascending(proxy => proxy.Text))
                .ObserveOn(schedulerProvider.MainThread)
                //force reset for each new or removed item dues to a bug in the underlying dragablz control which inserts in an incorrect position
                .Bind(out var excluded)
                .DisposeMany()
                .Subscribe();


            Excluded = excluded;
            Included = new ReadOnlyObservableCollection<SearchOptionsProxy>(collection);

            _cleanUp = new CompositeDisposable(proxyItems, includedLoader, excludedLoader, monitor);
        }
예제 #28
0
        public SearchOptionsViewModel(ISearchMetadataCollection metadataCollection,
            ISearchMetadataFactory searchMetadataFactory,
            ISchedulerProvider schedulerProvider,
            IColourProvider colourProvider,
            IIconProvider iconsProvider,
            ITextAssociationCollection textAssociationCollection,
            SearchHints searchHints,
            IThemeProvider themeProvider)
        {
            SearchHints = searchHints;

            var proxyItems = metadataCollection.Metadata.Connect()
                .WhereReasonsAre(ChangeReason.Add, ChangeReason.Remove) //ignore updates because we update from here
                .Transform(meta =>
                {
                    return new SearchOptionsProxy(meta,
                        colourProvider,
                        themeProvider,
                        new IconSelector(iconsProvider, schedulerProvider),
                        m => metadataCollection.Remove(m.SearchText),
                        iconsProvider.DefaultIconSelector,
                        Id);
                })
                .SubscribeMany(so =>
                {
                    //when a value changes, write the original value back to the metadata collection
                    var anyPropertyHasChanged = so.WhenAnyPropertyChanged()
                        .Select(_ => (SearchMetadata) so)
                        .Subscribe(metadataCollection.AddorUpdate);

                    //when an icon or colour has changed we need to record user choice so
                    //the same choice can be used again
                    var iconChanged = so.WhenValueChanged(proxy => proxy.IconKind,false).ToUnit();
                    var colourChanged = so.WhenValueChanged(proxy => proxy.HighlightHue, false).ToUnit();
                    var ignoreCaseChanged = so.WhenValueChanged(proxy => proxy.IgnoreCase, false).ToUnit();

                    var textAssociationChanged = iconChanged.Merge(colourChanged).Merge(ignoreCaseChanged)
                                .Throttle(TimeSpan.FromMilliseconds(250))
                                .Select(_=> new TextAssociation(so.Text, so.IgnoreCase, so.UseRegex, so.HighlightHue.Swatch, so.IconKind.ToString(), so.HighlightHue.Name, DateTime.Now))
                                .Subscribe(textAssociationCollection.MarkAsChanged);

                    return new CompositeDisposable(anyPropertyHasChanged, textAssociationChanged);
                })
                .AsObservableCache();

            var monitor = MonitorPositionalChanges()
                .Subscribe(metadataCollection.Add);

            //load data onto grid
            var collection = new ObservableCollectionExtended<SearchOptionsProxy>();

            var userOptions = proxyItems.Connect()
                .Sort(SortExpressionComparer<SearchOptionsProxy>.Ascending(proxy => proxy.Position))
                .ObserveOn(schedulerProvider.MainThread)
                //force reset for each new or removed item dues to a bug in the underlying dragablz control which inserts in an incorrect position
                .Bind(collection, new ObservableCollectionAdaptor<SearchOptionsProxy, string>(0))
                .DisposeMany()
                .Subscribe();

            Data = new ReadOnlyObservableCollection<SearchOptionsProxy>(collection);

            //command to add the current search to the tail collection
            var searchInvoker = SearchHints.SearchRequested
                .ObserveOn(schedulerProvider.Background)
                .Subscribe(request =>
                {
                    var meta = searchMetadataFactory.Create(request.Text,
                        request.UseRegEx,
                        metadataCollection.NextIndex(),
                        false);
                    metadataCollection.AddorUpdate(meta);
                });

            _cleanUp = new CompositeDisposable(searchInvoker,
                userOptions,
                searchInvoker,
                monitor,
                SearchHints);
        }
예제 #29
0
        public TailViewModel([NotNull] ILogger logger,
                             [NotNull] ISchedulerProvider schedulerProvider,
                             [NotNull] IFileWatcher fileWatcher,
                             [NotNull] ISelectionMonitor selectionMonitor,
                             [NotNull] IClipboardHandler clipboardHandler,
                             [NotNull] ISearchInfoCollection searchInfoCollection,
                             [NotNull] IInlineViewerFactory inlineViewerFactory,
                             [NotNull] ISetting <GeneralOptions> generalOptions,
                             [NotNull] ISearchMetadataCollection searchMetadataCollection,
                             [NotNull] IStateBucketService stateBucketService,
                             [NotNull] SearchOptionsViewModel searchOptionsViewModel,
                             [NotNull] ITailViewStateRestorer restorer,
                             [NotNull] SearchHints searchHints,
                             [NotNull] ITailViewStateControllerFactory tailViewStateControllerFactory)
        {
            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }
            if (schedulerProvider == null)
            {
                throw new ArgumentNullException(nameof(schedulerProvider));
            }
            if (fileWatcher == null)
            {
                throw new ArgumentNullException(nameof(fileWatcher));
            }
            if (selectionMonitor == null)
            {
                throw new ArgumentNullException(nameof(selectionMonitor));
            }
            if (clipboardHandler == null)
            {
                throw new ArgumentNullException(nameof(clipboardHandler));
            }
            if (searchInfoCollection == null)
            {
                throw new ArgumentNullException(nameof(searchInfoCollection));
            }
            if (inlineViewerFactory == null)
            {
                throw new ArgumentNullException(nameof(inlineViewerFactory));
            }
            if (generalOptions == null)
            {
                throw new ArgumentNullException(nameof(generalOptions));
            }
            if (searchMetadataCollection == null)
            {
                throw new ArgumentNullException(nameof(searchMetadataCollection));
            }
            if (stateBucketService == null)
            {
                throw new ArgumentNullException(nameof(stateBucketService));
            }
            if (searchOptionsViewModel == null)
            {
                throw new ArgumentNullException(nameof(searchOptionsViewModel));
            }
            if (searchHints == null)
            {
                throw new ArgumentNullException(nameof(searchHints));
            }

            Name                     = fileWatcher.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));
            SearchMetadataCollection = searchMetadataCollection;

            var horizonalScrollArgs = new ReplaySubject <TextScrollInfo>(1);

            HorizonalScrollChanged = args =>
            {
                horizonalScrollArgs.OnNext(args);
            };

            _tailViewStateControllerFactory = tailViewStateControllerFactory;

            //Move these 2 highlight fields to a service as all views require them
            UsingDarkTheme = generalOptions.Value
                             .ObserveOn(schedulerProvider.MainThread)
                             .Select(options => options.Theme == Theme.Dark)
                             .ForBinding();

            HighlightTail = generalOptions.Value
                            .ObserveOn(schedulerProvider.MainThread)
                            .Select(options => options.HighlightTail)
                            .ForBinding();

            //this deals with state when loading the system at start up and at shut-down
            _persister = new TailViewPersister(this, restorer);

            //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();

            //command to add the current search to the tail collection
            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())
                           .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);

            MaximumChars = lineScroller.MaximumLines()
                           .ObserveOn(schedulerProvider.MainThread)
                           .ForBinding();

            //load lines into observable collection
            var lineProxyFactory = new LineProxyFactory(new TextFormatter(searchMetadataCollection), new LineMatches(searchMetadataCollection), horizonalScrollArgs.DistinctUntilChanged());

            var loader = lineScroller.Lines.Connect()
                         .LogChanges(logger, "Received")
                         .Transform(lineProxyFactory.Create, new ParallelisationOptions(ParallelType.Ordered, 3))
                         .LogChanges(logger, "Sorting")
                         .Sort(SortExpressionComparer <LineProxy> .Ascending(proxy => proxy))
                         .ObserveOn(schedulerProvider.MainThread)
                         .Bind(out _data, 100)
                         .LogChanges(logger, "Bound")
                         .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();

            ////track first visible index
            var firstIndexMonitor = lineScroller.Lines.Connect()
                                    .Buffer(TimeSpan.FromMilliseconds(25)).FlattenBufferResult()
                                    .ToCollection()
                                    .Select(lines => lines.Count == 0 ? 0 : lines.Select(l => l.Index).Max() - lines.Count + 1)
                                    .ObserveOn(schedulerProvider.MainThread)
                                    .Subscribe(first =>
            {
                FirstIndex = first;
            });


            //Create objects required for inline viewing
            var isUserDefinedChanged = SearchCollection.WhenValueChanged(sc => sc.Selected)
                                       .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);

            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());

            InlineViewer = inlineViewerFactory.Create(inline, this.WhenValueChanged(vm => vm.SelectedItem), searchMetadataCollection);

            _cleanUp = new CompositeDisposable(lineScroller,
                                               loader,
                                               firstIndexMonitor,
                                               FileStatus,
                                               Count,
                                               LatestCount,
                                               FileSizeText,
                                               CanViewInline,
                                               InlineViewer,
                                               InlineViewerVisible,
                                               SearchCollection,
                                               searchInfoCollection,
                                               HighlightTail,
                                               UsingDarkTheme,
                                               searchHints,
                                               searchMetadataCollection,
                                               SelectionMonitor,
                                               SearchOptions,
                                               searchInvoker,
                                               MaximumChars,
                                               _stateMonitor,
                                               horizonalScrollArgs.SetAsComplete(),
                                               _userScrollRequested.SetAsComplete());
        }
예제 #30
0
        public SearchOptionsViewModel(ISearchMetadataCollection metadataCollection,
                                      ISchedulerProvider schedulerProvider,
                                      SearchHints searchHints)
        {
            SearchHints = searchHints;
            //TODO: options for colour

            var swatches = new SwatchesProvider().Swatches;

            bool binding = false;

            var orderChanged = Observable.FromEventPattern <OrderChangedEventArgs>(
                h => PositionMonitor.OrderChanged += h,
                h => PositionMonitor.OrderChanged -= h)
                               .Throttle(TimeSpan.FromMilliseconds(125))
                               .Select(evt => evt.EventArgs)
                               .Where(args => args.PreviousOrder != null && args.NewOrder.Length == args.PreviousOrder.Length)
                               .Select(positionChangedArgs =>
            {
                //reprioritise filters and highlights
                return(positionChangedArgs.NewOrder
                       .OfType <SearchOptionsProxy>()
                       .Select((item, index) => new { Meta = (SearchMetadata)item, index })
                       //.Where(x => x.index != x.Meta.Position)
                       .Select(x => new SearchMetadata(x.Meta, x.index))
                       .ToArray());
            })
                               .Subscribe(positionChangedArgs =>
            {
                positionChangedArgs.ForEach(metadataCollection.AddorUpdate);
            });

            ReadOnlyObservableCollection <SearchOptionsProxy> data;

            var userOptions = metadataCollection.Metadata.Connect()
                              .WhereReasonsAre(ChangeReason.Add, ChangeReason.Remove) //ignore updates because we update from here
                              .Transform(meta => new SearchOptionsProxy(meta, swatches, m => metadataCollection.Remove(m.SearchText)))
                              .SubscribeMany(so =>
            {
                //when a value changes, write the original value back to the cache
                return(so.WhenAnyPropertyChanged()
                       .Select(_ => new SearchMetadata(so.Position, so.Text, so.Filter, so.Highlight, so.UseRegex, so.IgnoreCase))
                       .Subscribe(metadataCollection.AddorUpdate));
            })
                              .Sort(SortExpressionComparer <SearchOptionsProxy> .Ascending(proxy => proxy.Position))

                              .ObserveOn(schedulerProvider.MainThread)
                              .Bind(out data)
                              .Subscribe();

            Data = data;

            //command to add the current search to the tail collection
            var searchInvoker = SearchHints.SearchRequested.Subscribe(request =>
            {
                schedulerProvider.Background.Schedule(() =>
                {
                    metadataCollection.AddorUpdate(new SearchMetadata(metadataCollection.NextIndex(), request.Text, false, true, request.UseRegEx, true));
                });
            });


            _cleanUp = new CompositeDisposable(searchInvoker,
                                               userOptions,
                                               searchInvoker,
                                               orderChanged);
        }
예제 #31
0
        public SearchOptionsViewModel(ISearchMetadataCollection metadataCollection, 
            ISchedulerProvider schedulerProvider,
            SearchHints searchHints)
        {
            SearchHints = searchHints;
            //TODO: options for colour

            var swatches = new SwatchesProvider().Swatches;

            bool binding = false;

            var orderChanged = Observable.FromEventPattern<OrderChangedEventArgs>(
                                            h => PositionMonitor.OrderChanged += h,
                                            h => PositionMonitor.OrderChanged -= h)
                                    .Select(evt => evt.EventArgs)
                                    .Where(args=>args.PreviousOrder!=null && args.NewOrder.Length == args.PreviousOrder.Length)
                                    .Select(positionChangedArgs =>
                                    {
                                            //reprioritise filters and highlights
                                            return positionChangedArgs.NewOrder
                                            .OfType<SearchOptionsProxy>()
                                            .Select((item, index) => new {Meta=(SearchMetadata)item, index})
                                            //.Where(x => x.index != x.Meta.Position)
                                            .Select(x => new SearchMetadata(x.Meta, x.index))
                                            .ToArray();
                                    })
                                    .Subscribe(positionChangedArgs =>
                                    {
                                       
                                        positionChangedArgs.ForEach(metadataCollection.AddorUpdate);
                                    });

            ReadOnlyObservableCollection<SearchOptionsProxy> data;

            var userOptions = metadataCollection.Metadata.Connect()
                .WhereReasonsAre(ChangeReason.Add, ChangeReason.Remove) //ignore updates because we update from here
                .Transform(meta => new SearchOptionsProxy(meta, swatches, m => metadataCollection.Remove(m.SearchText)))
                .SubscribeMany(so =>
                {
                    //when a value changes, write the original value back to the cache
                    return so.WhenAnyPropertyChanged()

                        .Subscribe(_ =>metadataCollection.AddorUpdate(new SearchMetadata(metadataCollection.Metadata.Count,
                                    so.Text, so.Filter, so.Highlight, so.UseRegex, so.IgnoreCase)));
                })
                .Sort(SortExpressionComparer<SearchOptionsProxy>.Ascending(proxy => proxy.Position))

                .ObserveOn(schedulerProvider.MainThread)
                .Bind(out data)
                .Subscribe();
            
            Data = data;

            //command to add the current search to the tail collection
            var searchInvoker = SearchHints.SearchRequested.Subscribe(request =>
            {
                schedulerProvider.Background.Schedule(() =>
                {
                    metadataCollection.AddorUpdate(new SearchMetadata(metadataCollection.NextIndex(), request.Text, false, true, request.UseRegEx, true));
                });
            });
        
            
            _cleanUp = new CompositeDisposable(searchInvoker, 
                userOptions, 
                searchInvoker,
                orderChanged);
        }
예제 #32
0
        public SearchOptionsViewModel(ISearchMetadataCollection metadataCollection,
                                      ISearchMetadataFactory searchMetadataFactory,
                                      ISchedulerProvider schedulerProvider,
                                      IColourProvider colourProvider,
                                      IIconProvider iconsProvider,
                                      ITextAssociationCollection textAssociationCollection,
                                      SearchHints searchHints)
        {
            SearchHints = searchHints;

            var proxyItems = metadataCollection.Metadata.Connect()
                             .WhereReasonsAre(ChangeReason.Add, ChangeReason.Remove) //ignore updates because we update from here
                             .Transform(meta =>
            {
                return(new SearchOptionsProxy(meta,
                                              colourProvider,
                                              new IconSelector(iconsProvider, schedulerProvider),
                                              m => metadataCollection.Remove(m.SearchText),
                                              iconsProvider.DefaultIconSelector,
                                              Id));
            })
                             .SubscribeMany(so =>
            {
                //when a value changes, write the original value back to the metadata collection
                var anyPropertyHasChanged = so.WhenAnyPropertyChanged()
                                            .Select(_ => (SearchMetadata)so)
                                            .Subscribe(metadataCollection.AddorUpdate);

                //when an icon or colour has changed we need to record user choice so
                //the same choice can be used again
                var iconChanged       = so.WhenValueChanged(proxy => proxy.IconKind, false).ToUnit();
                var colourChanged     = so.WhenValueChanged(proxy => proxy.HighlightHue, false).ToUnit();
                var ignoreCaseChanged = so.WhenValueChanged(proxy => proxy.IgnoreCase, false).ToUnit();

                var textAssociationChanged = iconChanged.Merge(colourChanged).Merge(ignoreCaseChanged)
                                             .Throttle(TimeSpan.FromMilliseconds(250))
                                             .Select(_ => new TextAssociation(so.Text, so.IgnoreCase, so.UseRegex, so.HighlightHue.Swatch, so.IconKind.ToString(), so.HighlightHue.Name, DateTime.Now))
                                             .Subscribe(textAssociationCollection.MarkAsChanged);

                return(new CompositeDisposable(anyPropertyHasChanged, textAssociationChanged));
            })
                             .AsObservableCache();

            var monitor = MonitorPositionalChanges()
                          .Subscribe(metadataCollection.Add);


            //load data onto grid
            var collection = new ObservableCollectionExtended <SearchOptionsProxy>();

            var userOptions = proxyItems.Connect()
                              .Sort(SortExpressionComparer <SearchOptionsProxy> .Ascending(proxy => proxy.Position))
                              .ObserveOn(schedulerProvider.MainThread)
                              //force reset for each new or removed item dues to a bug in the underlying dragablz control which inserts in an incorrect position
                              .Bind(collection, new ObservableCollectionAdaptor <SearchOptionsProxy, string>(0))
                              .DisposeMany()
                              .Subscribe();

            Data = new ReadOnlyObservableCollection <SearchOptionsProxy>(collection);

            //command to add the current search to the tail collection
            var searchInvoker = SearchHints.SearchRequested
                                .ObserveOn(schedulerProvider.Background)
                                .Subscribe(request =>
            {
                var meta = searchMetadataFactory.Create(request.Text,
                                                        request.UseRegEx,
                                                        metadataCollection.NextIndex(),
                                                        false);
                metadataCollection.AddorUpdate(meta);
            });

            _cleanUp = new CompositeDisposable(searchInvoker,
                                               userOptions,
                                               searchInvoker,
                                               monitor,
                                               SearchHints);
        }