1 // Copyright (C) 2014, 2015 Kazuhiro Fujieda <fujieda@users.osdn.me>
\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
7 // http://www.apache.org/licenses/LICENSE-2.0
\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
16 using System.Collections;
\r
17 using System.Collections.Generic;
\r
19 using System.Runtime.InteropServices;
\r
20 using System.Windows.Forms;
\r
21 using KancolleSniffer.Model;
\r
23 namespace KancolleSniffer.View
\r
25 public class ItemTreeView : TreeView
\r
27 private ItemStatus[] _prevItemList;
\r
29 public void SetNodes(ItemStatus[] itemList)
\r
31 if (_prevItemList != null && _prevItemList.SequenceEqual(itemList, new ItemStatusComparer()))
\r
33 _prevItemList = itemList.Select(CloneItemStatus).ToArray();
\r
34 SetNodes(CreateItemNodes(itemList));
\r
37 private TreeNode CreateItemNodes(IEnumerable<ItemStatus> itemList)
\r
39 var grouped = from item in itemList
\r
40 where !item.Spec.Empty
\r
41 orderby item.Spec.Type, item.Spec.Id, item.Alv, item.Level
\r
42 group item by item.Spec.Type
\r
44 from bySpec in (from item in byTypeGroup
\r
45 group item by item.Spec.Id
\r
47 from byParam in (from item in bySpecGroup
\r
48 group item by new {item.Alv, item.Level}
\r
50 from byHolder in (from item in byParamGroup group item by item.Holder.Id)
\r
51 group byHolder by byParamGroup.Key)
\r
52 group byParam by bySpecGroup.Key)
\r
53 group bySpec by byTypeGroup.Key;
\r
55 var root = new TreeNode();
\r
56 foreach (var byType in grouped)
\r
58 var typeName = byType.First().First().First().First().Spec.TypeName;
\r
59 var typeNode = new TreeNode();
\r
60 typeNode.Name = typeNode.Text = typeName;
\r
61 root.Nodes.Add(typeNode);
\r
62 foreach (var bySpec in byType)
\r
64 var item = bySpec.First().First().First();
\r
65 var itemNode = new TreeNode();
\r
66 itemNode.Name = itemNode.Text = item.Spec.Name + "x" +
\r
67 bySpec.SelectMany(spec => spec).SelectMany(param => param).Count();
\r
68 typeNode.Nodes.Add(itemNode);
\r
69 foreach (var byParam in bySpec)
\r
72 if (bySpec.Count() == 1 && byParam.Key.Alv == 0 && byParam.Key.Level == 0)
\r
74 paramNode = itemNode;
\r
78 paramNode = new TreeNode();
\r
79 item = byParam.First().First();
\r
80 paramNode.Name = paramNode.Text =
\r
81 (item.Spec.IsAircraft ? "+" + item.Alv : "") + "★" + item.Level + "x" +
\r
82 byParam.SelectMany(param => param).Count();
\r
83 itemNode.Nodes.Add(paramNode);
\r
85 foreach (var byShip in byParam)
\r
87 var ship = byShip.First().Holder;
\r
88 var name = ship.Empty
\r
89 ? "未装備x" + byShip.Count()
\r
90 : (ship.Fleet == null ? "" : ship.Fleet.Number + 1 + " ") +
\r
91 ship.Name + (ship.Level > 0 ? "Lv" + ship.Level : "") + "x" + byShip.Count();
\r
92 paramNode.Nodes.Add(name, name);
\r
100 private ItemStatus CloneItemStatus(ItemStatus org)
\r
102 return new ItemStatus
\r
106 Holder = new ShipStatus {Id = org.Holder.Id, Fleet = org.Holder.Fleet}
\r
110 private class ItemStatusComparer : IEqualityComparer<ItemStatus>
\r
112 public bool Equals(ItemStatus x, ItemStatus y)
\r
113 // ReSharper disable PossibleNullReferenceException
\r
114 => x.Level == y.Level && x.Spec == y.Spec && x.Holder.Id == y.Holder.Id &&
\r
115 x.Holder.Fleet == y.Holder.Fleet;
\r
116 // ReSharper restore PossibleNullReferenceException
\r
118 public int GetHashCode(ItemStatus obj) => obj.Level + obj.Spec.GetHashCode() + obj.Holder.GetHashCode();
\r
121 [DllImport("user32.dll")]
\r
122 private static extern int GetScrollPos(IntPtr hWnd, int nBar);
\r
124 [DllImport("user32.dll")]
\r
125 private static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);
\r
127 private void SetNodes(TreeNode root)
\r
129 var y = GetScrollPos(Handle, 1);
\r
131 var save = SaveTreeViewState(Nodes);
\r
133 foreach (TreeNode child in root.Nodes)
\r
135 RestoreTreeViewState(Nodes, save.Nodes);
\r
137 SetScrollPos(Handle, 1, y, true);
\r
140 private TreeNode SaveTreeViewState(IEnumerable nodes)
\r
142 var result = new TreeNode();
\r
143 foreach (TreeNode child in nodes)
\r
145 var copy = SaveTreeViewState(child.Nodes);
\r
146 if (child.IsExpanded)
\r
148 copy.Name = child.Name;
\r
149 result.Nodes.Add(copy);
\r
154 private void RestoreTreeViewState(TreeNodeCollection dst, TreeNodeCollection src)
\r
156 foreach (TreeNode d in dst)
\r
158 var s = src[d.Name];
\r
163 RestoreTreeViewState(d.Nodes, s.Nodes);
\r
167 // ReSharper disable InconsistentNaming
\r
168 // ReSharper disable IdentifierTypo
\r
170 private const int TV_FIRST = 0x1100;
\r
172 private const int TVM_SETEXTENDEDSTYLE = TV_FIRST + 44;
\r
174 private const int TVS_EX_DOUBLEBUFFER = 0x0004;
\r
176 // ReSharper restore IdentifierTypo
\r
177 // ReSharper restore InconsistentNaming
\r
179 [DllImport("user32.dll")]
\r
180 private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
\r
182 protected override void OnHandleCreated(EventArgs e)
\r
184 base.OnHandleCreated(e);
\r
185 // Enable double buffer
\r
186 SendMessage(Handle, TVM_SETEXTENDEDSTYLE, (IntPtr)TVS_EX_DOUBLEBUFFER, (IntPtr)TVS_EX_DOUBLEBUFFER);
\r