private async Task AskIfSave(bool cancel)
    {
        if (baseViewModel.IsModified)
        {
            var result = await messageBoxService.ShowDialog(new MessageBoxFactory <int>()
                                                            .SetTitle("Save changes")
                                                            .SetMainInstruction($"{Title} has unsaved changes")
                                                            .SetContent("Do you want to save them before picking the row?")
                                                            .WithNoButton(1)
                                                            .WithYesButton(2)
                                                            .WithCancelButton(0)
                                                            .Build());

            if (result == 0)
            {
                return;
            }
            if (result == 2)
            {
                ExecuteChangedCommand.Execute(null);
            }
        }
        if (cancel)
        {
            CloseCancel?.Invoke();
        }
        else
        {
            CloseOk?.Invoke();
        }
    }
        public NewItemDialogViewModel(ISolutionItemProvideService provider)
        {
            Dictionary <string, NewItemPrototypeGroup> groups = new();

            ItemPrototypes = new ObservableCollection <NewItemPrototypeGroup>();

            foreach (var item in provider.AllCompatible)
            {
                if (!groups.TryGetValue(item.GetGroupName(), out var group))
                {
                    group = new NewItemPrototypeGroup(item.GetGroupName());
                    groups[item.GetGroupName()] = group;
                    ItemPrototypes.Add(group);
                }

                var info = new NewItemPrototypeInfo(item);
                group.Add(info);
                FlatItemPrototypes.Add(info);
            }

            Accept = new DelegateCommand(() =>
            {
                CloseOk?.Invoke();
            });
            Cancel = new DelegateCommand(() =>
            {
                CloseCancel?.Invoke();
            });

            if (ItemPrototypes.Count > 0 && ItemPrototypes[0].Count > 0)
            {
                SelectedPrototype = ItemPrototypes[0][0];
            }
        }
 public void OnClose()
 {
     if (baseViewModel.IsModified)
     {
         AskIfSave(true).ListenErrors();
     }
     else
     {
         CloseCancel?.Invoke();
     }
 }
        public GenericSelectorDialogViewModel(IEnumerable <ColumnDescriptor> columns,
                                              IEnumerable <T> collection,
                                              Func <T, int> entryGetter,
                                              Func <T, string> index)
        {
            this.entryGetter = entryGetter;
            this.index       = index;
            items            = new SourceList <T>();
            ReadOnlyObservableCollection <T> l;
            var currentFilter = this.WhenValueChanged(t => t.SearchText).Select <string?, Func <T, bool> >(val =>
            {
                if (string.IsNullOrEmpty(val))
                {
                    return(model => true);
                }
                var lowerCase = val.ToLower();
                return(model => index(model).ToLower().Contains(lowerCase));
            });

            items
            .Connect()
            .Filter(currentFilter, ListFilterPolicy.ClearAndReplace)
            .Sort(Comparer <T> .Create((x, y) => entryGetter(x).CompareTo(entryGetter(y))))
            .Bind(out l)
            .Subscribe();
            FilteredItems = l;

            Columns = new ObservableCollection <ColumnDescriptor>();

            foreach (var column in columns)
            {
                Columns.Add(column);
            }

            items.AddRange(collection);

            Accept = new DelegateCommand(() =>
            {
                if (SelectedItem == null && FilteredItems.Count == 1)
                {
                    SelectedItem = FilteredItems[0];
                }
                CloseOk?.Invoke();
            }, () => SelectedItem != null || FilteredItems.Count == 1 || int.TryParse(SearchText, out _));
            Cancel = new DelegateCommand(() => CloseCancel?.Invoke());

            FilteredItems.ObserveCollectionChanges().Subscribe(_ => Accept.RaiseCanExecuteChanged());
            this.WhenPropertyChanged(t => t.SearchText).Subscribe(_ => Accept.RaiseCanExecuteChanged());
            this.WhenPropertyChanged(t => t.SelectedItem).Subscribe(_ => Accept.RaiseCanExecuteChanged());
        }
 public InputEntryProviderViewModel(string title, string description, T defaultValue, Func <T, bool>?isValid = null)
 {
     Description = description;
     entry       = defaultValue;
     Title       = title;
     Accept      = Save = new DelegateCommand(() =>
     {
         CloseOk?.Invoke();
     }, () => isValid == null || isValid(Entry)).ObservesProperty(() => Entry);
     Cancel = new DelegateCommand(() =>
     {
         CloseCancel?.Invoke();
     });
 }
 public RowPickerViewModel(ViewModelBase baseViewModel,
                           ITaskRunner taskRunner,
                           ISolutionItemSqlGeneratorRegistry queryGeneratorRegistry,
                           IClipboardService clipboardService,
                           IWindowManager windowManager,
                           IEventAggregator eventAggregator,
                           ISolutionItemEditorRegistry solutionItemEditorRegistry,
                           ISessionService sessionService,
                           IMessageBoxService messageBoxService,
                           ISolutionTasksService solutionTasksService,
                           bool noSaveMode = false)
 {
     this.baseViewModel = baseViewModel;
     this.solutionItemEditorRegistry = solutionItemEditorRegistry;
     this.sessionService             = sessionService;
     this.messageBoxService          = messageBoxService;
     this.noSaveMode = noSaveMode;
     Watch(baseViewModel, o => o.IsModified, nameof(Title));
     ExecuteChangedCommand = noSaveMode ? AlwaysDisabledCommand.Command : new AsyncAutoCommand(async() =>
     {
         baseViewModel.Save.Execute(null);
         eventAggregator.GetEvent <DatabaseTableChanged>().Publish(baseViewModel.TableDefinition.TableName);
         await taskRunner.ScheduleTask("Update session", async() => await sessionService.UpdateQuery(baseViewModel));
         if (solutionTasksService.CanReloadRemotely)
         {
             await solutionTasksService.ReloadSolutionRemotelyTask(baseViewModel.SolutionItem);
         }
     });
     CopyCurrentSqlCommand = new AsyncAutoCommand(async() =>
     {
         await taskRunner.ScheduleTask("Generating SQL",
                                       async() => { clipboardService.SetText((await baseViewModel.GenerateQuery()).QueryString); });
     });
     GenerateCurrentSqlCommand = new AsyncAutoCommand(async() =>
     {
         var sql    = await baseViewModel.GenerateQuery();
         var item   = new MetaSolutionSQL(new JustQuerySolutionItem(sql.QueryString));
         var editor = solutionItemEditorRegistry.GetEditor(item);
         await windowManager.ShowDialog((IDialog)editor);
     });
     PickSelected = new AsyncAutoCommand(async() =>
     {
         await AskIfSave(false);
     });
     Cancel = new DelegateCommand(() =>
     {
         CloseCancel?.Invoke();
     });
     Accept = PickSelected;
 }
예제 #7
0
 public StringPickerViewModel(string existing, bool acceptEmpty, bool multiline)
 {
     this.acceptEmpty = acceptEmpty;
     MultiLine        = multiline;
     content          = existing;
     Accept           = new DelegateCommand(() =>
     {
         CloseOk?.Invoke();
     }, () => acceptEmpty || !string.IsNullOrWhiteSpace(Content)).ObservesProperty(() => Content);
     Cancel = new DelegateCommand(() =>
     {
         CloseCancel?.Invoke();
     });
 }
예제 #8
0
        public NewItemDialogViewModel(ISolutionItemProvideService provider, ICurrentCoreVersion currentCore)
        {
            Dictionary <string, NewItemPrototypeGroup> groups = new();

            Categories = new ObservableCollection <NewItemPrototypeGroup>();

            bool coreIsSpecific = currentCore.IsSpecified;

            foreach (var item in provider.All)
            {
                if (!groups.TryGetValue(item.GetGroupName(), out var group))
                {
                    group = new NewItemPrototypeGroup(item.GetGroupName());
                    groups[item.GetGroupName()] = group;
                    Categories.Add(group);
                }

                bool isCompatible = item.IsCompatibleWithCore(currentCore.Current);

                if (!isCompatible && coreIsSpecific)
                {
                    continue;
                }

                var info = new NewItemPrototypeInfo(item, isCompatible);
                group.Add(info);
            }

            Accept = new DelegateCommand(() =>
            {
                CloseOk?.Invoke();
            });
            Cancel = new DelegateCommand(() =>
            {
                CloseCancel?.Invoke();
            });

            Categories.RemoveIf(c => c.Count == 0);

            if (Categories.Count > 0)
            {
                SelectedCategory = Categories[0];
            }

            if (Categories.Count > 0 && Categories[0].Count > 0)
            {
                SelectedPrototype = Categories[0][0];
            }
        }
