OSDN Git Service

装備のTPをTP.csvから読み込む
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / ItemTreeView.cs
1 // Copyright (C) 2014, 2015 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
2 //\r
3 // Licensed under the Apache License, Version 2.0 (the "License");\r
4 // you may not use this file except in compliance with the License.\r
5 // You may obtain a copy of the License at\r
6 //\r
7 //    http://www.apache.org/licenses/LICENSE-2.0\r
8 //\r
9 // Unless required by applicable law or agreed to in writing, software\r
10 // distributed under the License is distributed on an "AS IS" BASIS,\r
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
12 // See the License for the specific language governing permissions and\r
13 // limitations under the License.\r
14 \r
15 using System;\r
16 using System.Collections;\r
17 using System.Collections.Generic;\r
18 using System.Linq;\r
19 using System.Runtime.InteropServices;\r
20 using System.Windows.Forms;\r
21 \r
22 namespace KancolleSniffer\r
23 {\r
24     public class ItemTreeView : TreeView\r
25     {\r
26         private ItemStatus[] _prevItemList;\r
27 \r
28         public void SetNodes(ItemStatus[] itemList)\r
29         {\r
30             if (_prevItemList != null && _prevItemList.SequenceEqual(itemList, new ItemStatusComparer()))\r
31                 return;\r
32             _prevItemList = itemList.Select(CloneItemStatus).ToArray();\r
33             SetNodes(CreateItemNodes(itemList));\r
34         }\r
35 \r
36         private TreeNode CreateItemNodes(IEnumerable<ItemStatus> itemList)\r
37         {\r
38             var grouped = from byItem in (from item in itemList\r
39                 where item.Spec.Id != -1\r
40                 orderby item.Spec.Type, item.Spec.Id, item.Alv, item.Level descending\r
41                 group item by new {item.Spec.Id, item.Alv, item.Level}\r
42                 into grp\r
43                 from byShip in\r
44                     (from item in grp\r
45                         let ship = item.Holder\r
46                         orderby ship.Level descending, ship.Spec.SortNo\r
47                         group item by item.Holder.Id)\r
48                 group byShip by grp.Key)\r
49                 group byItem by byItem.First().First().Spec.Type;\r
50 \r
51             var root = new TreeNode();\r
52             foreach (var byType in grouped)\r
53             {\r
54                 var typeName = byType.First().First().First().Spec.TypeName;\r
55                 var typeNode = new TreeNode();\r
56                 typeNode.Name = typeNode.Text = typeName;\r
57                 root.Nodes.Add(typeNode);\r
58                 foreach (var byItem in byType)\r
59                 {\r
60                     var item = byItem.First().First();\r
61                     var itemNode = new TreeNode();\r
62                     itemNode.Name = itemNode.Text = item.Spec.Name +\r
63                                                     (item.Alv == 0 ? "" : "+" + item.Alv) +\r
64                                                     (item.Level == 0 ? "" : "★" + item.Level);\r
65                     typeNode.Nodes.Add(itemNode);\r
66                     foreach (var byShip in byItem)\r
67                     {\r
68                         var ship = byShip.First().Holder;\r
69                         var name = byShip.Key == -1\r
70                             ? "未装備x" + byShip.Count()\r
71                             : (ship.Fleet != -1 ? ship.Fleet + 1 + " " : "") +\r
72                               ship.Name + (ship.Level > 0 ? "Lv" + ship.Level : "") + "×" + byShip.Count();\r
73                         itemNode.Nodes.Add(name, name);\r
74                     }\r
75                 }\r
76             }\r
77             return root;\r
78         }\r
79 \r
80         private ItemStatus CloneItemStatus(ItemStatus org)\r
81         {\r
82             return new ItemStatus\r
83             {\r
84                 Level = org.Level,\r
85                 Spec = org.Spec,\r
86                 Holder = new ShipStatus {Id = org.Holder.Id, Fleet = org.Holder.Fleet}\r
87             };\r
88         }\r
89 \r
90         private class ItemStatusComparer : IEqualityComparer<ItemStatus>\r
91         {\r
92             public bool Equals(ItemStatus x, ItemStatus y)\r
93                 // ReSharper disable PossibleNullReferenceException\r
94                 => x.Level == y.Level && x.Spec == y.Spec && x.Holder.Id == y.Holder.Id &&\r
95                    x.Holder.Fleet == y.Holder.Fleet;\r
96                 // ReSharper restore PossibleNullReferenceException\r
97 \r
98             public int GetHashCode(ItemStatus obj) => obj.Level + obj.Spec.GetHashCode() + obj.Holder.GetHashCode();\r
99         }\r
100 \r
101         [DllImport("user32.dll")]\r
102         private static extern int GetScrollPos(IntPtr hWnd, int nBar);\r
103 \r
104         [DllImport("user32.dll")]\r
105         private static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);\r
106 \r
107         private void SetNodes(TreeNode root)\r
108         {\r
109             var y = GetScrollPos(Handle, 1);\r
110             BeginUpdate();\r
111             var save = SaveTreeViewState(Nodes);\r
112             Nodes.Clear();\r
113             foreach (TreeNode child in root.Nodes)\r
114                 Nodes.Add(child);\r
115             RestoreTreeViewState(Nodes, save.Nodes);\r
116             EndUpdate();\r
117             SetScrollPos(Handle, 1, y, true);\r
118         }\r
119 \r
120         private TreeNode SaveTreeViewState(IEnumerable nodes)\r
121         {\r
122             var result = new TreeNode();\r
123             foreach (TreeNode child in nodes)\r
124             {\r
125                 var copy = SaveTreeViewState(child.Nodes);\r
126                 if (child.IsExpanded)\r
127                     copy.Expand();\r
128                 copy.Name = child.Name;\r
129                 result.Nodes.Add(copy);\r
130             }\r
131             return result;\r
132         }\r
133 \r
134         private void RestoreTreeViewState(TreeNodeCollection dst, TreeNodeCollection src)\r
135         {\r
136             foreach (TreeNode d in dst)\r
137             {\r
138                 var s = src[d.Name];\r
139                 if (s == null)\r
140                     continue;\r
141                 if (s.IsExpanded)\r
142                     d.Expand();\r
143                 RestoreTreeViewState(d.Nodes, s.Nodes);\r
144             }\r
145         }\r
146 \r
147         // ReSharper disable InconsistentNaming\r
148 \r
149         private const int TV_FIRST = 0x1100;\r
150         private const int TVM_SETEXTENDEDSTYLE = TV_FIRST + 44;\r
151         private const int TVS_EX_DOUBLEBUFFER = 0x0004;\r
152 \r
153         // ReSharper restore InconsistentNaming\r
154 \r
155         [DllImport("user32.dll")]\r
156         private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);\r
157 \r
158         protected override void OnHandleCreated(EventArgs e)\r
159         {\r
160             base.OnHandleCreated(e);\r
161             // Enable double buffer\r
162             SendMessage(Handle, TVM_SETEXTENDEDSTYLE, (IntPtr)TVS_EX_DOUBLEBUFFER, (IntPtr)TVS_EX_DOUBLEBUFFER);\r
163         }\r
164     }\r
165 }