5
// Lluis Sanchez <lluis@xamarin.com>
7
// Copyright (c) 2011 Xamarin Inc
9
// Permission is hereby granted, free of charge, to any person obtaining a copy
10
// of this software and associated documentation files (the "Software"), to deal
11
// in the Software without restriction, including without limitation the rights
12
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
// copies of the Software, and to permit persons to whom the Software is
14
// furnished to do so, subject to the following conditions:
16
// The above copyright notice and this permission notice shall be included in
17
// all copies or substantial portions of the Software.
19
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30
using System.Collections.Generic;
32
using System.ComponentModel;
36
public class TreeStore: XwtComponent, ITreeDataSource
40
class TreeStoreBackendHost: BackendHost<TreeStore,ITreeStoreBackend>
42
protected override IBackend OnCreateBackend ()
44
var b = base.OnCreateBackend ();
46
b = new DefaultTreeStoreBackend ();
47
((ITreeStoreBackend)b).Initialize (Parent.fields.Select (f => f.FieldType).ToArray ());
52
protected override Xwt.Backends.BackendHost CreateBackendHost ()
54
return new TreeStoreBackendHost ();
57
public TreeStore (params DataField[] fields)
59
for (int n=0; n<fields.Length; n++) {
60
if (fields[n].Index != -1)
61
throw new InvalidOperationException ("DataField object already belongs to another data store");
67
ITreeStoreBackend Backend {
68
get { return (ITreeStoreBackend)BackendHost.Backend; }
71
public TreeNavigator GetFirstNode ()
73
var p = Backend.GetChild (null, 0);
74
return new TreeNavigator (Backend, p);
77
public TreeNavigator GetNavigatorAt (TreePosition pos)
79
return new TreeNavigator (Backend, pos);
82
public TreeNavigator AddNode ()
84
var pos = Backend.AddChild (null);
85
return new TreeNavigator (Backend, pos);
88
public TreeNavigator AddNode (TreePosition position)
90
var pos = Backend.AddChild (position);
91
return new TreeNavigator (Backend, pos);
99
event EventHandler<TreeNodeEventArgs> ITreeDataSource.NodeInserted {
100
add { Backend.NodeInserted += value; }
101
remove { Backend.NodeInserted -= value; }
103
event EventHandler<TreeNodeChildEventArgs> ITreeDataSource.NodeDeleted {
104
add { Backend.NodeDeleted += value; }
105
remove { Backend.NodeDeleted -= value; }
107
event EventHandler<TreeNodeEventArgs> ITreeDataSource.NodeChanged {
108
add { Backend.NodeChanged += value; }
109
remove { Backend.NodeChanged -= value; }
111
event EventHandler<TreeNodeOrderEventArgs> ITreeDataSource.NodesReordered {
112
add { Backend.NodesReordered += value; }
113
remove { Backend.NodesReordered -= value; }
116
TreePosition ITreeDataSource.GetChild (TreePosition pos, int index)
118
return Backend.GetChild (pos, index);
121
TreePosition ITreeDataSource.GetParent (TreePosition pos)
123
return Backend.GetParent (pos);
126
int ITreeDataSource.GetChildrenCount (TreePosition pos)
128
return Backend.GetChildrenCount (pos);
131
object ITreeDataSource.GetValue (TreePosition pos, int column)
133
return Backend.GetValue (pos, column);
136
void ITreeDataSource.SetValue (TreePosition pos, int column, object val)
138
Backend.SetValue (pos, column, val);
141
Type[] ITreeDataSource.ColumnTypes {
143
return fields.Select (f => f.FieldType).ToArray ();
148
class DefaultTreeStoreBackend: ITreeStoreBackend
151
public object[] Data;
152
public NodeList Children;
156
class NodePosition: TreePosition
158
public NodeList ParentList;
159
public int NodeIndex;
161
public int StoreVersion;
163
public override bool Equals (object obj)
165
NodePosition other = (NodePosition) obj;
168
return ParentList == other.ParentList && NodeId == other.NodeId;
171
public override int GetHashCode ()
173
return ParentList.GetHashCode () ^ NodeId;
177
class NodeList: List<Node>
179
public NodePosition Parent;
183
NodeList rootNodes = new NodeList ();
187
public event EventHandler<TreeNodeEventArgs> NodeInserted;
188
public event EventHandler<TreeNodeChildEventArgs> NodeDeleted;
189
public event EventHandler<TreeNodeEventArgs> NodeChanged;
190
public event EventHandler<TreeNodeOrderEventArgs> NodesReordered;
192
public void InitializeBackend (object frontend)
196
public void Initialize (Type[] columnTypes)
198
this.columnTypes = columnTypes;
206
NodePosition GetPosition (TreePosition pos)
210
NodePosition np = (NodePosition)pos;
211
if (np.StoreVersion != version) {
213
for (int i=0; i<np.ParentList.Count; i++) {
214
if (np.ParentList [i].NodeId == np.NodeId) {
219
if (np.NodeIndex == -1)
220
throw new InvalidOperationException ("Invalid node position");
221
np.StoreVersion = version;
226
public void SetValue (TreePosition pos, int column, object value)
228
NodePosition n = GetPosition (pos);
229
Node node = n.ParentList [n.NodeIndex];
230
if (node.Data == null) {
231
node.Data = new object [columnTypes.Length];
232
n.ParentList [n.NodeIndex] = node;
234
node.Data [column] = value;
235
if (NodeChanged != null)
236
NodeChanged (this, new TreeNodeEventArgs (pos));
239
public object GetValue (TreePosition pos, int column)
241
NodePosition np = GetPosition (pos);
242
Node n = np.ParentList[np.NodeIndex];
245
return n.Data [column];
248
public TreePosition GetChild (TreePosition pos, int index)
251
if (rootNodes.Count == 0)
253
Node n = rootNodes[index];
254
return new NodePosition () { ParentList = rootNodes, NodeId = n.NodeId, NodeIndex = index, StoreVersion = version };
256
NodePosition np = GetPosition (pos);
257
Node n = np.ParentList[np.NodeIndex];
258
return new NodePosition () { ParentList = n.Children, NodeId = n.Children[index].NodeId, NodeIndex = index, StoreVersion = version };
262
public TreePosition GetNext (TreePosition pos)
264
NodePosition np = GetPosition (pos);
265
if (np.NodeIndex >= np.ParentList.Count)
267
Node n = np.ParentList[np.NodeIndex + 1];
268
return new NodePosition () { ParentList = np.ParentList, NodeId = n.NodeId, NodeIndex = np.NodeIndex + 1, StoreVersion = version };
271
public TreePosition GetPrevious (TreePosition pos)
273
NodePosition np = GetPosition (pos);
274
if (np.NodeIndex <= 0)
276
Node n = np.ParentList[np.NodeIndex - 1];
277
return new NodePosition () { ParentList = np.ParentList, NodeId = n.NodeId, NodeIndex = np.NodeIndex - 1, StoreVersion = version };
280
public int GetChildrenCount (TreePosition pos)
283
return rootNodes.Count;
285
NodePosition np = GetPosition (pos);
286
Node n = np.ParentList[np.NodeIndex];
287
return n.Children != null ? n.Children.Count : 0;
290
public TreePosition InsertBefore (TreePosition pos)
292
NodePosition np = GetPosition (pos);
293
Node nn = new Node ();
294
nn.NodeId = nextNodeId++;
296
np.ParentList.Insert (np.NodeIndex, nn);
299
// Update the NodePosition since it is now invalid
301
np.StoreVersion = version;
303
var node = new NodePosition () { ParentList = np.ParentList, NodeId = nn.NodeId, NodeIndex = np.NodeIndex - 1, StoreVersion = version };
304
if (NodeInserted != null)
305
NodeInserted (this, new TreeNodeEventArgs (node));
309
public TreePosition InsertAfter (TreePosition pos)
311
NodePosition np = GetPosition (pos);
312
Node nn = new Node ();
313
nn.NodeId = nextNodeId++;
315
np.ParentList.Insert (np.NodeIndex + 1, nn);
318
// Update the provided position is still valid
319
np.StoreVersion = version;
321
var node = new NodePosition () { ParentList = np.ParentList, NodeId = nn.NodeId, NodeIndex = np.NodeIndex + 1, StoreVersion = version };
322
if (NodeInserted != null)
323
NodeInserted (this, new TreeNodeEventArgs (node));
327
public TreePosition AddChild (TreePosition pos)
329
NodePosition np = GetPosition (pos);
331
Node nn = new Node ();
332
nn.NodeId = nextNodeId++;
339
Node n = np.ParentList [np.NodeIndex];
340
if (n.Children == null) {
341
n.Children = new NodeList ();
342
n.Children.Parent = new NodePosition () { ParentList = np.ParentList, NodeId = n.NodeId, NodeIndex = np.NodeIndex, StoreVersion = version };
343
np.ParentList [np.NodeIndex] = n;
350
// The provided position is unafected by this change. Keep it valid.
352
np.StoreVersion = version;
354
var node = new NodePosition () { ParentList = list, NodeId = nn.NodeId, NodeIndex = list.Count - 1, StoreVersion = version };
355
if (NodeInserted != null)
356
NodeInserted (this, new TreeNodeEventArgs (node));
360
public void Remove (TreePosition pos)
362
NodePosition np = GetPosition (pos);
363
np.ParentList.RemoveAt (np.NodeIndex);
364
var parent = np.ParentList.Parent;
365
var index = np.NodeIndex;
367
if (NodeDeleted != null)
368
NodeDeleted (this, new TreeNodeChildEventArgs (parent, index));
371
public TreePosition GetParent (TreePosition pos)
373
NodePosition np = GetPosition (pos);
374
if (np.ParentList == rootNodes)
376
var parent = np.ParentList.Parent;
377
return new NodePosition () { ParentList = parent.ParentList, NodeId = parent.NodeId, NodeIndex = parent.NodeIndex, StoreVersion = version };
380
public Type[] ColumnTypes {
386
public void EnableEvent (object eventId)
390
public void DisableEvent (object eventId)