예제 #9
0
        public NewItemDialogViewModel(IEnumerable <ISolutionItemProvider> items,
                                      ICurrentCoreVersion coreVersion)
        {
            ItemPrototypes = new ObservableCollection <NewItemPrototypeInfo>();

            foreach (var item in items.Where(i => i.IsCompatibleWithCore(coreVersion.Current)))
            {
                ItemPrototypes.Add(new NewItemPrototypeInfo(item));
            }

            Accept = new DelegateCommand(() =>
            {
                CloseOk?.Invoke();
            });
            Cancel = new DelegateCommand(() =>
            {
                CloseCancel?.Invoke();
            });
        }
예제 #10
0
        public ItemFromListProviderViewModel(Dictionary <int, SelectOption> items, bool asFlags, int?current = null)
        {
            this.asFlags = asFlags;
            RawItems     = new ObservableCollection <KeyValuePair <int, CheckableSelectOption> >();

            foreach (int key in items.Keys)
            {
                bool isSelected = current.HasValue && ((current == 0 && key == 0) || (key > 0) && (current & key) == key);
                var  item       = new KeyValuePair <int, CheckableSelectOption>(key, new CheckableSelectOption(items[key], isSelected));
                if (isSelected)
                {
                    SelectedItem = item;
                }
                RawItems.Add(item);
            }

            Columns = new ObservableCollection <ColumnDescriptor>
            {
                new("Key", "Key", 50),
                new("Name", "Value.Name"),
                new("Description", "Value.Description")
            };

            if (asFlags)
            {
                Columns.Insert(0, new ColumnDescriptor("", "Value.IsChecked", null, true));
            }

            this.items         = new CollectionViewSource();
            this.items.Source  = RawItems;
            this.items.Filter += ItemsOnFilter;

            if (items.Count == 0)
            {
                SearchText = current.HasValue ? current.Value.ToString() : "";
            }

            ShowItemsList = items.Count > 0;
            DesiredHeight = ShowItemsList ? 470 : 130;
            Accept        = new DelegateCommand(() => CloseOk?.Invoke());
            Cancel        = new DelegateCommand(() => CloseCancel?.Invoke());
        }
