diff --git a/BeWo/BeWo.csproj b/BeWo/BeWo.csproj
index 4dc230d1c..f407d6ba5 100644
--- a/BeWo/BeWo.csproj
+++ b/BeWo/BeWo.csproj
@@ -1062,6 +1062,9 @@
DebugMessageLogView.xaml
+
+
+
ServiceRecordCreationView.xaml
diff --git a/BeWo/View/Controls/ValueListEntryEditControl.xaml.cs b/BeWo/View/Controls/ValueListEntryEditControl.xaml.cs
index 74871ca7a..0833e85ce 100644
--- a/BeWo/View/Controls/ValueListEntryEditControl.xaml.cs
+++ b/BeWo/View/Controls/ValueListEntryEditControl.xaml.cs
@@ -56,7 +56,6 @@ namespace BeWo.View.Controls
private void UpdateControls()
{
bool zeigeKatalogAuswahl = RBtnKatalog.IsChecked.HasValue && RBtnKatalog.IsChecked.Value;
-
LabelKatalog.Visibility = zeigeKatalogAuswahl ? Visibility.Visible : Visibility.Collapsed;
CboCatalog.Visibility = zeigeKatalogAuswahl ? Visibility.Visible : Visibility.Collapsed;
diff --git a/BeWo/View/Detail/MassnahmenHistory.cs b/BeWo/View/Detail/MassnahmenHistory.cs
new file mode 100644
index 000000000..8780a9505
--- /dev/null
+++ b/BeWo/View/Detail/MassnahmenHistory.cs
@@ -0,0 +1,136 @@
+using BeWo.Core;
+using BeWo.ViewModel.ListViewModel;
+using BS.Shared.Core;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using static BeWo.View.Detail.MassnahmenHistoryRecord;
+
+namespace BeWo.View.Detail
+{
+ //public class MassnahmenTreeViewHistoryManager
+ //{
+ // public MassnahmenTreeViewHistoryManager()
+ // {
+ // History = new Stack();
+ // }
+
+ // public Stack History { get; set; }
+
+ // internal void RecordAction(MassnahmenActionParameters param)
+ // {
+ // History.Push(param);
+ // }
+
+ // internal void UndoAction()
+ // {
+
+ // }
+
+ // internal void UndoAddAction()
+ // {
+
+ // }
+
+ // internal void UndoDeleteAction()
+ // {
+
+ // }
+
+ // internal void UndoMoveAction()
+ // {
+
+ // }
+
+ // internal void UndoCopyAction()
+ // {
+
+ // }
+ //}
+
+ public class MassnahmenHistory
+ {
+ public Action RefreshTree { get; set; }
+ public Action RefreshButton { get; set; }
+
+ public MassnahmenHistoryRecordOrigin Origin { get; set; }
+ public LinkedList History { get; set; }
+ public LinkedListNode LastChange { get; set; }
+
+ public MassnahmenTreeTrimmer TreeTrimmer { get; set; }
+
+ public MassnahmenHistory(MassnahmenTreeTrimmer trimmer, Action refresh, Action button)
+ {
+ Origin = new MassnahmenHistoryRecordOrigin();
+ History = new LinkedList();
+ History.AddLast(Origin);
+
+ LastChange = History.Last;
+
+ TreeTrimmer = trimmer;
+ RefreshTree = refresh;
+ RefreshButton = button;
+ }
+
+ public bool GotPrevAction => LastChange is object && LastChange.Value != Origin;
+ public bool GotNextAction => LastChange is object && LastChange.Next is object;
+ public bool GotChanges => LastChange is object && (GotNextAction || GotPrevAction);
+
+ public void RecordAdd(NodeRelation param) => RecordAction(new MassnahmenHistoryRecordAdd(param));
+ public void RecordMove(MassnahmenHistoryRecordMove move) => RecordAction(move);
+ public void RecordImport(List param) => RecordAction(new MassnahmenHistoryRecordImport(param));
+ public void RecordDelete(MassnahmenHistoryRecordDelete del) => RecordAction(del);
+ public void RecordCopy(NodeRelation root, List param) => RecordAction(new MassnahmenHistoryRecordCopy(root, param));
+ public void RecordEdit(MassnahmenHistoryRecordEdit edit) => RecordAction(edit);
+
+ private void RecordAction(MassnahmenHistoryRecord val)
+ {
+ while (LastChange != History.Last)
+ {
+ History.RemoveLast();
+ }
+
+ History.AddLast(val);
+
+ LastChange = History.Last;
+
+ RefreshTree();
+ RefreshButton();
+ }
+
+ public void ClearHistory()
+ {
+ while(History.Last != History.First)
+ {
+ History.RemoveLast();
+ }
+
+ LastChange = History.Last;
+
+ RefreshButton();
+ }
+
+ public void UndoPrevAction()
+ {
+ var action = LastChange.Value;
+
+ TreeTrimmer.UndoAction(action);
+
+ LastChange = LastChange.Previous;
+ RefreshButton();
+ RefreshTree();
+ }
+ public void RedoNextAction()
+ {
+ var action = LastChange.Next.Value;
+
+ TreeTrimmer.RedoAction(action);
+
+ LastChange = LastChange.Next;
+ RefreshButton();
+ RefreshTree();
+ }
+ }
+}
diff --git a/BeWo/View/Detail/MassnahmenHistoryRecord.cs b/BeWo/View/Detail/MassnahmenHistoryRecord.cs
new file mode 100644
index 000000000..c9b0f4ad0
--- /dev/null
+++ b/BeWo/View/Detail/MassnahmenHistoryRecord.cs
@@ -0,0 +1,129 @@
+using BeWo.Core;
+using BeWo.ViewModel;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BeWo.View.Detail
+{
+ public abstract class MassnahmenHistoryRecord
+ {
+ public struct NodeRelation
+ {
+ public SupportConceptGoalTreeItem Current { get; set; }
+ public SupportConceptGoalTreeItem Parent { get; set; }
+
+ public NodeRelation(SupportConceptGoalTreeItem newitem, SupportConceptGoalTreeItem parent)
+ {
+ Current = newitem;
+ Parent = parent;
+ }
+ public NodeRelation(SupportConceptGoalTreeItem newitem)
+ {
+ Current = newitem;
+ Parent = newitem.ParentGoal as SupportConceptGoalTreeItem;
+ }
+ }
+
+ public struct NodeEditInformation
+ {
+ public string Abbreviation { get; set; }
+ public string Description { get; set; }
+ public string Notice { get; set; }
+ }
+ }
+
+ public class MassnahmenHistoryRecordOrigin : MassnahmenHistoryRecord
+ {
+
+ }
+
+ public class MassnahmenHistoryRecordAdd : MassnahmenHistoryRecord
+ {
+ public NodeRelation Parameter { get; set; }
+
+ public MassnahmenHistoryRecordAdd(SupportConceptGoalTreeItem newitem, SupportConceptGoalTreeItem parent)
+ {
+ Parameter = new NodeRelation(newitem, parent);
+ }
+ public MassnahmenHistoryRecordAdd(NodeRelation param)
+ {
+ Parameter = param;
+ }
+ }
+
+ public class MassnahmenHistoryRecordImport : MassnahmenHistoryRecord
+ {
+ public List Parameters { get; set; }
+ public List ParametersReversed { get; set; }
+
+ public MassnahmenHistoryRecordImport(List list)
+ {
+ Parameters = list;
+ ParametersReversed = new Stack(list).ToList();
+ }
+ }
+
+ public class MassnahmenHistoryRecordDelete : MassnahmenHistoryRecord
+ {
+ public NodeRelation ExNode { get; set; }
+ public List Parameters { get; set; }
+
+ public MassnahmenHistoryRecordDelete(NodeRelation exnode, List list)
+ {
+ Parameters = list;
+ ExNode = exnode;
+ }
+ }
+
+ public class MassnahmenHistoryRecordMove : MassnahmenHistoryRecord
+ {
+ public SupportConceptGoalTreeItem Child { get; set; }
+ public SupportConceptGoalTreeItem ExParent { get; set; }
+ public SupportConceptGoalTreeItem Parent { get; set; }
+
+ public MassnahmenHistoryRecordMove(SupportConceptGoalTreeItem child, SupportConceptGoalTreeItem exparent, SupportConceptGoalTreeItem parent)
+ {
+ Child = child;
+ ExParent = exparent;
+ Parent = parent;
+ }
+ }
+
+ public class MassnahmenHistoryRecordCopy : MassnahmenHistoryRecord
+ {
+ public NodeRelation CurrentNode { get; set; }
+ public List Parameters { get; set; }
+
+ public MassnahmenHistoryRecordCopy(NodeRelation root, List list)
+ {
+ Parameters = list;
+ CurrentNode = root;
+ }
+ }
+
+ public class MassnahmenHistoryRecordEdit : MassnahmenHistoryRecord
+ {
+ public ValueListEntryVM VM { get; set; }
+
+ public NodeEditInformation Before { get; set; }
+ public NodeEditInformation After { get; set; }
+
+ public MassnahmenHistoryRecordEdit(ValueListEntryVM vm, NodeEditInformation b, NodeEditInformation a)
+ {
+ Before = b;
+ After = a;
+ VM = vm;
+ }
+
+ public void SetVM(NodeEditInformation info)
+ {
+ VM.Abbreviation = info.Abbreviation;
+ VM.Description = info.Description;
+ VM.Notice = info.Notice;
+ VM.CommitToDataContract();
+ }
+ }
+}
diff --git a/BeWo/View/Detail/MassnahmenTreeTrimmer.cs b/BeWo/View/Detail/MassnahmenTreeTrimmer.cs
new file mode 100644
index 000000000..7b824b139
--- /dev/null
+++ b/BeWo/View/Detail/MassnahmenTreeTrimmer.cs
@@ -0,0 +1,342 @@
+using BeWo.Core;
+using BeWo.ViewModel;
+using BeWo.ViewModel.ListViewModel;
+using BS.Shared;
+using BS.Shared.Core;
+using BS.Shared.DataContracts;
+using BS.Shared.DataContracts.ClientPartials;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using static BeWo.View.Detail.MassnahmenHistoryRecord;
+
+namespace BeWo.View.Detail
+{
+ public class MassnahmenTreeTrimmer
+ {
+ public Dictionary, Action>> Type2Actions { get; set; }
+
+ public MassnahmenTreeViewView View { get; set; }
+
+ public GenericValueListEntryListVM ViewModel => View.ViewModel;
+ public ObservableSortCollection GoalTree => View.GoalTree;
+
+ public MassnahmenTreeTrimmer(MassnahmenTreeViewView view)
+ {
+ View = view;
+
+ Type2Actions = new Dictionary, Action>>
+ {
+ { typeof(MassnahmenHistoryRecordAdd), GetTuple(UndoAddAction, RedoAddAction) },
+ { typeof(MassnahmenHistoryRecordCopy), GetTuple(UndoCopyAction, RedoCopyAction) },
+ { typeof(MassnahmenHistoryRecordDelete), GetTuple(UndoDeleteAction, RedoDeleteAction) },
+ { typeof(MassnahmenHistoryRecordImport), GetTuple(UndoImportAction, RedoImportAction) },
+ { typeof(MassnahmenHistoryRecordMove), GetTuple(UndoMoveAction, RedoMoveAction) },
+ { typeof(MassnahmenHistoryRecordEdit), GetTuple(UndoEditAction, RedoEditAction) },
+ };
+ }
+
+ public void UndoAction(MassnahmenHistoryRecord action)
+ {
+ Type2Actions[action.GetType()].Item1(action);
+ }
+ public void RedoAction(MassnahmenHistoryRecord action)
+ {
+ Type2Actions[action.GetType()].Item2(action);
+ }
+
+ public NodeRelation DoAddAction(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;
+
+ if (description is object) vm.Description = description;
+ if (abbreviation is object) vm.Abbreviation = abbreviation;
+ if (notice is object) vm.Notice = notice;
+
+ var newItem = new SupportConceptGoalTreeItem
+ {
+ GoalEntryVM = vm,
+ GoalEntryDC = vm.CommitToDataContract(),
+ ParentGoal = parent
+ };
+
+ var rtn = new NodeRelation(newItem, parent);
+
+ ViewModel.AddNewVMToList();
+
+ if (parent == null)
+ {
+ GoalTree.Add(newItem);
+ return rtn;
+ }
+
+
+ vm.ParentEntry = parent.GoalEntryDC ?? parent.GoalEntryVM.CommitToDataContract();
+
+ parent.Items.Add(newItem);
+ parent.IsExpanded = true;
+
+ return rtn;
+ }
+ private void UndoAddAction(MassnahmenHistoryRecordAdd record)
+ {
+ DeactivateNode(record.Parameter);
+ }
+ private void RedoAddAction(MassnahmenHistoryRecordAdd param) => RedoAddAction(param.Parameter);
+ private void RedoAddAction(NodeRelation addParam)
+ {
+ ActivateNode(addParam);
+ }
+
+ public List DoCopyAction(SupportConceptGoalTreeItem parent, SupportConceptGoalTreeItem source,
+ MassnahmenTreeCopyType copyType, bool force_deep_copy,
+ out NodeRelation current, Stack records = null)
+ {
+ if (records is null)
+ records = new Stack();
+
+ if (source == null || parent == null)
+ throw new NotImplementedException("#43298467891364987");
+
+ var wm = source.GoalEntryVM;
+ var childs = source.Items.ToList();
+ var param = DoAddAction(parent, wm.Type, wm.Description, wm.Abbreviation, wm.Notice);
+ var node = param.Current;
+ var parameter = new NodeRelation(node, parent);
+
+ current = parameter;
+
+ records.Push(parameter);
+
+ if (copyType == MassnahmenTreeCopyType.Subtree || force_deep_copy)
+ {
+ foreach (var child in childs)
+ {
+ DoCopyAction(node, child, copyType, force_deep_copy, out var item, records);
+ }
+ }
+
+ return records.ToList();
+ }
+ private void UndoCopyAction(MassnahmenHistoryRecordCopy record)
+ {
+ DeactivateSubtree(record.CurrentNode, record.Parameters);
+ }
+ private void RedoCopyAction(MassnahmenHistoryRecordCopy record)
+ {
+ ActivateSubtree(record.CurrentNode, record.Parameters);
+ }
+
+ public MassnahmenHistoryRecordDelete DoDeleteAction(NodeRelation param)
+ {
+ // Delete Full Subtree
+ var stack = new Stack();
+ var queue = new Queue();
+
+ DoDeleteActionRec(param.Current, ref stack, ref queue);
+
+ // Queue löschen
+ DeactivateSubtree(param, queue);
+
+ //var list = stack.Select(x => new MassnahmenHistoryNodeParameter(x, View.GetParent(x))).ToList();
+ var node = new NodeRelation(param.Current, param.Parent);
+
+ return new MassnahmenHistoryRecordDelete(node, stack.ToList());
+ }
+ public void DoDeleteActionRec(SupportConceptGoalTreeItem item, ref Stack stack, ref Queue queue)
+ {
+ foreach (var child in item.Items)
+ {
+ DoDeleteActionRec(child, ref stack, ref queue);
+ }
+
+ var param = new NodeRelation(item);
+ stack.Push(param);
+ queue.Enqueue(param);
+ }
+ private void UndoDeleteAction(MassnahmenHistoryRecordDelete param)
+ {
+ ActivateSubtree(param.ExNode, param.Parameters);
+ }
+ private void RedoDeleteAction(MassnahmenHistoryRecordDelete param)
+ {
+ DeactivateSubtree(param.ExNode, param.Parameters);
+ }
+
+ public List DoImportAction(SupportConceptGoalDC goal, List records = null)
+ {
+ if (goal == null)
+ return null;
+
+ if (records == null)
+ records = new List();
+
+ goal.Children?.ForEach(x => DoImportAction(x, records));
+
+ if (goal.IsChecked)
+ AddIcf(goal, records);
+
+ return records;
+ }
+ private void UndoImportAction(MassnahmenHistoryRecordImport param)
+ {
+ foreach (var item in param.ParametersReversed)
+ {
+ DeactivateNode(item);
+ }
+ }
+ private void RedoImportAction(MassnahmenHistoryRecordImport param)
+ {
+ foreach (var item in param.Parameters)
+ {
+ ActivateNode(item);
+ }
+ }
+
+ public MassnahmenHistoryRecordMove DoMoveAction(SupportConceptGoalTreeItem child, SupportConceptGoalTreeItem ex_parent, SupportConceptGoalTreeItem parent)
+ {
+ // Entferne child aus Ex-Parent
+ if (ex_parent is object)
+ ex_parent.Items.Remove(child);
+ else
+ GoalTree.Remove(child);
+
+ // Füge child parent hinzu
+ if (parent is object)
+ parent.Items.Add(child);
+ else
+ GoalTree.Add(child);
+
+ // Setze child Parent Entry
+ child.GoalEntryVM.ParentEntry = parent?.GoalEntryDC;
+ child.ParentGoal = parent;
+
+ return new MassnahmenHistoryRecordMove(child, ex_parent, parent);
+ }
+ private void UndoMoveAction(MassnahmenHistoryRecordMove move)
+ {
+ DoMoveAction(move.Child, move.Parent, move.ExParent);
+ }
+ private void RedoMoveAction(MassnahmenHistoryRecordMove move)
+ {
+ DoMoveAction(move.Child, move.ExParent, move.Parent);
+ }
+
+ public MassnahmenHistoryRecordEdit DoEditAction(ValueListEntryDC b, ValueListEntryVM a)
+ {
+ var before = new NodeEditInformation { Abbreviation = b.Abbreviation, Description = b.TypeDescription, Notice = b.Notice };
+ var after = new NodeEditInformation { Abbreviation = a.Abbreviation, Description = a.Description, Notice = a.Notice };
+
+ return new MassnahmenHistoryRecordEdit(a, before, after);
+ }
+ private void UndoEditAction(MassnahmenHistoryRecordEdit edit)
+ {
+ edit.SetVM(edit.Before);
+ }
+ private void RedoEditAction(MassnahmenHistoryRecordEdit edit)
+ {
+ edit.SetVM(edit.After);
+ }
+
+ private Tuple, Action> GetTuple(Action a, Action b) where T1 : MassnahmenHistoryRecord
+ => new Tuple, Action>(x => a(x as T1), x => b(x as T1));
+ private SupportConceptGoalTreeItem AddIcf(SupportConceptGoalDC goal, List records)
+ {
+ if (goal == null) return null;
+
+ // Schaut, ob das Child bereits existiert
+ var similarGoal = GoalTree.FirstOrDefault(x => MassnahmenTreeViewView.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)
+ {
+ // Ist Root Element
+ var record = DoAddAction(null, ValueListEntryType.SupportConceptGoalCategoryType,
+ goal.GoalEntryDC.TypeDescription, goal.GoalEntryDC.Abbreviation, goal.GoalEntryDC.Notice);
+
+ records.Add(record);
+
+ //GoalTree.Sort((x, y) => x.GoalEntryVM?.DisplayName?.CompareTo(y.GoalEntryVM?.DisplayName) ?? string.Compare(string.Empty, y.GoalEntryVM?.DisplayName, StringComparison.Ordinal));
+
+ return record.Current;
+ }
+
+ // Schaut, ob das ParentGoal bereits existiert
+ foreach (var goalTreeItem in GoalTree)
+ {
+ var similarParentGoal = MassnahmenTreeViewView.SearchGoalTreeItem(goalTreeItem, goal.ParentGoal.GoalEntryDC.TypeDescription, goal.ParentGoal.GoalEntryDC.Abbreviation, goal.ParentGoal.GoalEntryDC.Notice);
+ if (similarParentGoal == null)
+ continue;
+
+ var record = DoAddAction(similarParentGoal, ValueListEntryType.SupportConceptGoalCategoryType, goal.GoalEntryDC.TypeDescription, goal.GoalEntryDC.Abbreviation, goal.GoalEntryDC.Notice);
+ records.Add(record);
+ return record.Current;
+ }
+
+ // Fügt den Parent hinzu
+ var parent = AddIcf(goal.ParentGoal, records);
+ var record2 = DoAddAction(parent, ValueListEntryType.SupportConceptGoalCategoryType,
+ goal.GoalEntryDC.TypeDescription, goal.GoalEntryDC.Abbreviation, goal.GoalEntryDC.Notice);
+ records.Add(record2);
+ return record2.Current;
+ }
+
+ private void ActivateSubtree(NodeRelation currentNode, List param)
+ {
+ foreach (var item in param)
+ {
+ ViewModel.VMList.Add(item.Current.GoalEntryVM);
+ }
+
+ if (currentNode.Parent is object)
+ currentNode.Parent.Items.Add(currentNode.Current);
+ else
+ GoalTree.Add(currentNode.Current);
+ }
+ private void ActivateNode(NodeRelation currentNode)
+ {
+ var newItem = currentNode.Current;
+ var parent = currentNode.Parent;
+
+ ViewModel.VMList.Add(newItem.GoalEntryVM);
+
+ if (parent != null)
+ parent.Items.Add(newItem);
+ else
+ GoalTree.Add(newItem);
+ }
+
+ private void DeactivateSubtree(NodeRelation currentNode, IEnumerable param)
+ {
+ foreach (var item in param)
+ {
+ ViewModel.VMList.Remove(item.Current.GoalEntryVM);
+ }
+
+ if (currentNode.Parent is object)
+ currentNode.Parent.Items.Remove(currentNode.Current);
+ else
+ GoalTree.Remove(currentNode.Current);
+ }
+ private void DeactivateNode(NodeRelation currentNode)
+ {
+ var newItem = currentNode.Current;
+ var parent = currentNode.Parent;
+
+ ViewModel.VMList.Remove(newItem.GoalEntryVM);
+
+ if (parent != null)
+ parent.Items.Remove(newItem);
+ else
+ GoalTree.Remove(newItem);
+ }
+ }
+}
diff --git a/BeWo/View/Detail/MassnahmenTreeViewView.xaml b/BeWo/View/Detail/MassnahmenTreeViewView.xaml
index 22cdbd327..7ac7401ca 100644
--- a/BeWo/View/Detail/MassnahmenTreeViewView.xaml
+++ b/BeWo/View/Detail/MassnahmenTreeViewView.xaml
@@ -11,7 +11,7 @@
-
+