/// <summary>
        /// キーボード操作を登録
        /// </summary>
        /// <param name="keyReceiver"></param>
        /// <param name="client"></param>
        private void RegisterKeyReceiver(ClientWindowViewModel parent)
        {
            var keyReceiver = parent.KeyReceiver;

            var pageFilter = keyReceiver.AddPreFilter(x =>
                                                      (client.SelectedPage.Value == PageType.Catalog));

            var cursorFilter = keyReceiver.AddPreFilter(x =>
            {
                if (client.SelectedPage.Value != PageType.Catalog)
                {
                    return(false);
                }
                return(!(x.FocusedControl is TextBox));
            });

            var buttonFilter = keyReceiver.AddPreFilter(x =>
            {
                if (client.SelectedPage.Value != PageType.Catalog)
                {
                    return(false);
                }
                return(!(x.FocusedControl is ButtonBase) && !(x.FocusedControl is TextBox));
            });


            keyReceiver.Register(Key.PageUp, (t, key)
                                 => this.RequestScrollAction?.Invoke(new Vector(0, -0.8)),
                                 pageFilter, isPreview: true);
            keyReceiver.Register(Key.PageDown, (t, key)
                                 => this.RequestScrollAction?.Invoke(new Vector(0, 0.8)),
                                 pageFilter, isPreview: true);

            keyReceiver.Register(Key.Up, (t, key)
                                 => this.RequestScrollAction?.Invoke(new Vector(0, -0.2)),
                                 pageFilter, isPreview: true);
            keyReceiver.Register(Key.Down, (t, key)
                                 => this.RequestScrollAction?.Invoke(new Vector(0, 0.2)),
                                 pageFilter, isPreview: true);

            keyReceiver.Register(Key.Home, (t, key)
                                 => this.RequestScrollAction?.Invoke(new Vector(0, double.NegativeInfinity)),
                                 pageFilter, isPreview: true);
            keyReceiver.Register(Key.End, (t, key)
                                 => this.RequestScrollAction?.Invoke(new Vector(0, double.PositiveInfinity)),
                                 pageFilter, isPreview: true);



            keyReceiver.Register(Key.A, (t, key) =>
            {
                if (this.SelectedItems.Count != this.client.Length.Value)
                {
                    this.client.SelectAllAsync().FireAndForget();
                }
                else
                {
                    this.SelectedItems.Clear();
                }
            }, pageFilter, modifier: ModifierKeys.Control);


            keyReceiver.Register(Key.N, (t, key) => this.SelectedItems.Clear(),
                                 pageFilter, modifier: ModifierKeys.Control);

            keyReceiver.Register(Key.C,
                                 (t, key) => this.parent.Core.CopySelectedItemsPath(this.SelectedItems),
                                 pageFilter, modifier: ModifierKeys.Control);

            keyReceiver.Register(Key.T, (t, key) => this.parent.ShowTagSelector(null),
                                 cursorFilter, modifier: ModifierKeys.Control);


            keyReceiver.Register(Key.Apps, (t, key) =>
            {
                if (!parent.IsPaneFixed.Value)
                {
                    parent.ToggleInformationPane();
                }
            }, cursorFilter);

            keyReceiver.Register(k => k >= Key.A && k <= Key.Z,
                                 (t, key) => this.SetTag(((char)(key - Key.A + 'a')).ToString()),
                                 cursorFilter);


            keyReceiver.Register(Key.Delete,
                                 async(t, key) => await this.client.DeleteSelectedFiles(false),
                                 cursorFilter);

            keyReceiver.Register(Key.Delete,
                                 async(t, key) => await this.client.DeleteSelectedFiles(true),
                                 cursorFilter, modifier: ModifierKeys.Control);

            keyReceiver.Register(Key.F5, (t, key) => this.client.Refresh(), cursorFilter);
        }
        public CatalogPageViewModel(ClientWindowViewModel parent)
        {
            this.parent  = parent;
            this.client  = parent.Client;
            this.library = parent.Library;
            var core = parent.Core;

            this.Length = client.Length.ToReadOnlyReactiveProperty().AddTo(this.Disposables);

            this.IsInSelecting = this.client.SelectedItemsCount
                                 .Select(x => x > 0)
                                 .ToReadOnlyReactiveProperty()
                                 .AddTo(this.Disposables);

            //表示中のインデックス
            this.StartIndex = this.client
                              .CatalogIndex
                              .Select(x => (x < int.MaxValue) ? (int)x : int.MaxValue)
                              .ToReactiveProperty()
                              .AddTo(this.Disposables);

            this.StartIndex
            .Subscribe(x => this.client.CatalogIndex.Value = x)
            .AddTo(this.Disposables);

            this.DisplayIndex = this.StartIndex.Select(x => x + 1).ToReactiveProperty().AddTo(this.Disposables);
            this.DisplayIndex.Subscribe(x => this.StartIndex.Value = x - 1).AddTo(this.Disposables);

            this.ThumbnailSize = core.ObserveProperty(x => x.ThumbNailSize)
                                 .Select(x => (double)x)
                                 .ToReactiveProperty().AddTo(this.Disposables);

            this.ThumbnailViewSize = this.ThumbnailSize
                                     .Select(x => new Size(x, x))
                                     .ToReadOnlyReactiveProperty()
                                     .AddTo(this.Disposables);

            this.ImagePropertiesVisibility = this.ThumbnailSize
                                             .Select(x => VisibilityHelper.Set(x > 128)).ToReactiveProperty().AddTo(this.Disposables);

            this.ThumbnailMargin = this.ThumbnailSize
                                   .Select(x => new Thickness((x < 128) ? 1 : (x < 256) ? 2 : 4))
                                   .ToReactiveProperty().AddTo(this.Disposables);

            this.IsRefreshEnabled = this.client.IsStateChanging
                                    .Select(x => !x)
                                    .ToReadOnlyReactiveProperty()
                                    .AddTo(this.Disposables);

            this.IsRenderingEnabled = this.client.IsCatalogRenderingEnabled
                                      .CombineLatest(this.client.SelectedPage, (e, p) => e && p == PageType.Catalog)
                                      .ToReadOnlyReactiveProperty(true)
                                      .AddTo(this.Disposables);


            //戻ってきたときにサムネイル再読み込み
            client.BackHistoryCount
            .Pairwise()
            .CombineLatest(client.SelectedPage,
                           (history, page) => history.OldItem > history.NewItem && page == PageType.Catalog)
            .Where(x => x)
            .Subscribe(_ => this.RefreshTrigger = !this.RefreshTrigger)
            .AddTo(this.Disposables);

            client.CacheUpdated
            .SkipUntil(client.StateChanged)
            .Take(1)
            .Repeat()
            .Subscribe(_ => this.RefreshTrigger = !this.RefreshTrigger)
            .AddTo(this.Disposables);


            //スクロールが落ち着いたら再読み込み
            this.StartIndex
            .Throttle(TimeSpan.FromMilliseconds(3000))
            .ObserveOnUIDispatcher()
            .Subscribe(_ => this.RefreshTrigger = !this.RefreshTrigger)
            .AddTo(this.Disposables);

            //スクロール位置復元
            this.client.CatalogScrollIndex
            .Subscribe(x => this.ScrollToIndexAction?.Invoke((int)x))
            .AddTo(this.Disposables);

            //サムネイルクリック
            this.ItemClickCommand = new ReactiveCommand()
                                    .WithSubscribe(context => this.SelectOrShow(context, true), this.Disposables);

            //選択
            this.ItemSelectCommand = new ReactiveCommand()
                                     .WithSubscribe(context => this.SelectOrShow(context, false), this.Disposables);

            //ソート条件編集
            this.EditSortCommand = new ReactiveCommand()
                                   .WithSubscribe(x =>
            {
                var control = x as FrameworkElement;

                var content = new SortEditor()
                {
                    ItemsSource = this.client.GetSort(),
                };

                content.IsEnabledChanged += (o, e) =>
                {
                    var value = e.NewValue as bool?;
                    if (value.HasValue && !value.Value)
                    {
                        this.client.SetSort(content.SortSettings);
                    }
                };

                this.parent.PopupOwner.PopupDialog.Show(content,
                                                        new Thickness(double.NaN, 10.0, 0.0, double.NaN),
                                                        HorizontalAlignment.Right, VerticalAlignment.Bottom, control);
            }, this.Disposables);

            //すべて選択
            this.SelectAllCommand = new ReactiveCommand()
                                    .WithSubscribe(async _ => await this.client.SelectAllAsync(), this.Disposables);

            //選択をクリア
            this.SelectionClearCommand = this.IsInSelecting
                                         .ToReactiveCommand()
                                         .WithSubscribe(_ => this.SelectedItems.Clear(), this.Disposables);

            //グループ化
            this.GroupingCommand = this.client.SelectedItemsCount
                                   .CombineLatest(this.client.IsGroupMode, (c, g) => c > 1 && !g)
                                   .ToReactiveCommand()
                                   .WithSubscribe(_ => this.client.Grouping(), this.Disposables);

            //グループから退去
            this.RemoveFromGroupCommand = this.client.SelectedItemsCount
                                          .CombineLatest(this.client.IsGroupMode, (c, g) => c >= 1 && g)
                                          .ToReactiveCommand()
                                          .WithSubscribe(_ => this.client.RemoveFromGroup(), this.Disposables);

            this.SetToLeaderCommand = this.client.SelectedItemsCount
                                      .CombineLatest(this.client.IsGroupMode, (c, g) => c == 1 && g)
                                      .ToReactiveCommand()
                                      .WithSubscribe(_ => this.client.SetGroupLeader(), this.Disposables);

            this.RefreshCommand = new ReactiveCommand()
                                  .WithSubscribe(_ => this.client.Refresh(), this.Disposables);

            this.RegisterKeyReceiver(parent);
        }