예제 #11
0
        public ItemFromListProviderViewModel(Dictionary <T, SelectOption>?items,
                                             IComparer <CheckableSelectOption <T> > comparer,
                                             Func <T, bool> shouldBeSelected,
                                             bool asFlags,
                                             T?current = default)
        {
            Items        = items;
            this.asFlags = asFlags;

            this.items = AutoDispose(new SourceList <CheckableSelectOption <T> >());
            ReadOnlyObservableCollection <CheckableSelectOption <T> > outFilteredList;

            currentFilter = AutoDispose(new ReactiveProperty <Func <CheckableSelectOption <T>, bool> >(_ => true,
                                                                                                       Compare.Create <Func <CheckableSelectOption <T>, bool> >((_, _) => false, _ => 0)));
            AutoDispose(this.items.Connect()
                        .Filter(currentFilter)
                        .Sort(comparer)
                        .Bind(out outFilteredList)
                        .Subscribe());
            FilteredItems = outFilteredList;

            if (items != null)
            {
                this.items.Edit(list =>
                {
                    foreach (T key in items.Keys)
                    {
                        bool isSelected = shouldBeSelected(key);
                        var item        = new CheckableSelectOption <T>(key, items[key], isSelected);
                        if (isSelected)
                        {
                            SelectedItem = item;
                        }
                        list.Add(item);
                    }
                });
            }

            Columns = new ObservableCollection <ColumnDescriptor>
            {
                new("Key", "Entry", 80),
                new("Name", "Name", 220),
                new("Description", "Description", 320)
            };

            if (asFlags)
            {
                Columns.Insert(0, new ColumnDescriptor("", "IsChecked", 35, true));
            }

            if (items == null || items.Count == 0)
            {
                SearchText = current != null?current.ToString() ?? "" : "";
            }

            ShowItemsList = items?.Count > 0;
            DesiredHeight = ShowItemsList ? 670 : 130;
            DesiredWidth  = ShowItemsList ? 800 : 400;
            Accept        = new DelegateCommand(() =>
            {
                if (SelectedItem == null && FilteredItems.Count == 1)
                {
                    SelectedItem = FilteredItems[0];
                }
                CloseOk?.Invoke();
            }, () => asFlags || SelectedItem != null || FilteredItems.Count == 1 || int.TryParse(SearchText, out _));
            Cancel = new DelegateCommand(() => CloseCancel?.Invoke());

            FilteredItems.ObserveCollectionChanges().Subscribe(_ => Accept.RaiseCanExecuteChanged());
            this.WhenPropertyChanged(t => t.SearchText).Subscribe(_ => Accept.RaiseCanExecuteChanged());
            this.WhenPropertyChanged(t => t.SelectedItem).Subscribe(_ => Accept.RaiseCanExecuteChanged());
        }
        public ConditionsEditorViewModel(
            IConditionsFactory conditionsFactory,
            IConditionDataManager conditionDataManager,
            IItemFromListProvider itemFromListProvider,
            IHistoryManager historyManager,
            IEnumerable <ICondition>?conditions,
            int conditionSourceType)
        {
            this.conditionsFactory    = conditionsFactory;
            this.conditionDataManager = conditionDataManager;
            this.HistoryManager       = historyManager;

            ConditionTypes = conditionDataManager
                             .GetConditionGroups()
                             .SelectMany(group => group.Members)
                             .Where(conditionDataManager.HasConditionData)
                             .Select(conditionDataManager.GetConditionData)
                             .ToList();

            if (conditions != null)
            {
                int previousElseGroup = -1;
                foreach (var c in conditions)
                {
                    var vm = conditionsFactory.Create(conditionSourceType, c);
                    if (vm == null)
                    {
                        continue;
                    }

                    if (c.ElseGroup != previousElseGroup && previousElseGroup != -1)
                    {
                        Conditions.Add(conditionsFactory.CreateOr(conditionSourceType));
                    }

                    previousElseGroup = c.ElseGroup;
                    Conditions.Add(vm);
                }
            }

            Accept      = new DelegateCommand(() => CloseOk?.Invoke());
            Cancel      = new DelegateCommand(() => CloseCancel?.Invoke());
            PickCommand = new AsyncAutoCommand <ParameterValueHolder <long> >(async prh =>
            {
                if (!prh.HasItems)
                {
                    return;
                }

                var newItem = await itemFromListProvider.GetItemFromList(prh.Parameter.Items, prh.Parameter is FlagParameter, prh.Value);
                if (newItem.HasValue)
                {
                    prh.Value = newItem.Value;
                }
            });
            AddItemCommand = new DelegateCommand(() =>
            {
                int index = Conditions.Count;
                if (SelectedCondition != null)
                {
                    index = Conditions.IndexOf(SelectedCondition) + 1;
                }
                index = Math.Clamp(index, 0, Conditions.Count);

                Conditions.Insert(index, conditionsFactory.Create(conditionSourceType, 0) ?? conditionsFactory.CreateOr(conditionSourceType));
            });
            RemoveItemCommand = new DelegateCommand(() =>
            {
                if (SelectedCondition == null)
                {
                    return;
                }

                int indexOf = Conditions.IndexOf(SelectedCondition);
                if (indexOf != -1)
                {
                    Conditions.RemoveAt(indexOf);
                    if (indexOf - 1 >= 0 && Conditions.Count > 0)
                    {
                        SelectedCondition = Conditions[indexOf - 1];
                    }
                    else if (Conditions.Count > 0)
                    {
                        SelectedCondition = Conditions[indexOf];
                    }
                }
            }, () => SelectedCondition != null).ObservesProperty(() => SelectedCondition);
            CopyCommand = new DelegateCommand(() =>
            {
                if (SelectedCondition != null)
                {
                    Clipboard = SelectedCondition?.ToCondition(0);
                }
            }, () => SelectedCondition != null).ObservesProperty(() => SelectedCondition);
            CutCommand = new DelegateCommand(() =>
            {
                if (SelectedCondition != null)
                {
                    Clipboard = SelectedCondition?.ToCondition(0);
                    Conditions.Remove(SelectedCondition !);
                    SelectedCondition = null;
                }
            }, () => SelectedCondition != null).ObservesProperty(() => SelectedCondition);
            PasteCommand = new DelegateCommand(() =>
            {
                if (clipboard != null)
                {
                    int indexOf = Conditions.Count;
                    if (SelectedCondition != null)
                    {
                        indexOf = Conditions.IndexOf(SelectedCondition) + 1;
                    }
                    var item = conditionsFactory.Create(conditionSourceType, clipboard);
                    if (item != null)
                    {
                        Conditions.Insert(indexOf, item);
                    }
                }
            }, () => Clipboard != null).ObservesProperty(() => Clipboard);

            UndoCommand =
                new DelegateCommand(HistoryManager.Undo, () => HistoryManager.CanUndo).ObservesProperty(() =>
                                                                                                        HistoryManager.CanUndo);
            RedoCommand =
                new DelegateCommand(HistoryManager.Redo, () => HistoryManager.CanRedo).ObservesProperty(() =>
                                                                                                        HistoryManager.CanRedo);

            Watch(this, t => t.SelectedCondition, nameof(SelectedConditionsType));

            historyHandler = AutoDispose(new ConditionsEditorHistoryHandler(this, conditionsFactory));
            HistoryManager.AddHandler(historyHandler);
        }
