OSDN Git Service

任務一覧を自動的にスクロールする
authorKazuhiro Fujieda <fujieda@users.osdn.me>
Mon, 13 May 2019 11:20:55 +0000 (20:20 +0900)
committerKazuhiro Fujieda <fujieda@users.osdn.me>
Mon, 13 May 2019 11:20:55 +0000 (20:20 +0900)
KancolleSniffer.Test/KancolleSniffer.Test.csproj
KancolleSniffer.Test/QuestPanelTest.cs [new file with mode: 0644]
KancolleSniffer/Model/QuestInfo.cs
KancolleSniffer/View/QuestPanel.cs

index 1be0817..4739182 100644 (file)
@@ -83,6 +83,7 @@
     <Compile Include="BattleLogProcessorTest.cs" />\r
     <Compile Include="BattleBriefTest.cs" />\r
     <Compile Include="BattleTest.cs" />\r
+    <Compile Include="QuestPanelTest.cs" />\r
     <Compile Include="RepairShipCountTest.cs" />\r
     <Compile Include="ShipStatusTest.cs" />\r
     <Compile Include="PrivacyTest.cs" />\r
diff --git a/KancolleSniffer.Test/QuestPanelTest.cs b/KancolleSniffer.Test/QuestPanelTest.cs
new file mode 100644 (file)
index 0000000..2192724
--- /dev/null
@@ -0,0 +1,246 @@
+// Copyright (C) 2019 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
+//\r
+// Licensed under the Apache License, Version 2.0 (the "License");\r
+// you may not use this file except in compliance with the License.\r
+// You may obtain a copy of the License at\r
+//\r
+//    http://www.apache.org/licenses/LICENSE-2.0\r
+//\r
+// Unless required by applicable law or agreed to in writing, software\r
+// distributed under the License is distributed on an "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+// See the License for the specific language governing permissions and\r
+// limitations under the License.\r
+\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using KancolleSniffer.Model;\r
+using KancolleSniffer.View;\r
+using Microsoft.VisualStudio.TestTools.UnitTesting;\r
+\r
+namespace KancolleSniffer.Test\r
+{\r
+    [TestClass]\r
+    public class QuestPanelTest\r
+    {\r
+        private const int Lines = 4;\r
+        private const int AcceptMax = 7;\r
+        private readonly QuestPanel _panel = new QuestPanel();\r
+        private readonly QuestCountList _countList = new QuestCountList();\r
+\r
+        [TestInitialize]\r
+        public void Initialize()\r
+        {\r
+            _panel.CreateLabels(Lines, (obj, e) => { });\r
+        }\r
+\r
+        /// <summary>\r
+        /// 行数と同じ任務数\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void ShowAll()\r
+        {\r
+            _panel.Update(CreateQuests(Lines));\r
+            Assert.IsTrue(CheckResult(CreateQuests(Lines)));\r
+        }\r
+\r
+        /// <summary>\r
+        /// 最大の任務数について上から行数分\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void ShowTop()\r
+        {\r
+            _panel.Update(CreateQuests(AcceptMax));\r
+            Assert.IsTrue(CheckResult(CreateQuests(Lines)));\r
+        }\r
+\r
+        /// <summary>\r
+        /// IDの大きい任務の追加されたら、その表示のためにスクロールする\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void AddBottomWithScroll()\r
+        {\r
+            _panel.Update(CreateQuests(Lines));\r
+            _panel.Update(CreateQuests(Lines + 1));\r
+            Assert.IsTrue(CheckResult(CreateQuests(1, Lines)));\r
+\r
+            SetScrollPosition(1);\r
+            _panel.Update(CreateQuests(Lines + 2));\r
+            Assert.IsTrue(CheckResult(CreateQuests(2, Lines)));\r
+        }\r
+\r
+        /// <summary>\r
+        /// IDの小さい任務が追加されたらそれを表示する\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void AddTop()\r
+        {\r
+            _panel.Update(CreateQuests(2, Lines).ToArray());\r
+            _panel.Update(CreateQuests(1, Lines + 1).ToArray());\r
+            Assert.IsTrue(CheckResult(CreateQuests(1, Lines)));\r
+        }\r
+\r
+        /// <summary>\r
+        /// 上が隠れているときにIDの小さい任務が追加されたら上スクロールする\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void AddTopWithScroll()\r
+        {\r
+            _panel.Update(CreateQuests(1, Lines + 1));\r
+            SetScrollPosition(1);\r
+            _panel.Update(CreateQuests(Lines + 2).ToArray());\r
+            Assert.IsTrue(CheckResult(CreateQuests(Lines)));\r
+        }\r
+\r
+        /// <summary>\r
+        /// 中間のIDの任務が見える位置に挿入されたらスクロールしない\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void AddMediumWithoutScroll()\r
+        {\r
+            _panel.Update(CreateQuests(new[] {0, 2, 3, 4, 5}));\r
+            SetScrollPosition(1);\r
+            _panel.Update(CreateQuests(new[] {0, 1, 2, 3, 4, 5}));\r
+            Assert.IsTrue(CheckResult(CreateQuests(1, Lines)));\r
+        }\r
+\r
+        /// <summary>\r
+        /// 中間のIDの任務が見えない位置に挿入されたらスクロールする\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void AddMediumWithScroll()\r
+        {\r
+            _panel.Update(CreateQuests(new[] {0, 2, 3, 4, 5, 6}));\r
+            SetScrollPosition(2);\r
+            _panel.Update(CreateQuests(AcceptMax));\r
+            Assert.IsTrue(CheckResult(CreateQuests(1, Lines)));\r
+        }\r
+\r
+        /// <summary>\r
+        /// 最後の任務が減る場合\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void RemoveBottom()\r
+        {\r
+            _panel.Update(CreateQuests(AcceptMax));\r
+            _panel.Update(CreateQuests(AcceptMax - 1));\r
+            Assert.IsTrue(CheckResult(CreateQuests(Lines)));\r
+        }\r
+\r
+        /// <summary>\r
+        /// 最後の任務が減った結果上スクロールする\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void RemoveBottomWithScroll()\r
+        {\r
+            _panel.Update(CreateQuests(Lines + 2));\r
+            SetScrollPosition(2);\r
+            _panel.Update(CreateQuests(Lines + 1));\r
+            Assert.IsTrue(CheckResult(CreateQuests(1, Lines)));\r
+        }\r
+\r
+        /// <summary>\r
+        /// 中間の任務が減る場合\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void RemoveMedium()\r
+        {\r
+            _panel.Update(CreateQuests(AcceptMax));\r
+            var sparse = new[] {0, 1, 3, 4, 5, 6};\r
+            _panel.Update(CreateQuests(sparse));\r
+            Assert.IsTrue(CheckResult(CreateQuests(sparse.Take(Lines))));\r
+        }\r
+\r
+        /// <summary>\r
+        /// 中間の任務が減った結果上スクロールする\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void RemoveMediumWithScroll()\r
+        {\r
+            _panel.Update(CreateQuests(Lines + 2));\r
+            SetScrollPosition(2);\r
+            var sparse = new[] {0, 1, 2, 4, 5};\r
+            _panel.Update(CreateQuests(sparse));\r
+            Assert.IsTrue(CheckResult(CreateQuests(sparse.Skip(1))));\r
+        }\r
+\r
+        /// <summary>\r
+        /// カウントが増えた任務を見える位置にスクロールする\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void ChangeCount()\r
+        {\r
+            var quests = CreateQuests(AcceptMax);\r
+            _panel.Update(quests);\r
+\r
+            quests[AcceptMax - 1].Count.Now = 1;\r
+            _panel.Update(quests);\r
+            Assert.IsTrue(CheckResult(CreateQuests(3, Lines)), "下スクロール");\r
+\r
+            quests[2].Count.NowArray[0] = 1;\r
+            _panel.Update(quests);\r
+            Assert.IsTrue(CheckResult(CreateQuests(2, Lines)), "上スクロール");\r
+\r
+            quests[3].Count.Now = 1;\r
+            _panel.Update(quests);\r
+            Assert.IsTrue(CheckResult(CreateQuests(2, Lines)), "そのまま");\r
+\r
+            _panel.Update(quests);\r
+            Assert.IsTrue(CheckResult(CreateQuests(2, Lines)), "そのまま");\r
+\r
+            quests[0].Count.Now = 1;\r
+            _panel.Update(quests);\r
+            Assert.IsTrue(CheckResult(CreateQuests(Lines)), "上スクロール");\r
+        }\r
+\r
+\r
+        private QuestStatus[] CreateQuests(int length)\r
+        {\r
+            return CreateQuests(0, length);\r
+        }\r
+\r
+        private QuestStatus[] CreateQuests(int start, int count)\r
+        {\r
+            return CreateQuests(Enumerable.Range(start, count));\r
+        }\r
+\r
+        private QuestStatus[] CreateQuests(IEnumerable<int> indexes)\r
+        {\r
+            var quests = new[]\r
+            {\r
+                CreateStatus(210, "敵艦隊を10回邀撃せよ!"),\r
+                CreateStatus(211, "敵空母を3隻撃沈せよ!"),\r
+                CreateStatus(214, "あ号作戦"),\r
+                CreateStatus(216, "敵艦隊主力を撃滅せよ!"),\r
+                CreateStatus(218, "敵補給艦を3隻撃沈せよ!"),\r
+                CreateStatus(403, "「遠征」を10回成功させよう!"),\r
+                CreateStatus(503, "艦隊大整備!")\r
+            };\r
+            return indexes.Select(idx => quests[idx]).ToArray();\r
+        }\r
+\r
+        private QuestStatus CreateStatus(int id, string name)\r
+        {\r
+            return new QuestStatus\r
+            {\r
+                Id = id,\r
+                Name = name,\r
+                Color = _panel.BackColor,\r
+                Count = _countList.GetCount(id)\r
+            };\r
+        }\r
+\r
+        private bool CheckResult(IEnumerable<QuestStatus> expected)\r
+        {\r
+            var labels = (QuestLabels[])new PrivateObject(_panel).GetField("_labels");\r
+            var result = labels.Select(ql => ql.Name.Text);\r
+            return expected.Select(q => q.Name).Concat(Enumerable.Repeat("", Lines)).Take(Lines).SequenceEqual(result);\r
+        }\r
+\r
+        private void SetScrollPosition(int position)\r
+        {\r
+            var scroller = (ListScroller)new PrivateObject(_panel).GetField("_listScroller");\r
+            scroller.Position = position;\r
+        }\r
+    }\r
+}
\ No newline at end of file
index 0f2d36f..b78acd0 100644 (file)
@@ -47,6 +47,13 @@ namespace KancolleSniffer.Model
                       new[] {"燃", "弾", "鋼", "ボ", "建造", "修復", "開発", "改修"}\r
                           .Zip(Material, (m, num) => num == 0 ? "" : m + num)\r
                           .Where(s => !string.IsNullOrEmpty(s))));\r
