File: Category.m

package info (click to toggle)
grr.app 1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: buster, stretch
  • size: 3,948 kB
  • ctags: 118
  • sloc: objc: 4,019; sh: 72; makefile: 18
file content (219 lines) | stat: -rw-r--r-- 6,013 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
/*
   Grr RSS Reader
   
   Copyright (C) 2006, 2007 Guenther Noack <guenther@unix-ag.uni-kl.de>
   Copyright (C) 2009-2011  GNUstep Application Team
                            Riccardo Mottola

   This application is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
   License as published by the Free Software Foundation; either
   version 3 of the License, or (at your option) any later version.
 
   This application is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.
 
   You should have received a copy of the GNU General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. 
*/

#import <Foundation/Foundation.h>

#import "Category.h"

#ifdef __APPLE__
#import "GNUstep.h"
#endif

@implementation GrrCategory

// ---------------------------------------------------------
//    initialisation
// ---------------------------------------------------------

// conforming to DatabaseElement protocol
-(id) initWithDictionary: (NSDictionary*) dict
{
    NSString* aName;
    NSArray* subElemDicts;
    NSMutableArray* subElements;
    int i;

    NSParameterAssert([dict isKindOfClass: [NSDictionary class]]);
    
    aName = [dict objectForKey: @"name"];
    NSAssert1([aName isKindOfClass: [NSString class]], @"%@ is not a string", aName);
    
    subElemDicts = [dict objectForKey: @"elements"];
    subElements = [NSMutableArray new];
    
    for (i=0; i<[subElemDicts count]; i++) {
        id<DatabaseElement> elem = DatabaseElementFromPlistDictionary([subElemDicts objectAtIndex: i]);
        NSAssert1(
            [elem conformsToProtocol: @protocol(DatabaseElement)],
            @"%@ is not a database element", elem
        );
        [subElements addObject: elem];
        [elem setSuperElement: self];
    }
    
    return [self initWithName: aName elements: subElements];
}

-(id) initWithName: (NSString*) aName
{
    return [self initWithName: aName elements: [NSArray new]];
}

/**
 * Designated initialiser.
 */
-(id) initWithName: (NSString*) aName
          elements: (NSArray*) anElementsArray
{
    if ((self = [super init]) != nil) {
        ASSIGN(name, aName);
        ASSIGN(elements, [NSMutableArray arrayWithArray: anElementsArray]);
    }
    
    return self;
}

// ---------------------------------------------------------
//    NSObject protocol
// ---------------------------------------------------------

-(NSString*) description
{
    return name;
}

// ---------------------------------------------------------
//    database element protocol
// ---------------------------------------------------------

-(id) superElement
{
    return parent;
}


-(void) setSuperElement: (id)superElement
{
    ASSIGN(parent, superElement);
}

-(NSMutableDictionary*) plistDictionary
{
    NSMutableDictionary* dict = [NSMutableDictionary new];
    NSMutableArray* arr = [NSMutableArray new];
    
    int i;
    for (i=0; i<[elements count]; i++) {
        id<DatabaseElement> elem = [elements objectAtIndex: i];
        
        [arr addObject: [elem plistDictionary]];
    }
    
    [dict setObject: arr forKey: @"elements"];
    [dict setObject: name forKey: @"name"];
    [dict setObject: [[self class] description] forKey: @"isa"];
    
    return dict;
}

/**
 * Sets the name for the category. This name is then returned by
 * the -description method.
 */
-(void) setName: (NSString*) aString
{
    ASSIGN(name, aString);
}


// ---------------------------------------------------------
//    category protocol
// ---------------------------------------------------------

-(NSArray*) elements
{
    return elements;
}

/**
 * Inserts the given element in this category.
 * Returns YES if - and only if - the operation is a success.
 * Otherwise, NO is returned. The operation will fail when the
 * element is already contained in this category.
 *
 * The position argument is an integer between 0 and the number
 * of already existing database elements. A position of 0 inserts
 * the new element before the first and a position equaling the
 * number of elements inserts the new element after the last element.
 */
-(BOOL) insertElement: (id<DatabaseElement>)element
           atPosition: (int)index
{
    if (index < 0 || index > [elements count]) {
        return NO;
    } else {
        [elements insertObject: element atIndex: index];
        [element setSuperElement: self];
        return YES;
    }
}

/**
 * This convenience method inserts a database element in a category
 * without caring about the position. See the documentation for
 * -insertElement:atPosition: for details.
 */
-(BOOL) insertElement: (id<DatabaseElement>)element
{
    [elements addObject: element];
    [element setSuperElement: self];
    return YES;
}

/**
 * Removes the given database element from the category. If the object
 * has been removed, YES is returned. Not recursive.
 */
-(BOOL) removeElement: (id<DatabaseElement>)element
{
    if ([elements containsObject: element]) {
        [elements removeObject: element];
        // nil means 'top level element' here. Not very nice actually.
        [element setSuperElement: nil];
        return YES;
    } else {
        return NO;
    }
}

/**
 * Recursively removes the given database element from the category.
 * On success, YES is returned.
 */
-(BOOL) recursivelyRemoveElement: (id<DatabaseElement>)element
{
    BOOL result = [self removeElement: element];
    
    int i;
    for (i=0; i<[elements count]; i++) {
        id<DatabaseElement> elem = [elements objectAtIndex: i];
        
        if ([elem conformsToProtocol: @protocol(Category)]) {
            result = result || [(id<Category>)elem recursivelyRemoveElement: element];
        }
    }
    
    return result;
}

@end