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
22 namespace KancolleSniffer
\r
24 public class ItemTreeView : TreeView
\r
26 private ItemStatus[] _prevItemList;
\r
28 public void SetNodes(ItemStatus[] itemList)
\r
30 if (_prevItemList != null && _prevItemList.SequenceEqual(itemList, new ItemStatusComparer()))
\r
32 _prevItemList = itemList.Select(CloneItemStatus).ToArray();
\r
33 SetNodes(CreateItemNodes(itemList));
\r
36 private TreeNode CreateItemNodes(IEnumerable<ItemStatus> itemList)
\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
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
51 var root = new TreeNode();
\r
52 foreach (var byType in grouped)
\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
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
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
80 private ItemStatus CloneItemStatus(ItemStatus org)
\r
82 return new ItemStatus
\r
86 Holder = new ShipStatus {Id = org.Holder.Id, Fleet = org.Holder.Fleet}
\r
90 private class ItemStatusComparer : IEqualityComparer<ItemStatus>
\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
98 public int GetHashCode(ItemStatus obj) => obj.Level + obj.Spec.GetHashCode() + obj.Holder.GetHashCode();
\r
101 [DllImport("user32.dll")]
\r
102 private static extern int GetScrollPos(IntPtr hWnd, int nBar);
\r
104 [DllImport("user32.dll")]
\r
105 private static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);
\r
107 private void SetNodes(TreeNode root)
\r
109 var y = GetScrollPos(Handle, 1);
\r
111 var save = SaveTreeViewState(Nodes);
\r
113 foreach (TreeNode child in root.Nodes)
\r
115 RestoreTreeViewState(Nodes, save.Nodes);
\r
117 SetScrollPos(Handle, 1, y, true);
\r
120 private TreeNode SaveTreeViewState(IEnumerable nodes)
\r
122 var result = new TreeNode();
\r
123 foreach (TreeNode child in nodes)
\r
125 var copy = SaveTreeViewState(child.Nodes);
\r
126 if (child.IsExpanded)
\r
128 copy.Name = child.Name;
\r
129 result.Nodes.Add(copy);
\r
134 private void RestoreTreeViewState(TreeNodeCollection dst, TreeNodeCollection src)
\r
136 foreach (TreeNode d in dst)
\r
138 var s = src[d.Name];
\r
143 RestoreTreeViewState(d.Nodes, s.Nodes);
\r
147 // ReSharper disable InconsistentNaming
\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
153 // ReSharper restore InconsistentNaming
\r
155 [DllImport("user32.dll")]
\r
156 private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
\r
158 protected override void OnHandleCreated(EventArgs e)
\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