using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Data; using System.Windows.Input; using System.Windows.Media; using System.Windows.Threading; using BeWo.Core; using BeWo.Core.Service; using BeWo.ServiceProxy; using BeWo.View.Controls; using BeWo.View.Detail.Report; using BeWo.ViewModel; using BeWo.ViewModel.ListViewModel; using BS.Shared; using BS.Shared.Core; using BS.Shared.DataContracts; using BS.Shared.DataContracts.ClientPartials; using BS.Shared.Extensions; namespace BeWo.View.Detail { public partial class MassnahmenTreeViewView { private TreeViewItem _SelectedGoalTreeNode; private GenericValueListEntryListVM _ViewModel; private List _Children2Delete; private List _TreeViewItemsList; public MassnahmenTreeViewView(GenericValueListEntryListVM pViewModel) { InitializeComponent(); ViewModel = pViewModel; DataContext = this; } private void GoalTreeViewItem_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e) { var source = e.OriginalSource as DependencyObject; while (source != null && !(source is TreeViewItem)) { source = VisualTreeHelper.GetParent(source); } if (source != null) { ((TreeViewItem)source).IsSelected = true; _SelectedGoalTreeNode = (TreeViewItem)source; } else { _SelectedGoalTreeNode = null; } } private void TextBox_LostFocus(object sender, RoutedEventArgs e) { UpdateSelectedTreeItemText((TextBox)sender); } private void TextBox_KeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.Return) { UpdateSelectedTreeItemText((TextBox)sender); } } private void ContextMenuGoals_Click(object sender, RoutedEventArgs e) { if (!(e.OriginalSource is MenuItem twi)) return; var selectedItem = TreeView.SelectedItem as SupportConceptGoalTreeItem; switch (twi.Header) { case "Neue Maßnahme": if (_SelectedGoalTreeNode != null) { AddTreeItemWithControl(selectedItem, ValueListEntryType.SupportConceptGoalType, "Maßnahme hinzufügen"); } break; case "Neues Ziel": if (_SelectedGoalTreeNode != null) { AddTreeItemWithControl(selectedItem, ValueListEntryType.SupportConceptGoalCategoryType, "Ziel hinzufügen"); } break; case "Löschen": if (selectedItem != null) { var zielOderMassnahme = selectedItem.GoalEntryVM.Type == ValueListEntryType.SupportConceptGoalCategoryType ? "das Ziel" : "die Maßnahme"; var pluralendung = zielOderMassnahme.Equals("das Ziel") ? "en" : "n"; if (MessageBox.Show("ACHTUNG: Das Löschen von " + zielOderMassnahme.Substring(4) + pluralendung + " kann nicht rückgängig gemacht werden.\n" + "Alle verknüpften Eintragungen in der Zeiterfassung bleiben erhalten.\n\n" + "Wollen Sie " + zielOderMassnahme + " '" + selectedItem.GoalEntryVM?.DisplayName + "' wirklich löschen?", "Löschen bestätigen", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) { DeleteIndividualGoal(selectedItem); } } break; case "Bearbeiten": if (selectedItem != null) EditTreeItem(selectedItem.GoalEntryVM); break; } } private void ContextMenuGoals_Opened(object sender, RoutedEventArgs e) { if (e.OriginalSource is ContextMenu menu) { var goal = TreeView.SelectedItem as SupportConceptGoalTreeItem; foreach (var menuitem in menu.Items.OfType().Select(item => item)) { if (menuitem.Header.Equals("Neue Maßnahme")) { menuitem.IsEnabled = goal != null && !goal.IsGoal; } else if (menuitem.Header.Equals("Neues Ziel")) { menuitem.IsEnabled = goal != null && !goal.IsGoal; } else if (menuitem.Header.Equals("Notiz bearbeiten")) { menuitem.IsEnabled = goal != null; // && goal.IsGoal; } menuitem.IsEnabled = menuitem.IsEnabled && IsAllowedToEditGoals; } } } private void GoalTreeItemContainerGenerator_StatusChanged(object sender, EventArgs e) { var ig = (ItemContainerGenerator)sender; if (ig.Status != GeneratorStatus.ContainersGenerated) { return; } if (ig.ContainerFromIndex(_SelectedGoalTreeNode.Items.Count - 1) is TreeViewItem n) { n.IsSelected = true; new DispatcherTimer( TimeSpan.FromMilliseconds(200), DispatcherPriority.Background, (s1, e1) => { _SelectedGoalTreeNode = n; var item = ig.ItemFromContainer(n) as SupportConceptGoalDC; EditItem(TreeView, _SelectedGoalTreeNode, item); ((DispatcherTimer)s1).Stop(); }, Dispatcher).Start(); } _SelectedGoalTreeNode.ItemContainerGenerator.StatusChanged -= GoalTreeItemContainerGenerator_StatusChanged; } private void ZielHinzufuegenButton_Click(object sender, RoutedEventArgs e) { var newItem = new SupportConceptGoalTreeItem(); var vm = ViewModel.NewVM; vm.Type = ValueListEntryType.SupportConceptGoalCategoryType; newItem.GoalEntryVM = vm; ViewModel.AddNewVMToList(); GoalTree.Add(newItem); GoalTree.Sort((x, y) => x.GoalEntryVM?.DisplayName?.CompareTo(y.GoalEntryVM?.DisplayName) ?? string.Compare(string.Empty, y.GoalEntryVM?.DisplayName, StringComparison.Ordinal)); } private void IcfImport_Click(object sender, RoutedEventArgs e) { var vorhandeneZiele = new List(); foreach (var item in GoalTree) { vorhandeneZiele.AddRange(GetAllChildren(item, null)); } //#if DEBUG var control2 = new IcfImportControl(ServiceFacade.DoOperationsServiceSync(x => x.GetWholeIcfOhneImportierte(vorhandeneZiele))); var beWoWindow2 = new BeWoWindow { rootGroupBox = { Header = "Icf Importieren" }, Height = 500, Width = 500, WindowStartupLocation = WindowStartupLocation.CenterOwner, GroupBoxContent = control2, Owner = BeWoApp.CurrentBeWo.MainWindow }; control2.ButtonImportClicked += () => { ImportIcf(control2.TreeViewGoalItem); beWoWindow2.Close(); }; control2.ButtonCancelClicked += () => { beWoWindow2.Close(); }; beWoWindow2.ShowDialog(); return; //#endif //var control = new IcfImportControl(ServiceFacade.DoOperationsServiceSync(x => x.GetWholeIcf())); //var beWoWindow = new BeWoWindow //{ // rootGroupBox = { Header = "Icf Importieren" }, // Height = 500, // Width = 500, // WindowStartupLocation = WindowStartupLocation.CenterOwner, // GroupBoxContent = control, // Owner = BeWoApp.CurrentBeWo.MainWindow //}; //control.ButtonImportClicked += () => //{ // ImportIcf(control.TreeViewGoalItem); // beWoWindow.Close(); //}; //control.ButtonCancelClicked += () => //{ // beWoWindow.Close(); //}; //beWoWindow.ShowDialog(); } public List GetAllChildren(SupportConceptGoalTreeItem treeItem, SupportConceptGoalDC dcItem) { List returnThis = new List(); if (dcItem == null) { returnThis.Add(treeItem.GoalEntryDC); if (treeItem.Children.Count > 0) { foreach (var child in treeItem.Children) { returnThis.AddRange(GetAllChildren(null, child)); } } } else if (treeItem == null) { returnThis.Add(dcItem.GoalEntryDC); if (dcItem.Children.Count > 0) { foreach (var child in dcItem.Children) { returnThis.AddRange(GetAllChildren(null, child)); } } } return returnThis; } public static bool IsAllowedToEditGoals => BeWoApp.LoggedOnUser.HasRight(UserRightType.SupportConcept_AllowEditGoals); public GenericValueListEntryListVM ViewModel { get => _ViewModel; set { _ViewModel = value; InitGoalCategoriesTreeView(); TreeView.ItemsSource = GoalTree; } } public ObservableSortCollection GoalTree { get; private set; } public override bool IsDirty => ViewModel != null && ViewModel.IsDirty; public void AddTreeItemWithControl(SupportConceptGoalTreeItem parent, ValueListEntryType valueListEntryType, string viewHeader) { var control = new ValueListEntryEditControl(new ValueListEntryVM(new ValueListEntryDC()), null); var beWoWindow = new BeWoWindow(); control.CancelButtonClicked += () => { if (control.ValueListEntry.IsDirty) { if (MessageBox.Show("Möchten Sie die Änderung verwerfen?", "Änderungen vorhanden", MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes) return; control.ResetValueListEntry(); } beWoWindow.Close(); }; control.SaveButtonClicked += () => { var vm = control.ValueListEntry; AddTreeItem(parent, valueListEntryType, vm.Description, vm.Abbreviation, vm.Notice); beWoWindow.Close(); }; beWoWindow.Height = 200; beWoWindow.Width = 500; beWoWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner; beWoWindow.GroupBoxContent = control; beWoWindow.Owner = BeWoApp.CurrentBeWo.MainWindow; beWoWindow.rootGroupBox.Header = viewHeader; beWoWindow.ShowDialog(); } public SupportConceptGoalTreeItem AddTreeItem(SupportConceptGoalTreeItem parent, ValueListEntryType valueListEntryType, string description, string abbreviation, string notice) { if (!valueListEntryType.HasFlag(ValueListEntryType.SupportConceptGoalCategoryType) && !valueListEntryType.HasFlag(ValueListEntryType.SupportConceptGoalType)) throw new ArgumentOutOfRangeException(); var vm = ViewModel.NewVM; vm.Type = valueListEntryType; vm.Description = description; vm.Abbreviation = abbreviation; vm.Notice = notice; var newItem = new SupportConceptGoalTreeItem { GoalEntryVM = vm, GoalEntryDC = vm.CommitToDataContract(), ParentGoal = parent }; ViewModel.AddNewVMToList(); if (parent == null) return newItem; vm.ParentEntry = parent.GoalEntryDC ?? parent.GoalEntryVM.CommitToDataContract(); parent.GoalEntryVM = parent.GoalEntryVM; parent.Items.Add(newItem); parent.IsExpanded = true; return newItem; } internal void DeleteIndividualGoal(SupportConceptGoalTreeItem selectedItem) { _Children2Delete = new List(); TraverseCollection(selectedItem); var parent = selectedItem.ParentGoal as SupportConceptGoalTreeItem; if (parent != null && parent.Items != null) parent.Items.Remove(selectedItem); else GoalTree.Remove(selectedItem); ViewModel.VMList.Remove(selectedItem.GoalEntryVM); } protected override void Save() { var lToDos = new List>(); if (ViewModel.ChangedCount > 0) { lToDos.Add(s => s.UpdateValueListEntries(ViewModel.CommitChanged())); } if (ViewModel.AddedCount > 0) { var neueVMs = ViewModel.VMList.Where(w => w.IsNew).ToList(); _TreeViewItemsList = new List(); GetAllTreeViewItems(); var obersteZiele = neueVMs.Where(w => w.IsNew && (w.ParentEntry != null && w.ParentEntry.ValueListEntryOid != null) || w.ParentEntry == null); foreach (var ziel in obersteZiele) { var ve = _TreeViewItemsList.FirstOrDefault(f => f.GoalEntryVM != null && f.GoalEntryVM.Equals(ziel)); if (ve != null) { GoalService.RecursiveSynchronousValueListEntrySave(ve); // Hier passiert bei Komponente E ein Fehler } } } if (ViewModel.RemovedCount > 0) { var entfernte = _Children2Delete.Where(w => w.ValueListEntryOid != null).ToList(); var entfernteDic = entfernte.ToDictionary(k => k.ValueListEntryOid.Value, v => v.ValueListEntryVersion.Value); entfernteDic.AddAndIgnoreDuplicates(ViewModel.GetRemoved().ToDictionary(dc => dc.ValueListEntryOid.Value, dc => dc.ValueListEntryVersion.Value)); lToDos.Add(s => s.DeactivateValueListEntries(entfernteDic)); } ServiceFacade.DoMultipleValueListServicesAsync(lToDos, ReloadViewModel); Cache.GetInstance().ClearAllValueListEntries(); } private static void EditTreeItem(ValueListEntryVM valueListEntry) { if (valueListEntry == null) return; if (valueListEntry.IsNew) { valueListEntry.CommitToDataContract(); } var control = new ValueListEntryEditControl(valueListEntry, null); var beWoWindow = new BeWoWindow(); control.CancelButtonClicked += () => { if (control.ValueListEntry.IsDirty) { if (MessageBox.Show("Möchten Sie die Änderung verwerfen?", "Änderungen vorhanden", MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes) return; control.ResetValueListEntry(); } beWoWindow.Close(); }; control.SaveButtonClicked += () => beWoWindow.Close(); beWoWindow.Height = 200; beWoWindow.Width = 500; beWoWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner; beWoWindow.GroupBoxContent = control; beWoWindow.Owner = BeWoApp.CurrentBeWo.MainWindow; beWoWindow.rootGroupBox.Header = "Bearbeiten"; beWoWindow.ShowDialog(); } private static void EditItem(TreeView tv, TreeViewItem tvi, object item, bool isNoticeTextBox = false) { if (item != null) { var treeItem = tvi; if (treeItem == null && tv != null) { treeItem = tv.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem; } if (treeItem != null) { var textBox = BeWoWpfUtils.FindItem(treeItem, isNoticeTextBox ? 1 : 0); if (textBox == null) { return; } textBox.IsReadOnly = false; textBox.Padding = new Thickness(1, 1, 1, 1); textBox.BorderThickness = new Thickness(1); textBox.Background = Brushes.White; textBox.Tag = tv.SelectedItem; textBox.Focus(); textBox.SelectAll(); } } } private static void UpdateSelectedTreeItemText(TextBoxBase textBox) { if (!textBox.IsReadOnly) { textBox.Background = Brushes.Transparent; textBox.IsReadOnly = true; textBox.BorderThickness = new Thickness(0); textBox.Padding = new Thickness(1, 3, 1, 3); } } private static SupportConceptGoalTreeItem SearchGoalTreeItem(SupportConceptGoalTreeItem supportConceptGoalTreeItem, string description, string abbreviation, string notice) { if (supportConceptGoalTreeItem?.GoalEntryVM == null) return null; if ((supportConceptGoalTreeItem.GoalEntryVM.Description ?? "") == (description ?? "") && (supportConceptGoalTreeItem.GoalEntryVM.Abbreviation ?? "") == (abbreviation ?? "") && (supportConceptGoalTreeItem.GoalEntryVM.Notice ?? "") == (notice ?? "")) return supportConceptGoalTreeItem; if (supportConceptGoalTreeItem.Items == null) return null; foreach (var goal in supportConceptGoalTreeItem.Items) { var foundedGoal = SearchGoalTreeItem(goal, description, abbreviation, notice); if (foundedGoal != null) return foundedGoal; } return null; } private void ReloadViewModel() { VMFactory.CreateGoalCategoryVMAsync(vm => this.Dispatch(() => { ViewModel = vm; })); } private void InitGoalCategoriesTreeView() { var categoriesWithParent = new List(); var test = ViewModel.VMList.ToList(); var goalList = GoalService.GetZieleMassnahmenTree(test, false); var iGoalList = new ObservableSortCollection(); var dictOid2TreeItem = new Dictionary(); foreach (var category in goalList) { var item = new SupportConceptGoalTreeItem { GoalEntryDC = category.GoalEntryDC, GoalEntryVM = ViewModel.VMList.FirstOrDefault(f => f.DataContract.ValueListEntryOid.Value == category.GoalEntryDC.ValueListEntryOid.Value), IsExpanded = true, ParentGoal = category.ParentGoal }; if (item.GoalEntryDC.ParentOid == null) { iGoalList.Add(item); } else { categoriesWithParent.Add(item); } dictOid2TreeItem.Add(category.GoalEntryDC.ValueListEntryOid.Value, item); } foreach (var category in categoriesWithParent) { if (category.GoalEntryDC.ParentOid == null || category.GoalEntryDC.ValueListEntryOid == null) continue; if (dictOid2TreeItem.ContainsKey(category.GoalEntryDC.ParentOid.Value)) { var parent = dictOid2TreeItem[category.GoalEntryDC.ParentOid.Value]; parent.Items.Add(dictOid2TreeItem[category.GoalEntryDC.ValueListEntryOid.Value]); category.ParentGoal = parent; } } var categoriesWithParents = dictOid2TreeItem.Values.Where(w => w.GoalEntryDC.ParentOid != null).ToList(); foreach (var goalCategory in categoriesWithParents) { if (dictOid2TreeItem.ContainsKey(goalCategory.GoalEntryDC.ParentOid.Value)) { dictOid2TreeItem[goalCategory.GoalEntryDC.ParentOid.Value].Children.Add(goalCategory); } } foreach (var goal in ViewModel.VMList.Where(w => w.Type.Equals(ValueListEntryType.SupportConceptGoalType))) { var item = new SupportConceptGoalTreeItem { GoalEntryVM = goal }; if (goal.ParentEntry == null || !goal.ParentEntry.ValueListEntryOid.HasValue || !dictOid2TreeItem.ContainsKey(goal.ParentEntry.ValueListEntryOid.Value)) { iGoalList.Add(item); } else { var parent = dictOid2TreeItem[goal.ParentEntry.ValueListEntryOid.Value]; parent.Items.Add(item); item.ParentGoal = parent; } } GoalTree = iGoalList; } private void TraverseCollection(SupportConceptGoalTreeItem item) { var result = new List { item.GoalEntryDC ?? item.GoalEntryVM.CommitToDataContract() }; foreach (var child in item.Items) { TraverseCollection(child); } _Children2Delete.AddRange(result); } private void GetAllTreeViewItems() { foreach (var parent in GoalTree) { TraverseTreeViewItem(parent); } } private void TraverseTreeViewItem(SupportConceptGoalTreeItem item) { _TreeViewItemsList.Add(item); foreach (var child in item.Items) { TraverseTreeViewItem(child); } } private void ImportIcf(SupportConceptGoalDC goal) { if (goal == null) return; goal.Children?.ForEach(ImportIcf); if (goal.IsChecked) AddIcf(goal); } private SupportConceptGoalTreeItem AddIcf(SupportConceptGoalDC goal) { if (goal == null) return null; // Schaut, ob das Child bereits existiert var similarGoal = GoalTree.FirstOrDefault(x => SearchGoalTreeItem(x, goal.GoalEntryDC.TypeDescription, goal.GoalEntryDC.Abbreviation, goal.GoalEntryDC.Notice) != null); if (similarGoal != null) return similarGoal; // Schaut, ob das Goal ein Parent hat if (goal.ParentGoal == null) { var treeItem = AddTreeItem(null, ValueListEntryType.SupportConceptGoalCategoryType, goal.GoalEntryDC.TypeDescription, goal.GoalEntryDC.Abbreviation, goal.GoalEntryDC.Notice); GoalTree.Add(treeItem); GoalTree.Sort((x, y) => x.GoalEntryVM?.DisplayName?.CompareTo(y.GoalEntryVM?.DisplayName) ?? string.Compare(string.Empty, y.GoalEntryVM?.DisplayName, StringComparison.Ordinal)); return treeItem; } // Schaut, ob das ParentGoal bereits existiert foreach (var goalTreeItem in GoalTree) { var similarParentGoal = SearchGoalTreeItem(goalTreeItem, goal.ParentGoal.GoalEntryDC.TypeDescription, goal.ParentGoal.GoalEntryDC.Abbreviation, goal.ParentGoal.GoalEntryDC.Notice); if (similarParentGoal == null) continue; return AddTreeItem(similarParentGoal, ValueListEntryType.SupportConceptGoalCategoryType, goal.GoalEntryDC.TypeDescription, goal.GoalEntryDC.Abbreviation, goal.GoalEntryDC.Notice); } // Fügt den Parent hinzu var parent = AddIcf(goal.ParentGoal); return AddTreeItem(parent, ValueListEntryType.SupportConceptGoalCategoryType, goal.GoalEntryDC.TypeDescription, goal.GoalEntryDC.Abbreviation, goal.GoalEntryDC.Notice); } private bool IstGleichesZiel(ValueListEntryVM ziel1, ValueListEntryVM ziel2) { if (ziel1.DataContract.ValueListEntryOid.HasValue && ziel2.DataContract.ValueListEntryOid.HasValue) { return ziel1.DataContract.ValueListEntryOid.Value == ziel2.DataContract.ValueListEntryOid.Value; } else if (!ziel1.DataContract.ValueListEntryOid.HasValue && !ziel2.DataContract.ValueListEntryOid.HasValue) { if (ziel1.ParentEntry != null && ziel2.ParentEntry != null && ziel1.ParentEntry.Equals(ziel1.ParentEntry)) { bool test = ziel1.Equals(ziel2); return ziel1.Description == ziel2.Description; } else if (ziel1.ParentEntry == null && ziel2.ParentEntry == null) { return ziel1.Description == ziel2.Description; } } return false; } } public class ValueListEntryTypeToFontWeightConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var val = (bool)value; return val ? FontWeights.Normal : FontWeights.Bold; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } }