public SearchViewModel(SearchInfo tail, Action<SearchViewModel> removeAction) { _tail = tail; RemoveCommand = new Command(()=> removeAction(this)); var counter = _tail.Latest .Select(lp => lp.Count) .Subscribe(count => Count = count); var counterTextFormatter = _tail.Latest .Select(lp => { var limited = lp as IHasLimitationOfLines; if (limited == null) { return lp.Count.ToString("#,###0"); } return limited.HasReachedLimit ? limited.Maximum.ToString("#,###0") : lp.Count.ToString("#,###0"); }) .Subscribe(countText => CountText = countText); ; var progressMonitor = _tail.Latest.OfType<IProgressInfo>().Subscribe(result => { Searching = result.IsSearching; Segments = result.Segments; SegmentsSearched = result.SegmentsCompleted; }); _cleanUp = new CompositeDisposable(progressMonitor, counter, counterTextFormatter); }
public SearchOptionsProxy(SearchMetadata searchMetadata, IEnumerable<Swatch> swatches, Action<SearchMetadata> removeAction) { Swatches = swatches; if (searchMetadata == null) throw new ArgumentNullException("searchMetadata"); if (swatches == null) throw new ArgumentNullException("swatches"); if (removeAction == null) throw new ArgumentNullException("removeAction"); _searchMetadata = searchMetadata; Highlight = _searchMetadata.Highlight; Filter = _searchMetadata.Filter; RemoveCommand = new Command(() => removeAction(searchMetadata)); }
public WindowViewModel(IObjectProvider objectProvider, IWindowFactory windowFactory, ILogger logger, IWindowsController windowsController, RecentFilesViewModel recentFilesViewModel, GeneralOptionsViewModel generalOptionsViewModel, ISchedulerProvider schedulerProvider) { _logger = logger; _windowsController = windowsController; RecentFiles = recentFilesViewModel; Views = new ObservableCollection<ViewContainer>(); GeneralOptions = generalOptionsViewModel; _schedulerProvider = schedulerProvider; _objectProvider = objectProvider; InterTabClient = new InterTabClient(windowFactory); DropMonitor = new FileDropMonitor(); OpenFileCommand = new Command(OpenFile); ShowInGitHubCommand = new Command(()=> Process.Start("https://github.com/RolandPheasant")); ZoomOutCommand= new Command(()=> { GeneralOptions.Scale = GeneralOptions.Scale + 5; }); ZoomInCommand = new Command(() => { GeneralOptions.Scale = GeneralOptions.Scale - 5; }); Version = "v" + Assembly.GetEntryAssembly().GetName().Version.ToString(3); var fileDropped = DropMonitor.Dropped.Subscribe(OpenFile); var isEmptyChecker = Views.ToObservableChangeSet() .ToCollection() .Select(items=>items.Count) .StartWith(0) .Select(count=>count==0) .Subscribe(isEmpty=> IsEmpty = isEmpty); var openRecent = recentFilesViewModel.OpenFileRequest .Subscribe(file => { MenuIsOpen = false; OpenFile(file); }); _cleanUp = new CompositeDisposable(recentFilesViewModel, isEmptyChecker, fileDropped, DropMonitor, openRecent, Disposable.Create(() => { Views.Select(vc => vc.Content) .OfType<IDisposable>() .ForEach(d=>d.Dispose()); })); }
// public ICommand OpenSearchOptionsCommand // { // get { return new Command(OpenSearchOptions); } // } public FileTailerViewModel([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] IRecentSearchCollection recentSearchCollection, [NotNull] ISearchMetadataCollection searchMetadataCollection, [NotNull] SearchOptionsViewModel searchOptionsViewModel, [NotNull] SearchHints searchHints) { if (logger == null) throw new ArgumentNullException("logger"); if (schedulerProvider == null) throw new ArgumentNullException("schedulerProvider"); if (fileWatcher == null) throw new ArgumentNullException("fileWatcher"); if (selectionMonitor == null) throw new ArgumentNullException("selectionMonitor"); if (clipboardHandler == null) throw new ArgumentNullException("clipboardHandler"); if (searchInfoCollection == null) throw new ArgumentNullException("searchInfoCollection"); if (inlineViewerFactory == null) throw new ArgumentNullException("inlineViewerFactory"); if (generalOptions == null) throw new ArgumentNullException("generalOptions"); if (searchMetadataCollection == null) throw new ArgumentNullException("searchMetadataCollection"); if (searchOptionsViewModel == null) throw new ArgumentNullException("searchOptionsViewModel"); if (searchHints == null) throw new ArgumentNullException("searchHints"); SelectionMonitor = selectionMonitor; Id = Guid.NewGuid(); SearchOptions = searchOptionsViewModel; SearchHints = searchHints; CopyToClipboardCommand = new Command(() => clipboardHandler.WriteToClipboard(selectionMonitor.GetSelectedText())); SelectedItemsCount = selectionMonitor.Selected.Connect().QueryWhenChanged(collection => collection.Count).ForBinding(); SearchCollection = new SearchCollection(searchInfoCollection, schedulerProvider); 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); }) .ObserveOn(schedulerProvider.Background) .DistinctUntilChanged(); IsLoading = searchInfoCollection.All.Take(1).Select(_ => false).StartWith(true).ForBinding(); //command to add the current search to the tail collection AddSearchCommand = new Command(() => { var text = SearchHints.SearchText; searchInfoCollection.Add(text); recentSearchCollection.Add(new RecentSearch(text)); SearchHints.SearchText = string.Empty; }, () => SearchHints.SearchText.IsLongerThanOrEqualTo(3)); //User feedback to show file size FileSizeText = fileWatcher.Latest.Select(fn => fn.Size) .Select(size => size.FormatWithAbbreviation()) .DistinctUntilChanged() .ForBinding(); //User feedback to guide them whilst typing SearchHint = this.WhenValueChanged(vm => vm.SearchHints.SearchText) .Select(text => { if (string.IsNullOrEmpty(text)) return "Type to search"; return text.Length < 3 ? "Enter at least 3 characters" : "Hit enter to search"; }).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)); var loader = lineScroller.Lines.Connect() .Transform(x => lineProxyFactory.Create(x), new ParallelisationOptions(ParallelType.Ordered, 5)) .Sort(SortExpressionComparer<LineProxy>.Ascending(proxy => proxy)) .ObserveOn(schedulerProvider.MainThread) .Bind(out _data) .DisposeMany() .Subscribe(changes => logger.Info("Rows changed."+ changes.Adds+" adds, "+changes.Removes+" removed"), ex => logger.Error(ex, "There is a problem with bind data")); //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(250)).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), lineProxyFactory); _cleanUp = new CompositeDisposable(lineScroller, loader, firstIndexMonitor, IsLoading, Count, LatestCount, FileSizeText, SearchHint, SelectedItemsCount, CanViewInline, InlineViewer, InlineViewerVisible, SearchCollection, searchInfoCollection, HighlightTail, UsingDarkTheme, searchHints, searchMetadataCollection, searchMetadataCollection, SelectionMonitor, SearchOptions, Disposable.Create(_userScrollRequested.OnCompleted) ); }
public InlineViewer([NotNull] InlineViewerArgs args, [NotNull] IClipboardHandler clipboardHandler, [NotNull] ISchedulerProvider schedulerProvider, [NotNull] ISelectionMonitor selectionMonitor) { if (args == null) throw new ArgumentNullException("args"); if (clipboardHandler == null) throw new ArgumentNullException("clipboardHandler"); if (schedulerProvider == null) throw new ArgumentNullException("schedulerProvider"); if (selectionMonitor == null) throw new ArgumentNullException("selectionMonitor"); SelectionMonitor = selectionMonitor; CopyToClipboardCommand = new Command(() => clipboardHandler.WriteToClipboard(selectionMonitor.GetSelectedText())); _isSettingScrollPosition = false; var lineProvider = args.LineProvider; var selectedChanged = args.SelectedChanged; var pageSize = this.WhenValueChanged(vm=>vm.PageSize); var scrollSelected = selectedChanged.Where(proxy => proxy != null) .CombineLatest(lineProvider, pageSize,(proxy, lp,pge) => new ScrollRequest(pge, proxy.Start)); var scrollUser = _userScrollRequested .Where(x=>!_isSettingScrollPosition) .Select(request => new ScrollRequest(ScrollReason.User, request.PageSize, request.FirstIndex)); var scroller= scrollSelected.Merge(scrollUser) .ObserveOn(schedulerProvider.Background) .DistinctUntilChanged(); var lineScroller = new LineScroller(lineProvider, scroller); Count = lineProvider.Select(lp=>lp.Count).ForBinding(); //load lines into observable collection var loader = lineScroller.Lines.Connect() .Transform(args.LineProxyFactory.Create) .Sort(SortExpressionComparer<LineProxy>.Ascending(proxy => proxy)) .ObserveOn(schedulerProvider.MainThread) .Bind(out _data) .DisposeMany() .Subscribe(); // track first visible index[required to set scroll extent] var firstIndexMonitor = lineScroller.Lines.Connect() .Buffer(TimeSpan.FromMilliseconds(250)).FlattenBufferResult() .ToCollection() .Select(lines => lines.Count == 0 ? 0 : lines.Select(l => l.Index).Max() - lines.Count + 1) .ObserveOn(schedulerProvider.MainThread) .Subscribe(first => { try { _isSettingScrollPosition = true; FirstIndex = first; } finally { _isSettingScrollPosition = false; } }); _cleanUp = new CompositeDisposable(lineScroller, loader, Count, firstIndexMonitor, SelectionMonitor, Disposable.Create(() => { _userScrollRequested.OnCompleted(); })); }