From efbff88b1a9c42a0598623eb73873788ce18242e Mon Sep 17 00:00:00 2001 From: Daniel Kraus Date: Sat, 29 Aug 2015 02:06:10 +0200 Subject: [PATCH 01/11] Make ItemsTest work with preferred precisions. --- Tests/Controller/Elements/ItemsTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Controller/Elements/ItemsTest.cs b/Tests/Controller/Elements/ItemsTest.cs index 8bfc489..eb56ed2 100755 --- a/Tests/Controller/Elements/ItemsTest.cs +++ b/Tests/Controller/Elements/ItemsTest.cs @@ -152,7 +152,7 @@ namespace Tests.Controller.Elements StripMarkup( TimePointFormatter.DateAndTimeHeader(new DateTime(2015, 07, 13, 13, 31, 00)) )+ - "Klinische Chemie: Na 133, SU-Protein 2,8\r\r").Replace(Environment.NewLine, "\r"); + "Klinische Chemie: Na 133, SU-Protein 3\r\r").Replace(Environment.NewLine, "\r"); Assert.AreEqual(expected, _document.Range().Text); } @@ -176,7 +176,7 @@ namespace Tests.Controller.Elements StripMarkup( TimePointFormatter.DateAndTimeHeader(new DateTime(2015, 07, 13, 13, 31, 00)) ) + - "Klinische Chemie: Na 133, SU-Protein 2,8, Cl 110, U-Na 99\r\r") + "Klinische Chemie: Na 133, SU-Protein 3, Cl 110, U-Na 99\r\r") .Replace(Environment.NewLine, "\r"); Assert.AreEqual(expected, _document.Range().Text); } From a89a8103e591a8875bdc18347b7122e4d784cc3e Mon Sep 17 00:00:00 2001 From: Daniel Kraus Date: Sat, 29 Aug 2015 03:16:44 +0200 Subject: [PATCH 02/11] Initial implementation of ItemComments. --- Tests/Controller/Elements/ItemsTest.cs | 22 +++ Tests/Formatter/ItemCommentTest.cs | 57 ++++++ Tests/Tests.csproj | 1 + zaaReloaded2/Controller/Elements/Items.cs | 48 ++++- zaaReloaded2/Formatter/Formatter.cs | 80 +++++++- zaaReloaded2/Formatter/ItemComment.cs | 184 ++++++++++++++++++ .../Formatter/ItemCommentEventArgs.cs | 54 +++++ zaaReloaded2/Formatter/ItemFormatter.cs | 6 + zaaReloaded2/zaaReloaded2.csproj | 2 + 9 files changed, 442 insertions(+), 12 deletions(-) create mode 100755 Tests/Formatter/ItemCommentTest.cs create mode 100755 zaaReloaded2/Formatter/ItemComment.cs create mode 100755 zaaReloaded2/Formatter/ItemCommentEventArgs.cs diff --git a/Tests/Controller/Elements/ItemsTest.cs b/Tests/Controller/Elements/ItemsTest.cs index eb56ed2..4f757ad 100755 --- a/Tests/Controller/Elements/ItemsTest.cs +++ b/Tests/Controller/Elements/ItemsTest.cs @@ -181,6 +181,28 @@ namespace Tests.Controller.Elements Assert.AreEqual(expected, _document.Range().Text); } + [Test] + public void ItemCommentWithoutHandler() + { + Laboratory lab = new Laboratory(); + TimePoint tp = new TimePoint(); + tp.TimeStamp = new DateTime(2015, 7, 13, 13, 31, 00); + tp.AddItem(new LabItem("Na", "133", "133")); + tp.AddItem(new LabItem("K", "6", "5")); + lab.AddTimePoint(tp); + + _formatter.Laboratory = lab; + _formatter.Settings.Elements.Add( + new zaa.Items("Na \"(Zielbereich: <> mmol/l)\"")); + _formatter.Run(); + string expected = ( + StripMarkup( + TimePointFormatter.DateAndTimeHeader(new DateTime(2015, 07, 13, 13, 31, 00)) + + "Na 133\r\r").Replace(Environment.NewLine, "\r") + ); + Assert.AreEqual(expected, _document.Range().Text); + } + static string StripMarkup(string s) { return _markupStripper.Replace(s, string.Empty); diff --git a/Tests/Formatter/ItemCommentTest.cs b/Tests/Formatter/ItemCommentTest.cs new file mode 100755 index 0000000..1223273 --- /dev/null +++ b/Tests/Formatter/ItemCommentTest.cs @@ -0,0 +1,57 @@ +/* ItemCommentTest.cs + * part of zaaReloaded2 + * + * Copyright 2015 Daniel Kraus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NUnit.Framework; +using zaaReloaded2.Formatter; + +namespace Tests.Formatter +{ + [TestFixture] + class ItemCommentTest + { + [Test] + public void FactoryWithGoodDefinition() + { + ItemComment i = ItemComment.FromDefinition("TAC \"(Zielbereich: <4-7> µg/l)\""); + Assert.IsNotNull(i); + Assert.AreEqual("(Zielbereich: ", i.Prefix); + Assert.AreEqual("4-7", i.Value); + Assert.AreEqual(" µg/l)", i.Suffix); + Assert.AreEqual("TAC", i.Item); + Assert.AreEqual("(Zielbereich: 4-7 µg/l)", i.BuildComment()); + } + + [Test] + public void FactoryWithBadDefinition() + { + ItemComment i = ItemComment.FromDefinition("some bogus definition"); + Assert.IsNull(i); + } + + [Test] + public void EmptyValueProducesEmptyComment() + { + ItemComment i = ItemComment.FromDefinition("TAC \"(Zielbereich: µg/l)\""); + i.Value = String.Empty; + Assert.AreEqual(String.Empty, i.BuildComment()); + } + } +} diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 644547a..1119cc5 100755 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -80,6 +80,7 @@ + diff --git a/zaaReloaded2/Controller/Elements/Items.cs b/zaaReloaded2/Controller/Elements/Items.cs index 61f403d..8ebf00d 100755 --- a/zaaReloaded2/Controller/Elements/Items.cs +++ b/zaaReloaded2/Controller/Elements/Items.cs @@ -94,6 +94,15 @@ namespace zaaReloaded2.Controller.Elements #endregion + #region Events + + /// + /// Propagates the FillInComment events of collected items. + /// + public event EventHandler FillInComment; + + #endregion + #region Constructors public Items() : base() { } @@ -123,7 +132,7 @@ namespace zaaReloaded2.Controller.Elements { _items = null; _caption = null; - Regex r = new Regex(@"((?[^:]+):\s*)?((?[^,]+),\s*)*(?[^,]+)"); + Regex r = new Regex(@"((?[^:""]+):\s*)?((?[^,]+),\s*)*(?[^,]+)"); Match m = r.Match(Content); if (m.Success) { @@ -186,9 +195,22 @@ namespace zaaReloaded2.Controller.Elements /// /// Collects items for output by name. /// - /// Item name to look for. + /// Item name to look for. If the item name contains + /// a comment definition (see example in the description of the + /// event), List CollectByName(zaaReloaded2.Formatter.Formatter formatter, string name) { + // First, check if the item name contains an optional comment + // definition + ItemComment comment = ItemComment.FromDefinition(name); + if (comment != null) + { + name = comment.Item; + // Enable propagation of FillInComment events + comment.FillInComment += comment_FillInComment; + } + + // Then, see if we have such an item List items = new List(); TimePointFormatter tpf = formatter.WorkingTimePoints .FirstOrDefault(tp => tp.Value.ContainsItem(name)) @@ -200,19 +222,37 @@ namespace zaaReloaded2.Controller.Elements ItemFormatter i = tpf.ItemFormatters[name]; i.HasBeenUsed = true; i.IncludeMaterial = false; + i.Comment = comment; items.Add(i); } return items; } + void comment_FillInComment(object sender, ItemCommentEventArgs e) + { + OnFillInComment(e); + } + + #endregion + + #region Protected methods + + protected virtual void OnFillInComment(ItemCommentEventArgs args) + { + EventHandler h = FillInComment; + if (h != null) + { + h(this, args); + } + } #endregion #region Fields string _caption; List _items; - static Regex _wildcard = new Regex(@"(?[^-]+-)?\*"); - + static readonly Regex _wildcard = new Regex(@"(?[^-]+-)?\*"); + #endregion } } diff --git a/zaaReloaded2/Formatter/Formatter.cs b/zaaReloaded2/Formatter/Formatter.cs index 6639198..c5fd796 100755 --- a/zaaReloaded2/Formatter/Formatter.cs +++ b/zaaReloaded2/Formatter/Formatter.cs @@ -34,7 +34,20 @@ namespace zaaReloaded2.Formatter { #region Properties - public Settings Settings { get; set; } + /// + /// Gets or sets the Settings that this Formatter works with. + /// + public Settings Settings + { + get { return _settings; } + set + { + _settings = value; + // Listen to the FillInComment event of + _settings.Elements.OfType().ToList().ForEach( + items => items.FillInComment += items_FillInComment); + } + } /// /// Gets or sets the that shall be @@ -66,9 +79,28 @@ namespace zaaReloaded2.Formatter /// /// Is true if this Formatter object carries a Laboratory with - /// at least one time point. + /// at least one time point, and if there are Settings to work with. /// - public bool CanRun { get { return Laboratory.TimePoints.Count > 0; } } + public bool CanRun + { + get + { + return (Settings != null) + && (Laboratory != null) + && (Laboratory.TimePoints.Count > 0); + } + } + + #endregion + + #region Event + + /// + /// Relays the FillInComment events of any Items elements + /// in the Settings, which in turn relay the FillInComment + /// events of their collected items' ItemComments. + /// + public event EventHandler FillInComment; #endregion @@ -119,7 +151,14 @@ namespace zaaReloaded2.Formatter /// current position of the cursor). public void Run() { - if (!CanRun) throw new NoLaboratoryDataException("No laboratory data to format."); + if (!CanRun) + { + if (Settings == null) + throw new InvalidOperationException("No settings data to work with."); + if ((Laboratory == null) || Laboratory.TimePoints.Count == 0) + throw new NoLaboratoryDataException("No laboratory data to format."); + throw new InvalidOperationException("Cannot run formatter."); + } int current = 0; while (current < Settings.Elements.Count) @@ -147,12 +186,19 @@ namespace zaaReloaded2.Formatter } // Write everything to the Word document - Globals.ThisAddIn.Application.UndoRecord.StartCustomRecord( - String.Format("Laborformatierung ({0})", Properties.Settings.Default.AddinName) - ); + bool hasAddin = Globals.ThisAddIn != null; + if (hasAddin) + { + Globals.ThisAddIn.Application.UndoRecord.StartCustomRecord( + String.Format("Laborformatierung ({0})", Properties.Settings.Default.AddinName) + ); + } CreateStyles(); _secondaryBuffer.Flush(); - Globals.ThisAddIn.Application.UndoRecord.EndCustomRecord(); + if (hasAddin) + { + Globals.ThisAddIn.Application.UndoRecord.EndCustomRecord(); + } } /// @@ -385,6 +431,23 @@ namespace zaaReloaded2.Formatter #endregion + #region Private methods + + /// + /// Relays the FillInComment event of Items elements in the + /// Settings. + /// + void items_FillInComment(object sender, ItemCommentEventArgs e) + { + EventHandler h = FillInComment; + if (h != null) + { + h(this, e); + } + } + + #endregion + #region Protected properties /// @@ -396,6 +459,7 @@ namespace zaaReloaded2.Formatter #region Fields + Settings _settings; TimePointFormatterDictionary _timePointFormatters; Laboratory _laboratory; DocumentWriter _primaryBuffer; diff --git a/zaaReloaded2/Formatter/ItemComment.cs b/zaaReloaded2/Formatter/ItemComment.cs new file mode 100755 index 0000000..157eebf --- /dev/null +++ b/zaaReloaded2/Formatter/ItemComment.cs @@ -0,0 +1,184 @@ +/* ParameterComment.cs + * part of zaaReloaded2 + * + * Copyright 2015 Daniel Kraus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace zaaReloaded2.Formatter +{ + /// + /// Represents an optional comment for a laboratory item. + /// The zaaReloaded2.Controller.Elements.Items class can + /// parse these optional comment strings which may be used + /// to prompt users to enter target ranges etc. + /// + /// + /// TAC "(Zielspiegel: <8-10> µg/l)" + /// + /// + /// In the example, the tacrolimus trough level TAC carries a comment about the + /// recommended range. The comment must be enclosed in quotes in order for it + /// to be recognized. The quotes will be stripped. The angle brackets denote + /// a place holder that will be replaced by the comment that is set in the + /// RequestParameterComment's event args. The text between the angle brackets + /// ("8-10") is an optional default value. One could also just use 'empty' + /// brackets ("<>"). + /// + public class ItemComment + { + #region Factory + + /// + /// Creates a new ItemComment object from a definition. + /// + /// Definition string. + /// ItemComment object, or null if the + /// string could not be + /// parsed. + public static ItemComment FromDefinition(string definition) + { + ItemComment itemComment = null; + // TODO: Maybe turn these to regexes into one. + Match checkHasComment = _itemDefinition.Match(definition); + if (checkHasComment.Success) + { + Match commentComponents = + _commentDefinition.Match(checkHasComment.Groups["comment"].Value); + if (commentComponents.Success) + { + itemComment = new ItemComment( + checkHasComment.Groups["item"].Value.Trim(), + commentComponents.Groups["prefix"].Value, + commentComponents.Groups["value"].Value, + commentComponents.Groups["suffix"].Value + ); + } + } + return itemComment; + } + + #endregion + + #region Properties + + /// + /// Gets or sets the item name that this comment is for. + /// + public string Item { get; set; } + + /// + /// Prefix of this comment, e.g. "(target trough level: " + /// + public string Prefix { get; set; } + + /// + /// Value of this comment; String.Empty represents a + /// cancelled comment. + /// + public string Value { get; set; } + + /// + /// Suffix of this comment, e.g. " µg/l)" + /// + public string Suffix { get; set; } + + #endregion + + #region Event + + /// + /// Event that is raised when the comment value needs to be + /// filled in by someone or something. + /// + public event EventHandler FillInComment; + + #endregion + + #region Constructors + + public ItemComment() + { + Item = String.Empty; + Prefix = String.Empty; + Value = String.Empty; + Suffix = String.Empty; + } + + public ItemComment(string item, string prefix, string value, string suffix) + { + Item = item; + Prefix = prefix; + Value = value; + Suffix = suffix; + } + + #endregion + + #region Methods + + /// + /// Builds the comment string from the prefix, the value, and + /// the suffix. Raises the FillInComment event to get the value + /// first. If the value is an empty string, the entire comment + /// string will be an empty string. + /// + /// Comment string with filled-in value, or String.Empty + /// if the value is an empty string. + public string BuildComment() + { + OnFillInComment(); + + if (String.IsNullOrEmpty(Value)) + return String.Empty; + + return Prefix + Value + Suffix; + } + + #endregion + + #region Private methods + + /// + /// Raises the FillInComment event. + /// + protected virtual void OnFillInComment() + { + EventHandler h = FillInComment; + if (h != null) + { + ItemCommentEventArgs args = new ItemCommentEventArgs(this); + h(this, args); + if (args.IsCancelled) + args.Comment.Value = String.Empty; + } + } + + #endregion + + #region Fields + + static readonly Regex _itemDefinition = + new Regex(@"(?[^""]+)""(?[^""]+)"""); + static readonly Regex _commentDefinition = + new Regex(@"(?[^<]+)<(?[^>]*)>(?[^""]+)"); + + #endregion + } +} diff --git a/zaaReloaded2/Formatter/ItemCommentEventArgs.cs b/zaaReloaded2/Formatter/ItemCommentEventArgs.cs new file mode 100755 index 0000000..9787ed9 --- /dev/null +++ b/zaaReloaded2/Formatter/ItemCommentEventArgs.cs @@ -0,0 +1,54 @@ +/* ParameterCommentEventArgs.cs + * part of zaaReloaded2 + * + * Copyright 2015 Daniel Kraus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace zaaReloaded2.Formatter +{ + /// + /// Event arguments used in item commenting. + /// + public class ItemCommentEventArgs : EventArgs + { + #region Properties + + /// + /// Gets the comment object for this parameter. + /// + public ItemComment Comment { get; private set; } + + /// + /// Gets or sets whether the commenting was cancelled. + /// + public bool IsCancelled { get; set; } + + #endregion + + #region Constructor + + public ItemCommentEventArgs( + ItemComment comment) + { + Comment = comment; + } + + #endregion + } +} diff --git a/zaaReloaded2/Formatter/ItemFormatter.cs b/zaaReloaded2/Formatter/ItemFormatter.cs index c71baf9..fcd5fd1 100755 --- a/zaaReloaded2/Formatter/ItemFormatter.cs +++ b/zaaReloaded2/Formatter/ItemFormatter.cs @@ -70,6 +70,11 @@ namespace zaaReloaded2.Formatter /// public bool IsBlacklisted { get { return LabItem.IsBlacklisted; } } + /// + /// Gets or sets the item's comment. + /// + public ItemComment Comment { get; set; } + #endregion #region Constructor @@ -184,6 +189,7 @@ namespace zaaReloaded2.Formatter output = AbnormalStyle.ToMarkup(false) + output + AbnormalStyle.ToMarkup(true); } + formatter.Write(output); HasBeenUsed = true; } diff --git a/zaaReloaded2/zaaReloaded2.csproj b/zaaReloaded2/zaaReloaded2.csproj index 6d33e56..bfbc184 100755 --- a/zaaReloaded2/zaaReloaded2.csproj +++ b/zaaReloaded2/zaaReloaded2.csproj @@ -195,6 +195,8 @@ + + From 02b4bc07a3f5c3334afc9061c0cbb632d3a5a5c9 Mon Sep 17 00:00:00 2001 From: Daniel Kraus Date: Sun, 30 Aug 2015 07:48:32 +0200 Subject: [PATCH 03/11] Working comments with CommentPool. --- Tests/Controller/Comments/CommentPoolTest.cs | 60 ++++++++ .../Comments}/ItemCommentTest.cs | 9 +- Tests/Controller/Elements/ItemsTest.cs | 31 ++++ Tests/Tests.csproj | 3 +- .../Controller/Comments/CommentPool.cs | 134 ++++++++++++++++++ .../Comments}/ItemComment.cs | 61 ++++---- .../Comments}/ItemCommentEventArgs.cs | 2 +- zaaReloaded2/Controller/Elements/Items.cs | 31 +--- zaaReloaded2/Formatter/Formatter.cs | 41 +----- zaaReloaded2/Formatter/ItemFormatter.cs | 14 +- zaaReloaded2/zaaReloaded2.csproj | 5 +- 11 files changed, 285 insertions(+), 106 deletions(-) create mode 100755 Tests/Controller/Comments/CommentPoolTest.cs rename Tests/{Formatter => Controller/Comments}/ItemCommentTest.cs (80%) create mode 100755 zaaReloaded2/Controller/Comments/CommentPool.cs rename zaaReloaded2/{Formatter => Controller/Comments}/ItemComment.cs (76%) rename zaaReloaded2/{Formatter => Controller/Comments}/ItemCommentEventArgs.cs (97%) diff --git a/Tests/Controller/Comments/CommentPoolTest.cs b/Tests/Controller/Comments/CommentPoolTest.cs new file mode 100755 index 0000000..d993e4f --- /dev/null +++ b/Tests/Controller/Comments/CommentPoolTest.cs @@ -0,0 +1,60 @@ +/* CommentPoolTest.cs + * part of zaaReloaded2 + * + * Copyright 2015 Daniel Kraus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NUnit.Framework; +using zaaReloaded2.Controller.Comments; + +namespace Tests.Controller.Comments +{ + [TestFixture] + class CommentPoolTest + { + [Test] + public void CreateCommentIfDoesNotExist() + { + int n = CommentPool.Default.Count; + ItemComment i = CommentPool.Default.GetCommentFor("item \"<>\""); + Assert.AreEqual(n + 1, CommentPool.Default.Count); + } + + [Test] + public void ReturnExistingComment() + { + ItemComment i = CommentPool.Default.GetCommentFor("item \"<>\""); + int n = CommentPool.Default.Count; + i = CommentPool.Default.GetCommentFor("item \"<>\""); + Assert.AreEqual(n, CommentPool.Default.Count); + } + + [Test] + public void BuildingCommentRaisesEvent() + { + ItemComment i = CommentPool.Default.GetCommentFor("item \"<>\""); + bool eventRaised = false; + CommentPool.Default.FillInComment += (sender, args) => + { + eventRaised = true; + }; + string comment = i.BuildComment(); + Assert.IsTrue(eventRaised); + } + } +} diff --git a/Tests/Formatter/ItemCommentTest.cs b/Tests/Controller/Comments/ItemCommentTest.cs similarity index 80% rename from Tests/Formatter/ItemCommentTest.cs rename to Tests/Controller/Comments/ItemCommentTest.cs index 1223273..bb1aaa2 100755 --- a/Tests/Formatter/ItemCommentTest.cs +++ b/Tests/Controller/Comments/ItemCommentTest.cs @@ -21,8 +21,9 @@ using System.Linq; using System.Text; using NUnit.Framework; using zaaReloaded2.Formatter; +using zaaReloaded2.Controller.Comments; -namespace Tests.Formatter +namespace Tests.Controller.Comments { [TestFixture] class ItemCommentTest @@ -30,7 +31,7 @@ namespace Tests.Formatter [Test] public void FactoryWithGoodDefinition() { - ItemComment i = ItemComment.FromDefinition("TAC \"(Zielbereich: <4-7> µg/l)\""); + ItemComment i = ItemComment.FromDefinitionString("TAC \"(Zielbereich: <4-7> µg/l)\""); Assert.IsNotNull(i); Assert.AreEqual("(Zielbereich: ", i.Prefix); Assert.AreEqual("4-7", i.Value); @@ -42,14 +43,14 @@ namespace Tests.Formatter [Test] public void FactoryWithBadDefinition() { - ItemComment i = ItemComment.FromDefinition("some bogus definition"); + ItemComment i = ItemComment.FromDefinitionString("some bogus definition"); Assert.IsNull(i); } [Test] public void EmptyValueProducesEmptyComment() { - ItemComment i = ItemComment.FromDefinition("TAC \"(Zielbereich: µg/l)\""); + ItemComment i = ItemComment.FromDefinitionString("TAC \"(Zielbereich: µg/l)\""); i.Value = String.Empty; Assert.AreEqual(String.Empty, i.BuildComment()); } diff --git a/Tests/Controller/Elements/ItemsTest.cs b/Tests/Controller/Elements/ItemsTest.cs index 4f757ad..ff473f3 100755 --- a/Tests/Controller/Elements/ItemsTest.cs +++ b/Tests/Controller/Elements/ItemsTest.cs @@ -24,7 +24,9 @@ using Microsoft.Office.Interop.Word; using zaaReloaded2.LabModel; using zaaReloaded2.Formatter; using zaa = zaaReloaded2.Controller.Elements; +using zaaReloaded2.Controller.Comments; using System.Text.RegularExpressions; +using zaaReloaded2.Controller.Comments; namespace Tests.Controller.Elements { @@ -203,6 +205,35 @@ namespace Tests.Controller.Elements Assert.AreEqual(expected, _document.Range().Text); } + [Test] + public void ItemCommentWithHandler() + { + Laboratory lab = new Laboratory(); + TimePoint tp = new TimePoint(); + tp.TimeStamp = new DateTime(2015, 7, 13, 13, 31, 00); + tp.AddItem(new LabItem("Na", "133", "133")); + tp.AddItem(new LabItem("K", "6", "5")); + lab.AddTimePoint(tp); + + _formatter.Laboratory = lab; + _formatter.Settings.Elements.Add( + new zaa.Items("Na \"(Zielbereich: µg/l)\"")); + bool messageSent = false; + CommentPool.Default.FillInComment += (sender, args) => + { + messageSent = true; + args.Comment.Value = "4-7"; + }; + _formatter.Run(); + Assert.IsTrue(messageSent, "FillInComment message was not sent"); + string expected = ( + StripMarkup( + TimePointFormatter.DateAndTimeHeader(new DateTime(2015, 07, 13, 13, 31, 00)) + + "Na 133 (Zielbereich: 4-7 µg/l)\r\r").Replace(Environment.NewLine, "\r") + ); + Assert.AreEqual(expected, _document.Range().Text); + } + static string StripMarkup(string s) { return _markupStripper.Replace(s, string.Empty); diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 1119cc5..e6a43dc 100755 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -80,7 +80,8 @@ - + + diff --git a/zaaReloaded2/Controller/Comments/CommentPool.cs b/zaaReloaded2/Controller/Comments/CommentPool.cs new file mode 100755 index 0000000..4c9f9cd --- /dev/null +++ b/zaaReloaded2/Controller/Comments/CommentPool.cs @@ -0,0 +1,134 @@ +/* CommentPool.cs + * part of zaaReloaded2 + * + * Copyright 2015 Daniel Kraus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace zaaReloaded2.Controller.Comments +{ + /// + /// A pool of comments. + /// + class CommentPool + { + #region Singleton + + /// + /// Gets the singleton instance of the CommentPool. + /// + public static CommentPool Default + { + get + { + return _instance; + } + } + + private static readonly CommentPool _instance = new CommentPool(); + + #endregion + + #region Properties + + /// + /// Gets the number of ItemComments in the pool. + /// + public int Count { get { return _itemComments.Count; } } + + #endregion + + #region Event + + public event EventHandler FillInComment; + + #endregion + + #region Constructor + + /// + /// Static constructor to support the singleton implementation. + /// + /// + /// See http://csharpindepth.com/Articles/General/Singleton.aspx#cctor + /// + static CommentPool() { } + + private CommentPool() + { + _itemComments = new List(); + } + + #endregion + + #region Methods + + /// + /// Retrieves the ItemComment for a given definitionString; + /// creates a new ItemComment object if necessary. + /// + /// + /// ItemComment derived from the + /// + public ItemComment GetCommentFor(string definitionString) + { + ItemComment itemComment = _itemComments.FirstOrDefault( + i => i.Definition == definitionString); + if (itemComment == null) + { + itemComment = ItemComment.FromDefinitionString(definitionString); + if (itemComment != null) + { + _itemComments.Add(itemComment); + itemComment.FillInComment += itemComment_FillInComment; + } + } + return itemComment; + } + + #endregion + + #region Pribate methods + + protected virtual void itemComment_FillInComment(object sender, ItemCommentEventArgs e) + { + OnFillInComment(e); + } + + #endregion + + #region Protected methods + + protected virtual void OnFillInComment(ItemCommentEventArgs args) + { + EventHandler h = FillInComment; + if (h != null) + { + h(this, args); + } + } + + #endregion + + #region Fields + + List _itemComments; + + #endregion + } +} diff --git a/zaaReloaded2/Formatter/ItemComment.cs b/zaaReloaded2/Controller/Comments/ItemComment.cs similarity index 76% rename from zaaReloaded2/Formatter/ItemComment.cs rename to zaaReloaded2/Controller/Comments/ItemComment.cs index 157eebf..dac8c8a 100755 --- a/zaaReloaded2/Formatter/ItemComment.cs +++ b/zaaReloaded2/Controller/Comments/ItemComment.cs @@ -21,7 +21,7 @@ using System.Linq; using System.Text; using System.Text.RegularExpressions; -namespace zaaReloaded2.Formatter +namespace zaaReloaded2.Controller.Comments { /// /// Represents an optional comment for a laboratory item. @@ -46,34 +46,30 @@ namespace zaaReloaded2.Formatter #region Factory /// - /// Creates a new ItemComment object from a definition. + /// Creates a new ItemComment object from a definition string. /// - /// Definition string. - /// ItemComment object, or null if the - /// string could not be - /// parsed. - public static ItemComment FromDefinition(string definition) + /// String that complies + /// with the definition pattern (item "optional prefix <optional + /// default value> optioal suffix"). + public static ItemComment FromDefinitionString(string definitionString) { - ItemComment itemComment = null; - // TODO: Maybe turn these to regexes into one. - Match checkHasComment = _itemDefinition.Match(definition); - if (checkHasComment.Success) + Match match = _definition.Match(definitionString); + if (match.Success) { - Match commentComponents = - _commentDefinition.Match(checkHasComment.Groups["comment"].Value); - if (commentComponents.Success) - { - itemComment = new ItemComment( - checkHasComment.Groups["item"].Value.Trim(), - commentComponents.Groups["prefix"].Value, - commentComponents.Groups["value"].Value, - commentComponents.Groups["suffix"].Value - ); - } + return new ItemComment( + definitionString, + match.Groups["item"].Value.Trim(), + match.Groups["prefix"].Value, + match.Groups["value"].Value, + match.Groups["suffix"].Value); + } + else + { + return null; } - return itemComment; } + #endregion #region Properties @@ -99,6 +95,12 @@ namespace zaaReloaded2.Formatter /// public string Suffix { get; set; } + /// + /// Gets the original definition string that this ItemComment + /// was created from. + /// + public string Definition { get; private set; } + #endregion #region Event @@ -122,6 +124,7 @@ namespace zaaReloaded2.Formatter } public ItemComment(string item, string prefix, string value, string suffix) + : this() { Item = item; Prefix = prefix; @@ -129,6 +132,12 @@ namespace zaaReloaded2.Formatter Suffix = suffix; } + public ItemComment(string definition, string item, string prefix, string value, string suffix) + : this(item, prefix, value, suffix) + { + Definition = definition; + } + #endregion #region Methods @@ -174,10 +183,8 @@ namespace zaaReloaded2.Formatter #region Fields - static readonly Regex _itemDefinition = - new Regex(@"(?[^""]+)""(?[^""]+)"""); - static readonly Regex _commentDefinition = - new Regex(@"(?[^<]+)<(?[^>]*)>(?[^""]+)"); + static readonly Regex _definition = + new Regex(@"(?[^""]+)""(?[^<]+)?<(?[^>]*)>(?[^""]+)?"""); #endregion } diff --git a/zaaReloaded2/Formatter/ItemCommentEventArgs.cs b/zaaReloaded2/Controller/Comments/ItemCommentEventArgs.cs similarity index 97% rename from zaaReloaded2/Formatter/ItemCommentEventArgs.cs rename to zaaReloaded2/Controller/Comments/ItemCommentEventArgs.cs index 9787ed9..b6deaec 100755 --- a/zaaReloaded2/Formatter/ItemCommentEventArgs.cs +++ b/zaaReloaded2/Controller/Comments/ItemCommentEventArgs.cs @@ -20,7 +20,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; -namespace zaaReloaded2.Formatter +namespace zaaReloaded2.Controller.Comments { /// /// Event arguments used in item commenting. diff --git a/zaaReloaded2/Controller/Elements/Items.cs b/zaaReloaded2/Controller/Elements/Items.cs index 8ebf00d..d8f8b63 100755 --- a/zaaReloaded2/Controller/Elements/Items.cs +++ b/zaaReloaded2/Controller/Elements/Items.cs @@ -24,6 +24,7 @@ using Microsoft.Office.Interop.Word; using zaaReloaded2.LabModel; using zaaReloaded2.Formatter; using System.Runtime.Serialization; +using zaaReloaded2.Controller.Comments; namespace zaaReloaded2.Controller.Elements { @@ -94,15 +95,6 @@ namespace zaaReloaded2.Controller.Elements #endregion - #region Events - - /// - /// Propagates the FillInComment events of collected items. - /// - public event EventHandler FillInComment; - - #endregion - #region Constructors public Items() : base() { } @@ -202,12 +194,10 @@ namespace zaaReloaded2.Controller.Elements { // First, check if the item name contains an optional comment // definition - ItemComment comment = ItemComment.FromDefinition(name); + ItemComment comment = CommentPool.Default.GetCommentFor(name); if (comment != null) { name = comment.Item; - // Enable propagation of FillInComment events - comment.FillInComment += comment_FillInComment; } // Then, see if we have such an item @@ -228,23 +218,6 @@ namespace zaaReloaded2.Controller.Elements return items; } - void comment_FillInComment(object sender, ItemCommentEventArgs e) - { - OnFillInComment(e); - } - - #endregion - - #region Protected methods - - protected virtual void OnFillInComment(ItemCommentEventArgs args) - { - EventHandler h = FillInComment; - if (h != null) - { - h(this, args); - } - } #endregion #region Fields diff --git a/zaaReloaded2/Formatter/Formatter.cs b/zaaReloaded2/Formatter/Formatter.cs index c5fd796..b18010e 100755 --- a/zaaReloaded2/Formatter/Formatter.cs +++ b/zaaReloaded2/Formatter/Formatter.cs @@ -37,17 +37,7 @@ namespace zaaReloaded2.Formatter /// /// Gets or sets the Settings that this Formatter works with. /// - public Settings Settings - { - get { return _settings; } - set - { - _settings = value; - // Listen to the FillInComment event of - _settings.Elements.OfType().ToList().ForEach( - items => items.FillInComment += items_FillInComment); - } - } + public Settings Settings { get; set; } /// /// Gets or sets the that shall be @@ -93,17 +83,6 @@ namespace zaaReloaded2.Formatter #endregion - #region Event - - /// - /// Relays the FillInComment events of any Items elements - /// in the Settings, which in turn relay the FillInComment - /// events of their collected items' ItemComments. - /// - public event EventHandler FillInComment; - - #endregion - #region Constructors public Formatter() @@ -431,23 +410,6 @@ namespace zaaReloaded2.Formatter #endregion - #region Private methods - - /// - /// Relays the FillInComment event of Items elements in the - /// Settings. - /// - void items_FillInComment(object sender, ItemCommentEventArgs e) - { - EventHandler h = FillInComment; - if (h != null) - { - h(this, e); - } - } - - #endregion - #region Protected properties /// @@ -459,7 +421,6 @@ namespace zaaReloaded2.Formatter #region Fields - Settings _settings; TimePointFormatterDictionary _timePointFormatters; Laboratory _laboratory; DocumentWriter _primaryBuffer; diff --git a/zaaReloaded2/Formatter/ItemFormatter.cs b/zaaReloaded2/Formatter/ItemFormatter.cs index fcd5fd1..cc27a14 100755 --- a/zaaReloaded2/Formatter/ItemFormatter.cs +++ b/zaaReloaded2/Formatter/ItemFormatter.cs @@ -21,6 +21,7 @@ using System.Linq; using System.Text; using Microsoft.Office.Interop.Word; using zaaReloaded2.LabModel; +using zaaReloaded2.Controller.Comments; namespace zaaReloaded2.Formatter { @@ -174,15 +175,24 @@ namespace zaaReloaded2.Formatter value = LabItem.Value; } + string comment = String.Empty; + if (Comment != null) + { + comment = Comment.BuildComment(); + if (comment != String.Empty) comment = " " + comment; + } + string name = IncludeMaterial ? LabItem.QualifiedName : LabItem.Name; + string output = String.Format( - "{0} {1}{2}{3}", + "{0} {1}{2}{3}{4}", name, value, unit, - reference + reference, + comment ); if (!LabItem.IsNormal) { diff --git a/zaaReloaded2/zaaReloaded2.csproj b/zaaReloaded2/zaaReloaded2.csproj index bfbc184..07448a3 100755 --- a/zaaReloaded2/zaaReloaded2.csproj +++ b/zaaReloaded2/zaaReloaded2.csproj @@ -192,11 +192,12 @@ can be found. --> + - - + + From 9068dde1c368b10f8013b0dd0dd11fe3a6ae4446 Mon Sep 17 00:00:00 2001 From: Daniel Kraus Date: Sun, 30 Aug 2015 20:32:37 +0200 Subject: [PATCH 04/11] Implement ItemComment view model and view. - NEU: Optionale Kommentare zu Laborwerten. --- Tests/Controller/Comments/CommentPoolTest.cs | 6 +- Tests/Controller/Elements/ItemsTest.cs | 4 - Tests/Tests.csproj | 1 + Tests/ViewModels/ItemCommentViewModelTest.cs | 42 ++++++ .../Controller/Comments/CommentPool.cs | 12 +- zaaReloaded2/Controller/Elements/Items.cs | 2 +- zaaReloaded2/Ribbon.cs | 13 ++ .../ViewModels/ItemCommentViewModel.cs | 126 ++++++++++++++++++ zaaReloaded2/Views/ItemCommentView.xaml | 50 +++++++ zaaReloaded2/Views/ItemCommentView.xaml.cs | 33 +++++ zaaReloaded2/zaaReloaded2.csproj | 8 ++ 11 files changed, 288 insertions(+), 9 deletions(-) create mode 100755 Tests/ViewModels/ItemCommentViewModelTest.cs create mode 100755 zaaReloaded2/ViewModels/ItemCommentViewModel.cs create mode 100755 zaaReloaded2/Views/ItemCommentView.xaml create mode 100755 zaaReloaded2/Views/ItemCommentView.xaml.cs diff --git a/Tests/Controller/Comments/CommentPoolTest.cs b/Tests/Controller/Comments/CommentPoolTest.cs index d993e4f..e29fd52 100755 --- a/Tests/Controller/Comments/CommentPoolTest.cs +++ b/Tests/Controller/Comments/CommentPoolTest.cs @@ -48,13 +48,13 @@ namespace Tests.Controller.Comments public void BuildingCommentRaisesEvent() { ItemComment i = CommentPool.Default.GetCommentFor("item \"<>\""); - bool eventRaised = false; + int eventRaised = 0; CommentPool.Default.FillInComment += (sender, args) => { - eventRaised = true; + eventRaised += 1; }; string comment = i.BuildComment(); - Assert.IsTrue(eventRaised); + Assert.AreEqual(1, eventRaised); } } } diff --git a/Tests/Controller/Elements/ItemsTest.cs b/Tests/Controller/Elements/ItemsTest.cs index ff473f3..28401cb 100755 --- a/Tests/Controller/Elements/ItemsTest.cs +++ b/Tests/Controller/Elements/ItemsTest.cs @@ -16,9 +16,6 @@ * limitations under the License. */ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using NUnit.Framework; using Microsoft.Office.Interop.Word; using zaaReloaded2.LabModel; @@ -26,7 +23,6 @@ using zaaReloaded2.Formatter; using zaa = zaaReloaded2.Controller.Elements; using zaaReloaded2.Controller.Comments; using System.Text.RegularExpressions; -using zaaReloaded2.Controller.Comments; namespace Tests.Controller.Elements { diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index e6a43dc..edc784d 100755 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -98,6 +98,7 @@ + diff --git a/Tests/ViewModels/ItemCommentViewModelTest.cs b/Tests/ViewModels/ItemCommentViewModelTest.cs new file mode 100755 index 0000000..5d3b3bd --- /dev/null +++ b/Tests/ViewModels/ItemCommentViewModelTest.cs @@ -0,0 +1,42 @@ +/* ItemCommentViewModelTest.cs + * part of zaaReloaded2 + * + * Copyright 2015 Daniel Kraus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NUnit.Framework; +using zaaReloaded2.Controller.Comments; +using zaaReloaded2.ViewModels; + +namespace Tests.ViewModels +{ + [TestFixture] + class ItemCommentViewModelTest + { + [Test] + public void Properties() + { + ItemComment comment = new ItemComment("item", "pre", "val", "suf"); + ItemCommentViewModel vm = new ItemCommentViewModel(comment); + Assert.AreEqual(comment.Item, vm.Item); + Assert.AreEqual(comment.Prefix, vm.Prefix); + Assert.AreEqual(comment.Suffix, vm.Suffix); + Assert.AreEqual(comment.Value, vm.Value); + } + } +} diff --git a/zaaReloaded2/Controller/Comments/CommentPool.cs b/zaaReloaded2/Controller/Comments/CommentPool.cs index 4c9f9cd..69775e6 100755 --- a/zaaReloaded2/Controller/Comments/CommentPool.cs +++ b/zaaReloaded2/Controller/Comments/CommentPool.cs @@ -78,6 +78,16 @@ namespace zaaReloaded2.Controller.Comments #region Methods + /// + /// Clear the pool of ItemComments and sets the event handler + /// to null. + /// + public void Reset() + { + _itemComments.Clear(); + FillInComment = null; + } + /// /// Retrieves the ItemComment for a given definitionString; /// creates a new ItemComment object if necessary. @@ -103,7 +113,7 @@ namespace zaaReloaded2.Controller.Comments #endregion - #region Pribate methods + #region Private methods protected virtual void itemComment_FillInComment(object sender, ItemCommentEventArgs e) { diff --git a/zaaReloaded2/Controller/Elements/Items.cs b/zaaReloaded2/Controller/Elements/Items.cs index d8f8b63..0ce89fc 100755 --- a/zaaReloaded2/Controller/Elements/Items.cs +++ b/zaaReloaded2/Controller/Elements/Items.cs @@ -224,7 +224,7 @@ namespace zaaReloaded2.Controller.Elements string _caption; List _items; - static readonly Regex _wildcard = new Regex(@"(?[^-]+-)?\*"); + static readonly Regex _wildcard = new Regex(@"^(?[^-]+-)?\*$"); #endregion } diff --git a/zaaReloaded2/Ribbon.cs b/zaaReloaded2/Ribbon.cs index a556054..99412c6 100755 --- a/zaaReloaded2/Ribbon.cs +++ b/zaaReloaded2/Ribbon.cs @@ -31,6 +31,7 @@ using zaaReloaded2.ViewModels; using zaaReloaded2.Importer.ZaaImporter; using zaaReloaded2.Formatter; using zaaReloaded2.Controller; +using zaaReloaded2.Controller.Comments; using Word = Microsoft.Office.Interop.Word; using Bovender.Mvvm.Actions; using Bovender.Mvvm.Messaging; @@ -201,6 +202,8 @@ namespace zaaReloaded2 Globals.ThisAddIn.Application.ActiveDocument); formatter.Settings = settings; formatter.Laboratory = importer.Laboratory; + CommentPool.Default.Reset(); + CommentPool.Default.FillInComment += CommentPool_FillInComment; try { formatter.Run(); @@ -215,6 +218,16 @@ namespace zaaReloaded2 } } + void CommentPool_FillInComment(object sender, ItemCommentEventArgs e) + { + ItemCommentViewModel vm = new ItemCommentViewModel(e.Comment); + vm.CancelMessage.Sent += (cancelSender, cancelArgs) => + { + e.IsCancelled = true; + }; + vm.InjectInto().ShowDialog(); + } + void DoChooseSettings() { SettingsRepository repository = SettingsRepository.Load(); diff --git a/zaaReloaded2/ViewModels/ItemCommentViewModel.cs b/zaaReloaded2/ViewModels/ItemCommentViewModel.cs new file mode 100755 index 0000000..5cef561 --- /dev/null +++ b/zaaReloaded2/ViewModels/ItemCommentViewModel.cs @@ -0,0 +1,126 @@ +/* ItemCommentViewModel.cs + * part of zaaReloaded2 + * + * Copyright 2015 Daniel Kraus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Bovender.Mvvm; +using Bovender.Mvvm.ViewModels; +using Bovender.Mvvm.Messaging; +using zaaReloaded2.Controller.Comments; + +namespace zaaReloaded2.ViewModels +{ + /// + /// View model for zaaReloaded2.Controller.Comments.ItemComment. + /// + public class ItemCommentViewModel : ViewModelBase + { + #region Properties + + public string Item { get { return _itemComment.Item; } } + + public string Prefix { get { return _itemComment.Prefix; } } + + public string Value + { + get + { + return _itemComment.Value; + } + set + { + _itemComment.Value = value; + OnPropertyChanged("Value"); + } + } + + public string Suffix { get { return _itemComment.Suffix; } } + + #endregion + + #region Commands + + DelegatingCommand CancelCommand + { + get + { + if (_cancelCommand == null) + { + _cancelCommand = new DelegatingCommand( + param => DoCancel()); + } + return _cancelCommand; + } + } + + #endregion + + #region Message + + public Message CancelMessage + { + get + { + if (_cancelMessage == null) + { + _cancelMessage = new Message(); + } + return _cancelMessage; + } + } + + #endregion + + #region Constructor + + public ItemCommentViewModel(ItemComment itemComment) + { + _itemComment = itemComment; + } + + #endregion + + #region Implementation of ViewModelBase + + public override object RevealModelObject() + { + return _itemComment; + } + + #endregion + + #region Private methods + + void DoCancel() + { + CancelMessage.Send(new ViewModelMessageContent(this)); + DoCloseView(); + } + + #endregion + + #region Fields + + DelegatingCommand _cancelCommand; + Message _cancelMessage; + ItemComment _itemComment; + + #endregion + } +} diff --git a/zaaReloaded2/Views/ItemCommentView.xaml b/zaaReloaded2/Views/ItemCommentView.xaml new file mode 100755 index 0000000..954a2ec --- /dev/null +++ b/zaaReloaded2/Views/ItemCommentView.xaml @@ -0,0 +1,50 @@ + + + + + + + +