1/*
2   NSTreeNode.m
3
4   The tree node class
5
6   Copyright (C) 2013 Free Software Foundation, Inc.
7
8   Author:  Fred Kiefer <fredkiefer@gmx.de>
9   Date: 2013
10
11   This file is part of the GNUstep GUI Library.
12
13   This library is free software; you can redistribute it and/or
14   modify it under the terms of the GNU Lesser General Public
15   License as published by the Free Software Foundation; either
16   version 2 of the License, or (at your option) any later version.
17
18   This library is distributed in the hope that it will be useful,
19   but WITHOUT ANY WARRANTY; without even the implied warranty of
20   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
21   Lesser General Public License for more details.
22
23   You should have received a copy of the GNU Lesser General Public
24   License along with this library; see the file COPYING.LIB.
25   If not, see <http://www.gnu.org/licenses/> or write to the
26   Free Software Foundation, 51 Franklin Street, Fifth Floor,
27   Boston, MA 02110-1301, USA.
28*/
29
30#import <Foundation/NSArray.h>
31#import <Foundation/NSIndexPath.h>
32#import <Foundation/NSString.h>
33#import <Foundation/NSSortDescriptor.h>
34
35#import <AppKit/NSTreeNode.h>
36
37@interface NSTreeNode (Private)
38- (NSMutableArray*) _childNodes;
39- (void) _setParentNode: (NSTreeNode*)parentNode;
40@end
41
42@implementation NSTreeNode (Private)
43- (NSMutableArray*) _childNodes
44{
45  return _childNodes;
46}
47
48- (void) _setParentNode: (NSTreeNode*)parentNode
49{
50  _parentNode = parentNode;
51}
52
53@end
54
55
56@interface GSTreeNodeArray : NSMutableArray
57{
58  NSMutableArray *array;
59  NSTreeNode *parent;
60}
61
62@end
63
64@implementation GSTreeNodeArray
65
66- (id) initForTreeNode: (NSTreeNode*)node
67{
68  ASSIGN(parent, node);
69  array = [parent _childNodes];
70  return self;
71}
72
73- (void) dealloc
74{
75  RELEASE(parent);
76  [super dealloc];
77}
78
79- (NSUInteger) count
80{
81  return [array count];
82}
83
84- (id) objectAtIndex: (NSUInteger)index
85{
86  return [array objectAtIndex: index];
87}
88
89- (void) addObject: (id)anObject
90{
91  [array addObject: anObject];
92  [(NSTreeNode*)anObject _setParentNode: parent];
93}
94
95- (void) replaceObjectAtIndex: (NSUInteger)index withObject: (id)anObject
96{
97  id old = [array objectAtIndex: index];
98
99  [(NSTreeNode*)old _setParentNode: nil];
100  [array replaceObjectAtIndex: index withObject: anObject];
101  [(NSTreeNode*)anObject _setParentNode: parent];
102}
103
104- (void) insertObject: anObject atIndex: (NSUInteger)index
105{
106  [array insertObject: anObject atIndex: index];
107  [(NSTreeNode*)anObject _setParentNode: parent];
108}
109
110- (void) removeObjectAtIndex: (NSUInteger)index
111{
112  id old = [array objectAtIndex: index];
113
114  [(NSTreeNode*)old _setParentNode: nil];
115  [array removeObjectAtIndex: index];
116}
117
118@end
119
120
121@implementation NSTreeNode
122
123+ (id) treeNodeWithRepresentedObject: (id)modelObject
124{
125  NSTreeNode *node = [[NSTreeNode alloc] initWithRepresentedObject: modelObject];
126
127  return AUTORELEASE(node);
128}
129
130- (NSArray*) childNodes
131{
132  return [NSArray arrayWithArray: _childNodes];
133}
134
135- (NSTreeNode*) descendantNodeAtIndexPath: (NSIndexPath*)path
136{
137  NSUInteger len = [path length];
138  NSUInteger i;
139  NSTreeNode *node = self;
140
141  for (i = 0; i < len; i++)
142    {
143      NSUInteger index = [path indexAtPosition: i];
144
145      node = [node->_childNodes objectAtIndex: index];
146      if (node == nil)
147        {
148          return nil;
149        }
150    }
151
152  return node;
153}
154
155- (NSIndexPath*) indexPath
156{
157  if (_parentNode != nil)
158    {
159      NSIndexPath *path;
160      NSUInteger index;
161
162      index = [_parentNode->_childNodes indexOfObject: self];
163      path = [_parentNode indexPath];
164      if (path != nil)
165        {
166          return [path indexPathByAddingIndex: index];
167        }
168      else
169        {
170          return [NSIndexPath indexPathWithIndex: index];
171        }
172    }
173  else
174    {
175      return nil;
176    }
177}
178
179- (id) initWithRepresentedObject: (id)repObj
180{
181  ASSIGN(_representedObject, repObj);
182  _childNodes = [[NSMutableArray alloc] init];
183  return self;
184}
185
186- (void) dealloc
187{
188  RELEASE(_representedObject);
189  RELEASE(_childNodes);
190  [super dealloc];
191}
192
193- (BOOL) isLeaf
194{
195  return [_childNodes count] == 0;
196}
197
198- (NSMutableArray*) mutableChildNodes
199{
200  GSTreeNodeArray *nodeArray = [[GSTreeNodeArray alloc] initForTreeNode: self];
201
202  return AUTORELEASE(nodeArray);
203}
204
205- (NSTreeNode*) parentNode
206{
207  return _parentNode;
208}
209
210- (id) representedObject
211{
212  return _representedObject;
213}
214
215- (void) sortWithSortDescriptors: (NSArray*)sortDescs recursively: (BOOL)flag
216{
217  // Sort children nodes
218  NSUInteger i;
219  NSUInteger len = [sortDescs count];
220  NSMutableArray *newSortDescs = [[NSMutableArray alloc] init];
221
222  for (i = 0; i < len; i++)
223    {
224      NSSortDescriptor *oldDesc = [sortDescs objectAtIndex: i];
225      NSString * newKey = [@"representedObject." stringByAppendingString: [oldDesc key]];
226      NSSortDescriptor *newDesc = [[NSSortDescriptor alloc]
227                                    initWithKey: newKey
228                                   ascending: [oldDesc ascending]
229                                    selector: [oldDesc selector]];
230
231      [newSortDescs addObject: newDesc];
232      RELEASE(newDesc);
233    }
234
235  [_childNodes sortUsingDescriptors: newSortDescs];
236  RELEASE(newSortDescs);
237
238  if (flag)
239    {
240      // sort recursive
241      NSUInteger count = [_childNodes count];
242
243      for (i = 0; i < count; i++)
244        {
245          [[_childNodes objectAtIndex: i] sortWithSortDescriptors: sortDescs
246                                                      recursively: YES];
247        }
248    }
249}
250
251@end
252