Пример #3
0
        public ViewerPageViewModel(ClientWindowViewModel parent)
        {
            this.parent = parent;
            this.client = parent.Client;

            this.library = parent.Library;

            this.DisplayIndex = client.ViewerIndex
                                .Select(x => x + 1)
                                .ToReactiveProperty()
                                .AddTo(this.Disposables);

            this.DisplayIndex.Subscribe(x =>
            {
                client.ViewerIndex.Value = x - 1;
            })
            .AddTo(this.Disposables);

            this.Length = client.Length.ToReadOnlyReactiveProperty().AddTo(this.Disposables);

            this.randomNumber = new RandomNumber();
            this.IsRandom     = parent.Core
                                .ToReactivePropertyAsSynchronized(x => x.IsSlideshowRandom).AddTo(this.Disposables);

            this.IsRandom.Select(_ => Unit.Default)
            .Merge(this.Length.Select(_ => Unit.Default))
            .Subscribe(x =>
            {
                if (this.IsRandom.Value && this.Length.Value > 0)
                {
                    this.randomNumber.Length = (int)this.Length.Value;
                    this.randomNumber.Clear();
                    this.client.PrepareNext(this.randomNumber.GetNext());
                }
            })
            .AddTo(this.Disposables);

            this.client.ViewerCacheClearedTrigger
            .Subscribe(x =>
            {
                if (this.IsRandom.Value && this.Length.Value > 0)
                {
                    this.client.PrepareNext(this.randomNumber.GetNext());
                }
            })
            .AddTo(this.Disposables);



            this.ZoomFactor        = new ReactiveProperty <double>().AddTo(this.Disposables);
            this.DesiredZoomFactor = new ReactiveProperty <double>(0.0).AddTo(this.Disposables);

            this.CurrentZoomFactorPercent = this.ZoomFactor
                                            .Select(x => x * 100.0)
                                            .ToReactiveProperty()
                                            .AddTo(this.Disposables);

            this.DisplayZoomFactor = this.CurrentZoomFactorPercent.ToReactiveProperty().AddTo(this.Disposables);

            this.DisplayZoomFactor.Where(x => x != this.CurrentZoomFactorPercent.Value)
            .Subscribe(x => this.ChangeZoomFactor(x / 100.0))
            .AddTo(this.Disposables);

            this.UsePhysicalPixel = parent.Core
                                    .ObserveProperty(x => x.UseLogicalPixel)
                                    .Select(x => !x)
                                    .ToReadOnlyReactiveProperty()
                                    .AddTo(this.Disposables);

            this.ScalingMode = parent.Core
                               .ObserveProperty(x => x.ScalingMode)
                               .ToReadOnlyReactiveProperty()
                               .AddTo(this.Disposables);

            this.IsImageChanging = new ReactiveProperty <bool>().AddTo(this.Disposables);

            //拡大率表示ポップアップ
            this.ZoomFactorVisibility = this.ZoomFactor.Select(x => true)
                                        .Merge(this.ZoomFactor.Throttle(TimeSpan.FromMilliseconds(zoomFactorDisplayTime)).Select(x => false))
                                        .Where(x => !this.IsImageChanging.Value)
                                        .Merge(this.IsImageChanging.Where(x => x).Select(x => !x))
                                        .Select(x => VisibilityHelper.Set(x))
                                        .ToReactiveProperty(Visibility.Collapsed)
                                        .AddTo(this.Disposables);

            this.IsGifAnimationEnabled = parent.Core
                                         .ToReactivePropertyAsSynchronized(x => x.IsAnimatedGifEnabled)
                                         .AddTo(this.Disposables);


            this.IsFill = parent.Core
                          .ObserveProperty(x => x.IsSlideshowResizeToFill)
                          .ToReadOnlyReactiveProperty()
                          .AddTo(this.Disposables);

            this.IsZoomoutOnly = parent.Core
                                 .ObserveProperty(x => x.IsSlideshowResizingAlways)
                                 .Select(x => !x)
                                 .ToReadOnlyReactiveProperty()
                                 .AddTo(this.Disposables);

            parent.MouseExButtonPressed
            .Subscribe(x =>
            {
                if (parent.Core.UseExtendedMouseButtonsToSwitchImage &&
                    client.SelectedPage.Value == PageType.Viewer)
                {
                    if (x)
                    {
                        this.MoveRight();
                    }
                    else
                    {
                        this.MoveLeft();
                    }
                }
            })
            .AddTo(this.Disposables);



            this.ViewWidth = new ReactiveProperty <double>().AddTo(this.Disposables);
            this.ViewWidth.Subscribe(x => client.ViewWidth = x).AddTo(this.Disposables);
            this.ViewHeight = new ReactiveProperty <double>().AddTo(this.Disposables);
            this.ViewHeight.Subscribe(x => client.ViewHeight = x).AddTo(this.Disposables);

            this.IsInHorizontalMirror = new ReactiveProperty <bool>(false).AddTo(this.Disposables);
            this.IsInVerticalMirror   = new ReactiveProperty <bool>(false).AddTo(this.Disposables);
            this.IsAutoScalingEnabled = new ReactiveProperty <bool>(false).AddTo(this.Disposables);
            this.Orientation          = new ReactiveProperty <int>().AddTo(this.Disposables);

            this.IsScrollRequested = new ReactiveProperty <bool>().AddTo(this.Disposables);

            this.IsTopBarOpen  = new ReactiveProperty <bool>(false).AddTo(this.Disposables);
            this.IsTopBarFixed = parent.Core
                                 .ToReactivePropertyAsSynchronized(x => x.IsViewerPageTopBarFixed)
                                 .AddTo(this.Disposables);
            if (this.IsTopBarFixed.Value)
            {
                this.IsTopBarOpen.Value = true;
            }

            this.OpenPaneCommand = new ReactiveCommand()
                                   .WithSubscribe(_ => parent.TogglePane(OptionPaneType.ItemInfo), this.Disposables);

            this.TogglePaneCommand = new ReactiveCommand()
                                     .WithSubscribe(_ => this.TogglePane(), this.Disposables);

            this.TapCommand = new ReactiveCommand().AddTo(this.Disposables);

            var tapped = this.TapCommand.OfType <ViewerTapEventArgs>().Publish().RefCount();

            tapped
            .Subscribe(e =>
            {
                if (e.HolizontalRate < edgeTapThreshold)
                {
                    this.MoveLeft();
                }
                else if (e.HolizontalRate > (1.0 - edgeTapThreshold))
                {
                    this.MoveRight();
                }
            })
            .AddTo(this.Disposables);

            tapped
            .Where(_ => parent.Core.IsOpenNavigationWithSingleTapEnabled)
            .Throttle(TimeSpan.FromMilliseconds(500))
            .Subscribe(e =>
            {
                if (e.Count == 1 &&
                    parent.Core.IsOpenNavigationWithSingleTapEnabled &&
                    e.HolizontalRate >= edgeTapThreshold &&
                    e.HolizontalRate <= (1.0 - edgeTapThreshold) &&
                    (!this.IsTopBarFixed.Value || !this.IsTopBarOpen.Value))
                {
                    this.IsTopBarOpen.Toggle();
                }
            })
            .AddTo(this.Disposables);


            this.PointerMoveCommand = new ReactiveCommand()
                                      .WithSubscribe(x =>
            {
                var y = ((Point)x).Y;

                if (y < 100)
                {
                    this.IsTopBarOpen.Value    = true;
                    this.topBarOpenedByPointer = true;
                }
                else if (y > 150)
                {
                    if (this.topBarOpenedByPointer && !this.IsTopBarFixed.Value)
                    {
                        this.IsTopBarOpen.Value = false;
                    }
                    this.topBarOpenedByPointer = false;
                }
            }, this.Disposables);


            this.BackCommand = client.BackHistoryCount
                               .Select(x => x > 0)
                               .ToReactiveCommand()
                               .WithSubscribe(_ => client.Back(), this.Disposables);

            this.SplitViewButtonVisibility = parent.IsPaneFixed
                                             .Select(x => VisibilityHelper.Set(!x))
                                             .ToReactiveProperty()
                                             .AddTo(this.Disposables);

            this.IsSlideshowPlaying = this.client.SelectedPage
                                      .Select(_ => false)
                                      .ToReactiveProperty(false)
                                      .AddTo(this.Disposables);

            this.IsSlideshowPlaying.Subscribe(x =>
            {
                if (x)
                {
                    this.StartSlideShow();
                }
                else
                {
                    this.parent.IsFullScreen.Value = false;
                }
            })
            .AddTo(this.Disposables);

            this.SlideshowSubject = new Subject <Unit>().AddTo(this.Disposables);

            var slideshowSubscription = new SerialDisposable().AddTo(this.Disposables);

            this.parent.Core.ObserveProperty(x => x.SlideshowFlipTimeMillisec)
            .Subscribe(x =>
            {
                slideshowSubscription.Disposable = this.SlideshowSubject
                                                   .Throttle(TimeSpan.FromMilliseconds(x))
                                                   .Where(_ => this.IsSlideshowPlaying.Value)
                                                   .ObserveOnUIDispatcher()
                                                   .Subscribe(y =>
                {
                    if (this.IsSlideshowPlaying.Value)
                    {
                        this.MoveNext();
                    }
                });

                if (this.IsSlideshowPlaying.Value)
                {
                    this.SlideshowSubject.OnNext(Unit.Default);
                }
            })
            .AddTo(this.Disposables);



            // Transform Dialog

            this.IsTransformDialogEnabled = new ReactiveProperty <bool>(true).AddTo(this.Disposables);

            this.VerticalMirrorCommand = new ReactiveCommand()
                                         .WithSubscribe(_ => { this.VerticalMirror(); this.HidePopup(); }, this.Disposables);
            this.HorizontalMirrorCommand = new ReactiveCommand()
                                           .WithSubscribe(_ => { this.HorizontalMirror(); this.HidePopup(); }, this.Disposables);
            this.RotateCwCommand = new ReactiveCommand()
                                   .WithSubscribe(_ => { this.Rotate(1); this.HidePopup(); }, this.Disposables);
            this.RotateCcwCommand = new ReactiveCommand()
                                    .WithSubscribe(_ => { this.Rotate(-1); this.HidePopup(); }, this.Disposables);

            this.MoveToGroupCommand = this.Record.Select(x => x?.IsGroup ?? false).ToReactiveCommand()
                                      .WithSubscribe(_ => this.client.DisplayGroup(0), this.Disposables);

            this.CheckHorizontalScrollRequestFunction = () =>
            {
                var k = this.CheckKeyboardScrollModifier();

                return((Keyboard.IsKeyDown(Key.Right)) ? k
                    : (Keyboard.IsKeyDown(Key.Left)) ? -k
                    : 0);
            };

            this.CheckVerticalScrollRequestFunction = () =>
            {
                var k = this.CheckKeyboardScrollModifier();

                return((Keyboard.IsKeyDown(Key.Down)) ? k
                    : (Keyboard.IsKeyDown(Key.Up)) ? -k
                    : 0);
            };

            this.TopBarWheelAction = (o, e) =>
            {
                if (e.Delta > 0)
                {
                    this.MovePrev();
                }
                else if (e.Delta < 0)
                {
                    this.MoveNext();
                }
            };


            //画像変更ボタン
            this.MoveButtonVisibility = parent.Core
                                        .ObserveProperty(x => x.IsViewerMoveButtonDisabled)
                                        .Select(x => VisibilityHelper.Set(!x))
                                        .ToReadOnlyReactiveProperty()
                                        .AddTo(this.Disposables);


            this.IsLeftButtonEnter    = new ReactiveProperty <bool>(false).AddTo(this.Disposables);
            this.IsRightButtonEnter   = new ReactiveProperty <bool>(false).AddTo(this.Disposables);
            this.IsLeftButtonPressed  = new ReactiveProperty <bool>(false).AddTo(this.Disposables);
            this.IsRightButtonPressed = new ReactiveProperty <bool>(false).AddTo(this.Disposables);

            this.PointerMoveAction = (o, e) =>
            {
                if (this.IsDisposed)
                {
                    return;
                }
                var element = o as FrameworkElement;
                if (element == null)
                {
                    return;
                }
                var point = (Vector)e.GetPosition(element) / element.ActualWidth;

                if (point.X < edgeTapThreshold)
                {
                    this.IsLeftButtonEnter.Value = true;
                }
                else
                {
                    this.IsLeftButtonEnter.Value   = false;
                    this.IsLeftButtonPressed.Value = false;
                }
                if (point.X > (1.0 - edgeTapThreshold))
                {
                    this.IsRightButtonEnter.Value = true;
                }
                else
                {
                    this.IsRightButtonEnter.Value   = false;
                    this.IsRightButtonPressed.Value = false;
                }
            };
            this.PointerLeaveAction = (o, e) =>
            {
                if (this.IsDisposed)
                {
                    return;
                }
                this.IsLeftButtonEnter.Value    = false;
                this.IsRightButtonEnter.Value   = false;
                this.IsLeftButtonPressed.Value  = false;
                this.IsRightButtonPressed.Value = false;
            };
            this.PointerDownAction = (o, e) =>
            {
                if (this.IsDisposed)
                {
                    return;
                }
                var element = o as FrameworkElement;
                if (element == null)
                {
                    return;
                }
                var point = (Vector)e.GetPosition(element) / element.ActualWidth;

                this.IsLeftButtonPressed.Value  = point.X < edgeTapThreshold;
                this.IsRightButtonPressed.Value = point.X > (1.0 - edgeTapThreshold);
            };
            this.PointerUpAction = (o, e) =>
            {
                if (this.IsDisposed)
                {
                    return;
                }
                this.IsLeftButtonPressed.Value  = false;
                this.IsRightButtonPressed.Value = false;
            };

            //キーボード操作
            this.RegisterKeyReceiver(parent);
        }
Пример #4
0
        /// <summary>
        /// キーボード操作を登録
        /// </summary>
        /// <param name="keyReceiver"></param>
        /// <param name="client"></param>
        private void RegisterKeyReceiver(ClientWindowViewModel parent)
        {
            var keyReceiver = parent.KeyReceiver;

            var pageFilter = keyReceiver.AddPreFilter(x =>
                                                      (client.SelectedPage.Value == PageType.Viewer));

            var cursorFilter = keyReceiver.AddPreFilter(x =>
            {
                if (client.SelectedPage.Value != PageType.Viewer)
                {
                    return(false);
                }
                return(!(x.FocusedControl is TextBox));
            });

            var buttonFilter = keyReceiver.AddPreFilter(x =>
            {
                if (client.SelectedPage.Value != PageType.Viewer)
                {
                    return(false);
                }
                return(!(x.FocusedControl is ButtonBase) && !(x.FocusedControl is TextBox));
            });


            //var scrollDelta = 100;
            var zoom = 1.2;
            var shiftOrControlKey = new[] { ModifierKeys.Shift, ModifierKeys.Control };

            shiftOrControlKey.ForEach(m =>
            {
                keyReceiver.Register(
                    new[] { Key.Up, Key.Down, Key.Right, Key.Left },
                    (t, key) => this.ReceiveCursorKey(key, !this.CursorKeyForMove, zoom),
                    cursorFilter, isPreview: true, modifier: m);
            });


            keyReceiver.Register(
                new Key[] { Key.Up, Key.Down, Key.Right, Key.Left },
                (t, key) => this.ReceiveCursorKey(key, this.CursorKeyForMove, zoom),
                cursorFilter, isPreview: true);



            keyReceiver.Register(new[] { Key.Add, Key.OemPlus },
                                 (t, key) => this.ZoomImage(zoom), cursorFilter, modifier: ModifierKeys.Control);
            //keyReceiver.Register(k => (int)k == 187, (t, key) => this.ZoomImage(zoom),
            //    pageFilter, false, ModifierKeys.Control);

            keyReceiver.Register(new[] { Key.Subtract, Key.OemMinus },
                                 (t, key) => this.ZoomImage(1.0 / zoom), cursorFilter, modifier: ModifierKeys.Control);
            //keyReceiver.Register(k => (int)k == 189, (t, key) => this.ZoomImage(1.0 / zoom),
            //    pageFilter, false, ModifierKeys.Control);



            keyReceiver.Register(Key.PageUp, (t, key) => this.MovePrev(), pageFilter, isPreview: true);
            keyReceiver.Register(Key.PageDown, (t, key) => this.MoveNext(), pageFilter, isPreview: true);


            keyReceiver.Register(Key.Home, (t, key) => this.client.ViewerIndex.Value = 0,
                                 cursorFilter, isPreview: true);
            keyReceiver.Register(Key.End, (t, key) => this.client.ViewerIndex.Value = this.Length.Value - 1,
                                 cursorFilter, isPreview: true);


            keyReceiver.Register(Key.Escape, (t, key) =>
            {
                if (!this.IsTopBarOpen.Value && !this.parent.IsPaneOpen.Value)
                {
                    this.parent.IsFullScreen.Value = false;
                }
                else
                {
                    this.IsTopBarOpen.Value = false;
                }
            }, cursorFilter);


            keyReceiver.Register(new[] { Key.Space, Key.Enter },
                                 (t, key) => this.StartAutoScaling(), buttonFilter);
            //keyReceiver.Register(k => (int)k == 190, (t, key) => this.StartAutoScaling(), pageFilter);

            keyReceiver.Register(new[] { Key.Decimal, Key.OemPeriod },
                                 (t, key) => this.StartAutoScaling(), cursorFilter);


            keyReceiver.Register(new[] { Key.Space, Key.Enter },
                                 (t, key) => this.IsSlideshowPlaying.Toggle(), buttonFilter, modifier: ModifierKeys.Control);

            keyReceiver.Register(new[] { Key.Decimal, Key.OemPeriod },
                                 (t, key) => this.IsSlideshowPlaying.Toggle(), cursorFilter, modifier: ModifierKeys.Control);
            //keyReceiver.Register(k => (int)k == 190, (t, key) => this.StartSlideShow(),
            //    pageFilter, false, ModifierKeys.Control);



            keyReceiver.Register(new[] { Key.Add, Key.OemPlus },
                                 (t, key) => this.SetRating(true), cursorFilter);
            keyReceiver.Register(new[] { Key.Subtract, Key.OemMinus },
                                 (t, key) => this.SetRating(false), cursorFilter);
            //keyReceiver.Register(k => (int)k == 187, (t, key) => this.SetRating(true), pageFilter);
            //keyReceiver.Register(k => (int)k == 189, (t, key) => this.SetRating(false), pageFilter);

            keyReceiver.Register(k => k >= Key.A && k <= Key.Z,
                                 (t, key) => this.SetTagWithShortCut(((char)(key - Key.A + 'a')).ToString()),
                                 cursorFilter);


            keyReceiver.Register(Key.H, (t, key) => this.HorizontalMirror(),
                                 cursorFilter, modifier: ModifierKeys.Control);
            keyReceiver.Register(Key.V, (t, key) => this.VerticalMirror(),
                                 cursorFilter, modifier: ModifierKeys.Control);
            keyReceiver.Register(Key.E, (t, key) => this.Rotate(-1),
                                 cursorFilter, modifier: ModifierKeys.Control);
            keyReceiver.Register(Key.R, (t, key) => this.Rotate(1),
                                 cursorFilter, modifier: ModifierKeys.Control);

            keyReceiver.Register(Key.T, (t, key) => this.parent.ShowTagSelector(null),
                                 cursorFilter, modifier: ModifierKeys.Control);

            keyReceiver.Register(Key.P, (t, key) =>
            {
                if (!parent.IsPaneFixed.Value)
                {
                    parent.TogglePane(OptionPaneType.ItemInfo);
                }
            }, cursorFilter, modifier: ModifierKeys.Control);



            keyReceiver.Register(Key.S, (t, key) => this.IsRandom.Toggle(),
                                 cursorFilter, modifier: ModifierKeys.Control);


            keyReceiver.Register(Key.L, (t, key) =>
            {
                SharePathOperation.OpenExplorer(this.Record.Value?.FullPath);
            }, cursorFilter, modifier: ModifierKeys.Control);

            keyReceiver.Register(Key.C, (t, key) =>
            {
                SharePathOperation.CopyPath(this.Record.Value?.FullPath);
            }, cursorFilter, modifier: ModifierKeys.Control);

            keyReceiver.Register(Key.Apps, (t, key) => this.TogglePane(), cursorFilter);


            keyReceiver.Register(Key.G, (t, key) => this.client.DisplayGroup(0),
                                 cursorFilter, modifier: ModifierKeys.Control);


            keyReceiver.Register(Key.Delete,
                                 async(t, key) => await this.client.DeleteDisplayingFile(false),
                                 cursorFilter);

            keyReceiver.Register(Key.Delete,
                                 async(t, key) => await this.client.DeleteDisplayingFile(true),
                                 cursorFilter, modifier: ModifierKeys.Control);



            keyReceiver.Register(Key.F5, (t, key) => this.client.Refresh(), cursorFilter);

            keyReceiver.Register(Key.F11, (t, key) => this.parent.IsFullScreen.Toggle(), cursorFilter);

#if DEBUG
            keyReceiver.Register(Key.Divide, async(t, key) =>
            {
                var index = await this.client.FindIndexFromDatabaseAsync(this.Record.Value);
                MessageBox.Show((index + 1).ToString());
            }, cursorFilter);
#endif
        }
        public SearchPageViewModel(ClientWindowViewModel parent)
        {
            this.parent = parent;
            var client  = parent.Client;
            var library = parent.Library;
            var core    = parent.Core;

            var searcher = library.Searcher;

            this.HistoryList  = searcher.SearchHistory.ToReadOnlyReactiveCollection().AddTo(this.Disposables);
            this.FavoriteList = searcher.FavoriteSearchList.ToReadOnlyReactiveCollection().AddTo(this.Disposables);

            this.SelectedTab = new ReactiveProperty <TabMode>
                                   ((searcher.FavoriteSearchList.Count > 0 && core.LastSearchedFavorite)
                    ? TabMode.Favorite : TabMode.History)
                               .AddTo(this.Disposables);

            this.SelectedTab
            .Subscribe(x => core.LastSearchedFavorite = (x == TabMode.Favorite))
            .AddTo(this.Disposables);

            this.IsEditing = new ReactiveProperty <bool>(false).AddTo(this.Disposables);


            this.SelectHistoryCommand  = new ReactiveCommand().AddTo(this.Disposables);
            this.SelectFavoriteCommand = new ReactiveCommand().AddTo(this.Disposables);

            var hitoryItem = this.SelectHistoryCommand
                             .OfType <SearchInformation>()
                             .Select(x => x.Clone());

            var favoriteItem = this.SelectFavoriteCommand
                               .OfType <SearchInformation>();

            this.CurrentSearch = Observable
                                 .Merge(hitoryItem, favoriteItem)//, newItem)
                                 .ToReactiveProperty(SearchInformation.GenerateEmpty())
                                 .AddTo(this.Disposables);

            this.CurrentSearch
            .Subscribe(x => this.IsEditing.Value = (x != null && !x.Key.IsNullOrEmpty()))
            .AddTo(this.Disposables);

            this.IsThumbnailVisible = this.CurrentSearch
                                      .Select(x => x.DateLastUsed > default(DateTimeOffset))
                                      .ToReadOnlyReactiveProperty()
                                      .AddTo(this.Disposables);

            searcher.FavoriteSearchList
            .ObserveAddChanged()
            .Subscribe(x =>
            {
                if (this.CurrentSearch.Value == x)
                {
                    this.SelectedTab.Value = TabMode.Favorite;
                }
            })
            .AddTo(this.Disposables);

            searcher.FavoriteSearchList
            .ObserveRemoveChanged()
            .Subscribe(x =>
            {
                if (this.CurrentSearch.Value == x && this.SelectedTab.Value == TabMode.Favorite)
                {
                    this.CurrentSearch.Value = SearchInformation.GenerateEmpty();
                }
            })
            .AddTo(this.Disposables);

            this.CurrentSearchType = this.HistoryList
                                     .CollectionChangedAsObservable()
                                     .Merge(this.FavoriteList.CollectionChangedAsObservable())
                                     .Select(_ => this.CurrentSearch.Value)
                                     .Merge(this.CurrentSearch)
                                     .Select(x => this.HasFavoriteSearch(x) ? 1
                    : this.HasHistorySearch(x) ? 0 : 2)
                                     .ToReadOnlyReactiveProperty()
                                     .AddTo(this.Disposables);

            this.IsFavoriteSearch = this.CurrentSearchType
                                    .Select(x => x == 1)
                                    .ToReadOnlyReactiveProperty()
                                    .AddTo(this.Disposables);


            this.ClickHistoryCommand  = new ReactiveCommand().AddTo(this.Disposables);
            this.ClickFavoriteCommand = new ReactiveCommand().AddTo(this.Disposables);

            this.ClickHistoryCommand
            .Select(x => x as SearchInformation)
            .Where(x => x != null)
            .Subscribe(x =>
            {
                if (!this.IsEditing.Value ||
                    this.CurrentSearch.Value == null ||
                    this.CurrentSearch.Value.Key.IsNullOrEmpty() ||
                    this.CurrentSearch.Value.Key.Equals(x.Key))
                {
                    this.StartSearch(client, x);
                }
                else
                {
                    this.SelectHistoryCommand.Execute(x);
                }
            })
            .AddTo(this.Disposables);

            this.ClickFavoriteCommand
            .Select(x => x as SearchInformation)
            .Where(x => x != null)
            .Subscribe(x =>
            {
                if (!this.IsEditing.Value ||
                    this.CurrentSearch.Value == null ||
                    this.CurrentSearch.Value.Key.IsNullOrEmpty() ||
                    this.CurrentSearch.Value.Key.Equals(x.Key))
                {
                    this.StartSearch(client, x);
                }
                else
                {
                    this.SelectFavoriteCommand.Execute(x);
                }
            })
            .AddTo(this.Disposables);

            this.StartSearchCommand = new ReactiveCommand()
                                      .WithSubscribe(_ => this.StartSearch(client, this.CurrentSearch.Value), this.Disposables);

            this.AddCriteriaCommand = new ReactiveCommand()
                                      .WithSubscribe(_ => this.EditSearch(this.CurrentSearch.Value.Root), this.Disposables);

            this.ItemClickCommand = new ReactiveCommand()
                                    .WithSubscribe(item =>
            {
                var search = item as ISqlSearch;

                if (search != null)
                {
                    this.EditSearch(search);
                }
            }, this.Disposables);

            this.AddToFavoriteCommand = new ReactiveCommand()
                                        .WithSubscribe(_ =>
            {
                var item = this.CurrentSearch.Value;
                if (item == null)
                {
                    return;
                }

                if (this.HasFavoriteSearch(item))
                {
                    searcher.MarkSearchUnfavorite(item);
                }
                else
                {
                    searcher.MarkSearchFavorite(item);
                }
            }, this.Disposables);


            this.SwitchModeCommand = new ReactiveCommand()
                                     .WithSubscribe(_ =>
            {
                var item = this.CurrentSearch.Value;
                if (item == null)
                {
                    return;
                }

                item.Root.IsOr = !item.Root.IsOr;
            }, this.Disposables);

            this.NewSearchCommand = new ReactiveCommand()
                                    .WithSubscribe(_ => this.CurrentSearch.Value = SearchInformation.GenerateEmpty(),
                                                   this.Disposables);

            this.ShowFavoriteCommand = new ReactiveCommand()
                                       .WithSubscribe(_ => this.SelectedTab.Value = TabMode.Favorite, this.Disposables);
            this.ShowHistoryCommand = new ReactiveCommand()
                                      .WithSubscribe(_ => this.SelectedTab.Value = TabMode.History, this.Disposables);
        }