예제 #13
0
        public PacketFilterDialogViewModel(IClipboardService clipboardService,
                                           IReadOnlyFilterData?filterData)
        {
            this.clipboardService = clipboardService;
            Accept = new DelegateCommand(() => CloseOk?.Invoke());
            Cancel = new DelegateCommand(() => CloseCancel?.Invoke());

            ClearFiltersCommand = new AsyncAutoCommand(async() =>
            {
                ExcludedEntries = "";
                IncludedEntries = "";
                ExcludedOpcodes = "";
                IncludedOpcodes = "";
                ExcludedGuids.Clear();
                IncludedGuids.Clear();
                CommaSeparatedPackets = "";
                HasMaxPacketNumber    = false;
                HasMinPacketNumber    = false;
                MinPacketNumber       = 0;
                MaxPacketNumber       = 0;
            });
            CopyFiltersCommand = new AsyncAutoCommand(async() =>
            {
                var data = new SerializedClipboardData()
                {
                    ExcludedEntries      = GenerateList(excludedEntries, s => uint.TryParse(s, out _), uint.Parse),
                    IncludedEntries      = GenerateList(includedOpcodes, s => uint.TryParse(s, out _), uint.Parse),
                    ExcludedGuids        = ExcludedGuids.Count == 0 ? null : ExcludedGuids.Select(s => s.ToHexWithTypeString()).ToList(),
                    IncludedGuids        = IncludedGuids.Count == 0 ? null : IncludedGuids.Select(s => s.ToHexWithTypeString()).ToList(),
                    ExcludedOpcodes      = GenerateList(excludedOpcodes, _ => true, s => s.ToUpper()),
                    IncludedOpcodes      = GenerateList(includedOpcodes, _ => true, s => s.ToUpper()),
                    ForceIncludedNumbers = GenerateList(commaSeparatedPackets, s => int.TryParse(s, out var x) && x >= 0, int.Parse),
                    MinPacket            = HasMinPacketNumber ? MinPacketNumber : null,
                    MaxPacket            = HasMaxPacketNumber ? MaxPacketNumber : null,
                };
                var serialized = JsonConvert.SerializeObject(data, Formatting.Indented, new JsonSerializerSettings()
                {
                    NullValueHandling = NullValueHandling.Ignore
                });
                clipboardService.SetText(serialized);
            });
            PasteFiltersCommand = new AsyncAutoCommand(async() =>
            {
                var text = await clipboardService.GetText();
                if (string.IsNullOrEmpty(text))
                {
                    return;
                }

                SerializedClipboardData?serialized = null;
                try
                {
                    serialized = JsonConvert.DeserializeObject <SerializedClipboardData>(text);
                }
                catch (Exception _)
                {
                    // ignored
                }

                if (!serialized.HasValue)
                {
                    return;
                }

                HasMinPacketNumber = serialized.Value.MinPacket.HasValue;
                HasMaxPacketNumber = serialized.Value.MaxPacket.HasValue;
                MinPacketNumber    = serialized.Value.MinPacket ?? 0;
                MaxPacketNumber    = serialized.Value.MaxPacket ?? 0;

                if (serialized.Value.ExcludedEntries != null)
                {
                    ExcludedEntries = string.Join(", ", serialized.Value.ExcludedEntries);
                }
                if (serialized.Value.IncludedEntries != null)
                {
                    IncludedEntries = string.Join(", ", serialized.Value.IncludedEntries);
                }
                if (serialized.Value.ExcludedGuids != null)
                {
                    ExcludedGuids.AddRange(serialized.Value.ExcludedGuids.StringToGuids());
                }
                if (serialized.Value.IncludedGuids != null)
                {
                    IncludedGuids.AddRange(serialized.Value.IncludedGuids.StringToGuids());
                }
                if (serialized.Value.ExcludedOpcodes != null)
                {
                    ExcludedOpcodes = string.Join(", ", serialized.Value.ExcludedOpcodes);
                }
                if (serialized.Value.IncludedOpcodes != null)
                {
                    IncludedOpcodes = string.Join(", ", serialized.Value.IncludedOpcodes);
                }
                if (serialized.Value.ForceIncludedNumbers != null)
                {
                    CommaSeparatedPackets = string.Join(", ", serialized.Value.ForceIncludedNumbers);
                }
            });

            if (filterData != null)
            {
                HasMinPacketNumber = filterData.MinPacketNumber.HasValue;
                HasMaxPacketNumber = filterData.MaxPacketNumber.HasValue;
                MinPacketNumber    = filterData.MinPacketNumber ?? 0;
                MaxPacketNumber    = filterData.MaxPacketNumber ?? 0;

                if (filterData.ExcludedEntries != null)
                {
                    ExcludedEntries = string.Join(", ", filterData.ExcludedEntries);
                }
                if (filterData.IncludedEntries != null)
                {
                    IncludedEntries = string.Join(", ", filterData.IncludedEntries);
                }
                if (filterData.ExcludedGuids != null)
                {
                    ExcludedGuids.AddRange(filterData.ExcludedGuids);
                }
                if (filterData.IncludedGuids != null)
                {
                    IncludedGuids.AddRange(filterData.IncludedGuids);
                }
                if (filterData.ExcludedOpcodes != null)
                {
                    ExcludedOpcodes = string.Join(", ", filterData.ExcludedOpcodes);
                }
                if (filterData.IncludedOpcodes != null)
                {
                    IncludedOpcodes = string.Join(", ", filterData.IncludedOpcodes);
                }
                if (filterData.ForceIncludePacketNumbers != null)
                {
                    CommaSeparatedPackets = string.Join(", ", filterData.ForceIncludePacketNumbers);
                }
            }

            DeleteIncludedGuid = new DelegateCommand <UniversalGuid?>(guid =>
            {
                if (guid != null)
                {
                    IncludedGuids.Remove(guid);
                }
            });

            DeleteExcludedGuid = new DelegateCommand <UniversalGuid?>(guid =>
            {
                if (guid != null)
                {
                    ExcludedGuids.Remove(guid);
                }
            });

            AutoDispose(this.ToObservable(o => o.ExcludedEntries).SubscribeAction(_ => RaisePropertyChanged(nameof(EntriesHeader))));
            AutoDispose(this.ToObservable(o => o.IncludedEntries).SubscribeAction(_ => RaisePropertyChanged(nameof(EntriesHeader))));
            AutoDispose(ExcludedGuids.ToCountChangedObservable().SubscribeAction(_ => RaisePropertyChanged(nameof(GuidsHeader))));
            AutoDispose(IncludedGuids.ToCountChangedObservable().SubscribeAction(_ => RaisePropertyChanged(nameof(GuidsHeader))));
            AutoDispose(this.ToObservable(o => o.ExcludedOpcodes).SubscribeAction(_ => RaisePropertyChanged(nameof(OpcodesHeader))));
            AutoDispose(this.ToObservable(o => o.IncludedOpcodes).SubscribeAction(_ => RaisePropertyChanged(nameof(OpcodesHeader))));
        }
        public ItemFromListProviderViewModel(Dictionary <long, SelectOption> items, bool asFlags, long?current = null)
        {
            this.asFlags = asFlags;

            this.items = AutoDispose(new SourceList <CheckableSelectOption>());
            ReadOnlyObservableCollection <CheckableSelectOption> outFilteredList;

            currentFilter = AutoDispose(new ReactiveProperty <Func <CheckableSelectOption, bool> >(_ => true,
                                                                                                   Compare.Create <Func <CheckableSelectOption, bool> >((_, _) => false, _ => 0)));
            AutoDispose(this.items.Connect()
                        .Filter(currentFilter)
                        .Sort(Comparer <CheckableSelectOption> .Create((x, y) => x.Entry.CompareTo(y.Entry)))
                        .Bind(out outFilteredList)
                        .Subscribe());
            FilteredItems = outFilteredList;

            this.items.Edit(list =>
            {
                foreach (long key in items.Keys)
                {
                    bool isSelected = current.HasValue && ((current == 0 && key == 0) || (key > 0) && (current & key) == key);
                    var item        = new CheckableSelectOption(key, items[key], isSelected);
                    if (isSelected)
                    {
                        SelectedItem = item;
                    }
                    list.Add(item);
                }
            });

            Columns = new ObservableCollection <ColumnDescriptor>
            {
                new("Key", "Entry", 50),
                new("Name", "Name"),
                new("Description", "Description")
            };

            if (asFlags)
            {
                Columns.Insert(0, new ColumnDescriptor("", "IsChecked", 35, true));
            }

            if (items.Count == 0)
            {
                SearchText = current.HasValue ? current.Value.ToString() : "";
            }

            ShowItemsList = items.Count > 0;
            DesiredHeight = ShowItemsList ? 470 : 130;
            Accept        = new DelegateCommand(() =>
            {
                if (SelectedItem == null && FilteredItems.Count == 1)
                {
                    SelectedItem = FilteredItems[0];
                }
                CloseOk?.Invoke();
            }, () => asFlags || SelectedItem != null || FilteredItems.Count == 1 || int.TryParse(SearchText, out _));
            Cancel = new DelegateCommand(() => CloseCancel?.Invoke());

            FilteredItems.ObserveCollectionChanges().Subscribe(_ => Accept.RaiseCanExecuteChanged());
            this.WhenPropertyChanged(t => t.SearchText).Subscribe(_ => Accept.RaiseCanExecuteChanged());
            this.WhenPropertyChanged(t => t.SelectedItem).Subscribe(_ => Accept.RaiseCanExecuteChanged());
        }
    public VariablePickerViewModel(GlobalVariableType type, SmartScriptBase script, long?initial)
    {
        this.type   = type;
        this.script = script;
        Items       = new(script.GlobalVariables.Where(gv => gv.VariableType == type)
                          .OrderBy(i => i.Key)
                          .Distinct(Compare.By <GlobalVariable, long>(i => i !.Key))
                          .Select(gv => new VariableItemViewModel(gv)));

        SelectedItem = initial.HasValue ? Items.FirstOrDefault(i => i.Id == initial) : null;

        if (SelectedItem == null && initial != null)
        {
            var phantom = VariableItemViewModel.CreatePhantom(initial.Value);
            Items.Add(phantom);
            SelectedItem = phantom;
        }

        Cancel = new DelegateCommand(() =>
        {
            CloseCancel?.Invoke();
        });
        Accept = new DelegateCommand(() =>
        {
            var dict = Items.Where(i => !i.IsPhantom).SafeToDictionary(i => i.OriginalId ?? i.Id, i => i);
            for (var i = script.GlobalVariables.Count - 1; i >= 0; i--)
            {
                var existing = script.GlobalVariables[i];
                if (existing.VariableType == type)
                {
                    if (dict.TryGetValue(existing.Key, out var item))
                    {
                        existing.Key     = item.Id;
                        existing.Name    = item.Name;
                        existing.Comment = item.Comment;
                        dict.Remove(item.OriginalId ?? item.Id);
                    }
                    else
                    {
                        script.GlobalVariables.RemoveAt(i);
                    }
                }
            }

            foreach (var pair in dict)
            {
                script.GlobalVariables.Add(new GlobalVariable()
                {
                    Key          = pair.Key,
                    Name         = pair.Value.Name,
                    Comment      = pair.Value.Comment,
                    VariableType = type
                });
            }

            CloseOk?.Invoke();
        });

        AddItemCommand = new DelegateCommand(() =>
        {
            var phantom = VariableItemViewModel.CreatePhantom((Items.Count > 0 ? Items.Max(i => i.Id) : 0) + 1);
            Items.Add(phantom);
            SelectedItem = phantom;
        });

        RemoveItemCommand = new DelegateCommand(() =>
        {
            if (SelectedItem != null)
            {
                Items.Remove(SelectedItem);
                SelectedItem = null;
            }
        }, () => SelectedItem != null).ObservesProperty(() => SelectedItem);

        Items.DisposeOnRemove();
        AutoDispose(new ActionDisposable(() => Items.Clear()));
    }