+\r
+        public QuestStatus Clone()\r
+        {\r
+            var clone = (QuestStatus)MemberwiseClone();\r
+            clone.Count = Count.Clone();\r
+            return clone;\r
+        }\r
     }\r
 \r
     public enum QuestInterval\r
@@ -203,6 +210,23 @@ namespace KancolleSniffer.Model
                 : $"{Now}/{Spec.Max}";\r
         }\r
 \r
+        public QuestCount Clone()\r
+        {\r
+            var clone = (QuestCount)MemberwiseClone();\r
+            if (NowArray != null)\r
+                clone.NowArray = (int[])NowArray.Clone();\r
+            return clone;\r
+        }\r
+\r
+        public bool Equals(QuestCount other)\r
+        {\r
+            if (Id != other.Id)\r
+                return false;\r
+            if (NowArray == null)\r
+                return Now == other.Now;\r
+            return NowArray.SequenceEqual(other.NowArray);\r
+        }\r
+\r
         public string ToToolTip()\r
         {\r
             switch (Id)\r
index 9d623f4..13574cc 100644 (file)
 \r
 using System;\r
 using System.Drawing;\r
+using System.Linq;\r
 using System.Windows.Forms;\r
 using KancolleSniffer.Model;\r
+\r
 // ReSharper disable CoVariantArrayConversion\r
 \r
 namespace KancolleSniffer.View\r
@@ -103,13 +105,38 @@ namespace KancolleSniffer.View
 \r
         public void Update(QuestStatus[] quests)\r
         {\r
-            _questList = quests;\r
             _listScroller.DataCount = quests.Length;\r
-            if (quests.Length <= _lines)\r
-                _listScroller.Position = 0;\r
+            _listScroller.Position = CalcScrollPosition(quests);\r
+            _questList = quests.Select(q => q.Clone()).ToArray();\r
             ShowQuestList();\r
         }\r
 \r
+        private int CalcScrollPosition(QuestStatus[] newQuests)\r
+        {\r
+            if (newQuests.Length <= _lines)\r
+                return 0;\r
+            var current = _listScroller.Position;\r
+            var bottomIndex = current + _lines - 1;\r
+            if (newQuests.Length < _questList.Length)\r
+                return bottomIndex >= newQuests.Length ? newQuests.Length - _lines : current;\r
+            var changedIndex = 0;\r
+            if (newQuests.Length > _questList.Length)\r
+            {\r
+                changedIndex = _questList.TakeWhile((q, i) => q.Id == newQuests[i].Id).Count();\r
+            }\r
+            else if (newQuests.Length == _questList.Length)\r
+            {\r
+                changedIndex = _questList.TakeWhile((q, i) => q.Count.Equals(newQuests[i].Count)).Count();\r
+                if (changedIndex == _questList.Length) // unchanged\r
+                    return current;\r
+            }\r
+            if (changedIndex < current)\r
+                return changedIndex;\r
+            if (changedIndex > bottomIndex)\r
+                return current + changedIndex - bottomIndex;\r
+            return current;\r
+        }\r
+\r
         private void ShowQuestList()\r
         {\r
             SuspendLayout();\r