1 |
masakih |
419 |
// |
2 |
|
|
// BSThreadListUpdateTask.m |
3 |
|
|
// BathyScaphe |
4 |
|
|
// |
5 |
|
|
// Created by Hori,Masaki on 06/03/29. |
6 |
|
|
// Copyright 2006 __MyCompanyName__. All rights reserved. |
7 |
|
|
// |
8 |
|
|
|
9 |
|
|
#import "BSThreadListUpdateTask.h" |
10 |
|
|
#import "BSDBThreadList.h" |
11 |
|
|
#import "BoardListItem.h" |
12 |
|
|
#import "DatabaseManager.h" |
13 |
|
|
#import "AppDefaults.h" |
14 |
|
|
|
15 |
masakih |
586 |
NSString *BSThreadListUpdateTaskDidFinishNotification = @"BSThreadListUpdateTaskDidFinishNotification"; |
16 |
|
|
|
17 |
masakih |
419 |
@implementation BSThreadListUpdateTask |
18 |
|
|
|
19 |
|
|
+ (id)taskWithBSDBThreadList:(BSDBThreadList *)threadList |
20 |
|
|
{ |
21 |
|
|
return [[[[self class] alloc] initWithBSDBThreadList:threadList] autorelease]; |
22 |
|
|
} |
23 |
|
|
- (id)initWithBSDBThreadList:(BSDBThreadList *)threadList |
24 |
|
|
{ |
25 |
|
|
if(self = [super init]) { |
26 |
masakih |
518 |
target = threadList; //[threadList retain]; |
27 |
masakih |
419 |
progress = YES; |
28 |
|
|
userCanceled = NO; |
29 |
|
|
} |
30 |
|
|
|
31 |
|
|
return self; |
32 |
|
|
} |
33 |
|
|
- (void)dealloc |
34 |
|
|
{ |
35 |
masakih |
518 |
// [target release]; |
36 |
masakih |
593 |
[cursor release]; |
37 |
masakih |
419 |
|
38 |
|
|
[super dealloc]; |
39 |
|
|
} |
40 |
|
|
|
41 |
|
|
- (id) identifier |
42 |
|
|
{ |
43 |
|
|
return [NSValue valueWithPointer:self]; |
44 |
|
|
} |
45 |
|
|
|
46 |
|
|
- (NSString *) title |
47 |
|
|
{ |
48 |
|
|
return [[target boardListItem] representName]; |
49 |
|
|
} |
50 |
|
|
- (NSString *) message |
51 |
|
|
{ |
52 |
|
|
return [NSString stringWithFormat:@"Updating -- %@", [[target boardListItem] representName]]; |
53 |
|
|
} |
54 |
masakih |
586 |
- (NSString *) messageInProgress |
55 |
masakih |
419 |
{ |
56 |
masakih |
586 |
return [NSString stringWithFormat: |
57 |
|
|
NSLocalizedString(@"Updating Thread(%@)", @"Updating Thread(%@)"), |
58 |
|
|
[target boardName]]; |
59 |
masakih |
419 |
} |
60 |
|
|
|
61 |
|
|
- (IBAction) cancel : (id) sender |
62 |
|
|
{ |
63 |
|
|
userCanceled = YES; |
64 |
masakih |
611 |
target = nil; |
65 |
masakih |
419 |
} |
66 |
|
|
|
67 |
|
|
|
68 |
|
|
//- (id)copyWithZone:(NSZone *)zone |
69 |
|
|
//{ |
70 |
|
|
// BSThreadListUpdateTask *result = [[self class] taskWithBSDBThreadList:target]; |
71 |
|
|
// if(result) { |
72 |
|
|
// result->progress = progress; |
73 |
|
|
// result->userCanceled = userCanceled; |
74 |
|
|
// } |
75 |
|
|
// |
76 |
|
|
// return [result retain]; |
77 |
|
|
//} |
78 |
|
|
|
79 |
|
|
#pragma mark- |
80 |
|
|
|
81 |
|
|
static inline NSArray *componentsSeparatedByWhiteSpace(NSString *string) |
82 |
|
|
{ |
83 |
|
|
NSMutableArray *result = [NSMutableArray array]; |
84 |
|
|
NSScanner *s = [NSScanner scannerWithString : string]; |
85 |
|
|
NSCharacterSet *cs = [NSCharacterSet whitespaceCharacterSet]; |
86 |
|
|
NSString *str; |
87 |
|
|
|
88 |
|
|
while ([s scanUpToCharactersFromSet : cs intoString : &str]) { |
89 |
|
|
[result addObject : str]; |
90 |
|
|
} |
91 |
|
|
|
92 |
|
|
if ([result count] == 0) { |
93 |
|
|
return nil; |
94 |
|
|
} |
95 |
|
|
|
96 |
|
|
return result; |
97 |
|
|
} |
98 |
|
|
static inline NSString *whereClauseFromSearchString(NSString *searchString) |
99 |
|
|
{ |
100 |
|
|
NSMutableString *clause; |
101 |
|
|
NSArray *searchs; |
102 |
|
|
NSEnumerator *searchsEnum; |
103 |
|
|
NSString *token; |
104 |
|
|
|
105 |
|
|
NSString *p = @""; |
106 |
|
|
|
107 |
|
|
searchs = componentsSeparatedByWhiteSpace(searchString); |
108 |
|
|
|
109 |
|
|
if (!searchs || [searchs count] == 0) { |
110 |
|
|
return nil; |
111 |
|
|
} |
112 |
|
|
|
113 |
|
|
clause = [NSMutableString stringWithFormat : @" WHERE "]; |
114 |
|
|
|
115 |
|
|
searchsEnum = [searchs objectEnumerator]; |
116 |
|
|
while (token = [searchsEnum nextObject]) { |
117 |
|
|
if ([token hasPrefix : @"!"]) { |
118 |
|
|
if ([token length] == 1) continue; |
119 |
|
|
|
120 |
|
|
[clause appendFormat : @"%@NOT %@ LIKE '%%%@%%' ", |
121 |
|
|
p, ThreadNameColumn, [token substringFromIndex : 1]]; |
122 |
|
|
} else { |
123 |
|
|
[clause appendFormat : @"%@%@ LIKE '%%%@%%' ", |
124 |
|
|
p, ThreadNameColumn, token]; |
125 |
|
|
} |
126 |
|
|
p = @"AND "; |
127 |
|
|
} |
128 |
|
|
|
129 |
|
|
return clause; |
130 |
|
|
} |
131 |
|
|
|
132 |
|
|
enum { |
133 |
|
|
kNewerThreadType, // ������������ |
134 |
|
|
kOlderThreadType, // ��������������� |
135 |
|
|
kAllThreadType, // ��������� |
136 |
|
|
}; |
137 |
|
|
|
138 |
|
|
// filter ��������� |
139 |
|
|
// ������������������������������������������������������������������������������DB��������������������������� |
140 |
|
|
// WHERE��������������� |
141 |
|
|
static inline NSString *conditionFromStatusAndType( int status, int type ) |
142 |
|
|
{ |
143 |
|
|
NSMutableString *result = [NSMutableString string]; |
144 |
|
|
NSString *brankOrAnd = @""; |
145 |
|
|
|
146 |
|
|
if(status & ThreadLogCachedStatus && |
147 |
|
|
(type == kOlderThreadType || !(status & ThreadNewCreatedStatus))) { |
148 |
|
|
// ������/������������������������������������������ ��������������������������������� |
149 |
|
|
[result appendFormat : @"NOT %@ IS NULL\n", NumberOfReadColumn]; |
150 |
|
|
brankOrAnd = @" AND "; |
151 |
|
|
} else if(status & ThreadNoCacheStatus) { |
152 |
|
|
// ��������������������� |
153 |
|
|
[result appendFormat : @"%@ IS NULL\n", NumberOfReadColumn]; |
154 |
|
|
brankOrAnd = @" AND "; |
155 |
|
|
} else if(status & ThreadNewCreatedStatus && type == kOlderThreadType) { |
156 |
|
|
// ������������������������������������������������������������ boardID ���������������������������0��������� |
157 |
|
|
[result appendFormat : @"%@ < 0\n",BoardIDColumn]; |
158 |
|
|
brankOrAnd = @" AND "; |
159 |
|
|
} |
160 |
|
|
|
161 |
|
|
switch(type) { |
162 |
|
|
case kNewerThreadType: |
163 |
|
|
[result appendFormat : @"%@%@ = %u\n", |
164 |
|
|
brankOrAnd, ThreadStatusColumn, ThreadNewCreatedStatus]; |
165 |
|
|
break; |
166 |
|
|
case kOlderThreadType: |
167 |
|
|
[result appendFormat : @"%@%@ != %u\n", |
168 |
|
|
brankOrAnd, ThreadStatusColumn, ThreadNewCreatedStatus]; |
169 |
|
|
break; |
170 |
|
|
case kAllThreadType: |
171 |
|
|
// Do nothing. |
172 |
|
|
break; |
173 |
|
|
default: |
174 |
|
|
UTILUnknownCSwitchCase(type); |
175 |
|
|
break; |
176 |
|
|
} |
177 |
|
|
|
178 |
|
|
return result; |
179 |
|
|
} |
180 |
|
|
static inline NSString *orderBy( NSString *sortKey, BOOL isAscending ) |
181 |
|
|
{ |
182 |
masakih |
566 |
// NSString *result = nil; |
183 |
masakih |
419 |
NSString *sortCol = nil; |
184 |
|
|
NSString *ascending = @""; |
185 |
|
|
|
186 |
|
|
if (!isAscending) ascending = @"DESC"; |
187 |
|
|
|
188 |
|
|
if ([sortKey isEqualTo : CMRThreadTitleKey]) { |
189 |
|
|
sortCol = ThreadNameColumn; |
190 |
|
|
} else if ([sortKey isEqualTo : CMRThreadLastLoadedNumberKey]) { |
191 |
|
|
sortCol = NumberOfReadColumn; |
192 |
|
|
} else if ([sortKey isEqualTo : CMRThreadNumberOfMessagesKey]) { |
193 |
|
|
sortCol = NumberOfAllColumn; |
194 |
|
|
} else if ([sortKey isEqualTo : CMRThreadNumberOfUpdatedKey]) { |
195 |
|
|
sortCol = NumberOfDifferenceColumn; |
196 |
|
|
} else if ([sortKey isEqualTo : CMRThreadSubjectIndexKey]) { |
197 |
|
|
sortCol = TempThreadThreadNumberColumn; |
198 |
|
|
} else if ([sortKey isEqualTo : CMRThreadStatusKey]) { |
199 |
|
|
sortCol = ThreadStatusColumn; |
200 |
|
|
} else if ([sortKey isEqualTo : CMRThreadModifiedDateKey]) { |
201 |
|
|
sortCol = ModifiedDateColumn; |
202 |
|
|
} else if ([sortKey isEqualTo : ThreadPlistIdentifierKey]) { |
203 |
|
|
sortCol = ThreadIDColumn; |
204 |
|
|
} else if ([sortKey isEqualTo : ThreadPlistBoardNameKey]) { |
205 |
|
|
sortCol = BoardNameColumn; |
206 |
|
|
} |
207 |
|
|
|
208 |
masakih |
518 |
// if(sortCol) { |
209 |
|
|
// result = [NSString stringWithFormat : @"ORDER BY %@ %@",sortCol, ascending]; |
210 |
|
|
// } |
211 |
|
|
// |
212 |
|
|
// return result; |
213 |
|
|
return [sortCol lowercaseString]; |
214 |
masakih |
419 |
} |
215 |
|
|
- (NSString *) sqlForListForType : (int) type |
216 |
|
|
{ |
217 |
|
|
NSString *targetTable = [[target boardListItem] query]; |
218 |
|
|
NSMutableString *sql; |
219 |
|
|
NSString *whereOrAnd = @" WHERE "; |
220 |
|
|
NSString *searchCondition; |
221 |
|
|
NSString *filterCondition; |
222 |
masakih |
566 |
// NSString *order; |
223 |
masakih |
419 |
|
224 |
|
|
sql = [NSMutableString stringWithFormat : @"SELECT * FROM (%@) ",targetTable]; |
225 |
|
|
|
226 |
|
|
if ([target searchString] && ![[target searchString] isEmpty]) { |
227 |
|
|
searchCondition = whereClauseFromSearchString([target searchString]); |
228 |
|
|
if (searchCondition) { |
229 |
|
|
[sql appendString : searchCondition]; |
230 |
|
|
whereOrAnd = @" AND "; |
231 |
|
|
} |
232 |
|
|
} |
233 |
|
|
|
234 |
|
|
filterCondition = conditionFromStatusAndType( [target status], type); |
235 |
masakih |
518 |
if(filterCondition && [filterCondition length] != 0) { |
236 |
masakih |
419 |
[sql appendFormat : @"%@ %@\n", whereOrAnd, filterCondition]; |
237 |
|
|
// whereOrAnd = @" AND "; |
238 |
|
|
} |
239 |
|
|
|
240 |
masakih |
518 |
// order = orderBy( [target sortKey], [target isAscending]); |
241 |
|
|
// if(order) { |
242 |
|
|
// [sql appendString : order]; |
243 |
|
|
// } |
244 |
masakih |
419 |
|
245 |
|
|
return sql; |
246 |
|
|
} |
247 |
|
|
- (id)cursor |
248 |
|
|
{ |
249 |
masakih |
586 |
return cursor; |
250 |
|
|
} |
251 |
|
|
- (void) setCursor:(id)new |
252 |
|
|
{ |
253 |
|
|
id temp = cursor; |
254 |
|
|
cursor = [new retain]; |
255 |
|
|
[temp release]; |
256 |
|
|
} |
257 |
|
|
- (void) doExecuteWithLayout : (CMRThreadLayout *) layout |
258 |
|
|
{ |
259 |
masakih |
419 |
id result = nil; |
260 |
|
|
|
261 |
masakih |
586 |
// [self postTaskWillStartNotification]; |
262 |
masakih |
419 |
|
263 |
|
|
SQLiteDB *db = [[DatabaseManager defaultManager] databaseForCurrentThread]; |
264 |
|
|
NSString *newersSQL = nil; |
265 |
|
|
NSString *sql; |
266 |
|
|
id <SQLiteMutableCursor> newerCursor = nil; |
267 |
|
|
id <SQLiteMutableCursor> olderCursor = nil; |
268 |
|
|
|
269 |
|
|
UTILAssertNotNil(db); |
270 |
|
|
|
271 |
|
|
if( [CMRPref collectByNew] ) { |
272 |
|
|
if(userCanceled) goto final; |
273 |
|
|
newersSQL = [self sqlForListForType : kNewerThreadType]; |
274 |
|
|
if(userCanceled) goto final; |
275 |
|
|
sql = [self sqlForListForType : kOlderThreadType]; |
276 |
|
|
} else { |
277 |
|
|
sql = [self sqlForListForType : kAllThreadType]; |
278 |
|
|
} |
279 |
|
|
|
280 |
masakih |
518 |
// if(userCanceled) goto final; |
281 |
|
|
// sql = [sql stringByAppendingString:@"\nLIMIT 5000"]; |
282 |
|
|
// newersSQL = [newersSQL stringByAppendingString:@"\nLIMIT 5000"]; |
283 |
masakih |
419 |
|
284 |
|
|
do { |
285 |
|
|
if(userCanceled) goto final; |
286 |
|
|
olderCursor = [db cursorForSQL : sql]; |
287 |
|
|
if ([db lastErrorID] != 0) { |
288 |
|
|
NSLog(@"sql error on %s line %d.\n\tReason : %@", __FILE__, __LINE__, [db lastError]); |
289 |
|
|
olderCursor = nil; |
290 |
|
|
break; |
291 |
|
|
} |
292 |
|
|
if(userCanceled) goto final; |
293 |
|
|
if(newersSQL) { |
294 |
|
|
newerCursor = [db cursorForSQL : newersSQL]; |
295 |
|
|
if([db lastErrorID] != 0) { |
296 |
|
|
NSLog(@"sql error on %s line %d.\n\tReason : %@", __FILE__, __LINE__, [db lastError]); |
297 |
|
|
newerCursor = nil; |
298 |
|
|
break; |
299 |
|
|
} |
300 |
|
|
} |
301 |
masakih |
518 |
|
302 |
masakih |
419 |
if(userCanceled) goto final; |
303 |
masakih |
566 |
|
304 |
|
|
/* |
305 |
masakih |
518 |
id sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:orderBy([target sortKey], 0) |
306 |
|
|
ascending:[target isAscending] |
307 |
|
|
selector:@selector(numericCompare:)] autorelease]; |
308 |
|
|
id sortDescriptors = [NSArray arrayWithObject:sortDescriptor]; |
309 |
masakih |
566 |
*/ |
310 |
|
|
id sortDescriptors = [target sortDescriptors]; |
311 |
masakih |
518 |
if(newerCursor) { |
312 |
|
|
NSArray *data = [newerCursor arrayForTableView]; |
313 |
|
|
NSArray *col = [newerCursor columnNames]; |
314 |
|
|
NSArrayController *acon = [[[NSArrayController alloc] initWithContent:data] autorelease]; |
315 |
|
|
|
316 |
|
|
[acon setSortDescriptors:sortDescriptors]; |
317 |
|
|
data = [acon arrangeObjects:data]; |
318 |
|
|
|
319 |
|
|
newerCursor = [NSDictionary dictionaryWithObjectsAndKeys:data, @"Values", col, @"ColumnNames", nil]; |
320 |
|
|
} |
321 |
|
|
if(olderCursor) { |
322 |
|
|
NSArray *data = [olderCursor arrayForTableView]; |
323 |
|
|
NSArray *col = [olderCursor columnNames]; |
324 |
|
|
NSArrayController *acon = [[[NSArrayController alloc] initWithContent:data] autorelease]; |
325 |
|
|
|
326 |
|
|
[acon setSortDescriptors:sortDescriptors]; |
327 |
|
|
data = [acon arrangeObjects:data]; |
328 |
|
|
|
329 |
|
|
olderCursor = [NSDictionary dictionaryWithObjectsAndKeys:data, @"Values", col, @"ColumnNames", nil]; |
330 |
|
|
} |
331 |
|
|
|
332 |
|
|
if(userCanceled) goto final; |
333 |
masakih |
419 |
if(newerCursor && [newerCursor rowCount]) { |
334 |
|
|
[newerCursor appendCursor : olderCursor]; |
335 |
|
|
olderCursor = nil; |
336 |
|
|
} |
337 |
|
|
} while( NO ); |
338 |
|
|
|
339 |
|
|
if(olderCursor || newerCursor) { |
340 |
|
|
if(olderCursor) { |
341 |
|
|
result = olderCursor; |
342 |
|
|
} else { |
343 |
|
|
result = newerCursor; |
344 |
|
|
} |
345 |
|
|
} |
346 |
|
|
|
347 |
|
|
final: |
348 |
masakih |
586 |
[self setCursor:result]; |
349 |
masakih |
419 |
[self postTaskDidFinishNotification]; |
350 |
|
|
} |
351 |
|
|
|
352 |
|
|
@end |
353 |
|
|
|
354 |
masakih |
586 |
@implementation BSThreadListUpdateTask(Notification) |
355 |
masakih |
419 |
|
356 |
|
|
- (void) postTaskDidFinishNotification |
357 |
|
|
{ |
358 |
|
|
NSNotificationCenter *nc_; |
359 |
masakih |
586 |
|
360 |
masakih |
419 |
nc_ = [NSNotificationCenter defaultCenter]; |
361 |
masakih |
586 |
[nc_ postNotificationName : BSThreadListUpdateTaskDidFinishNotification |
362 |
masakih |
419 |
object : self]; |
363 |
|
|
} |
364 |
|
|
@end |
365 |
masakih |
518 |
|
366 |
|
|
@implementation NSString(BSThreadListUpdateTaskAddition) |
367 |
|
|
- (NSComparisonResult)numericCompare:(NSString *)string |
368 |
|
|
{ |
369 |
|
|
return [self compare:string options:NSNumericSearch]; |
370 |
|
|
} |
371 |
|
|
@end |
372 |
|
|
@implementation NSNumber(BSThreadListUpdateTaskAddition) |
373 |
|
|
- (NSComparisonResult)numericCompare:(id)obj |
374 |
|
|
{ |
375 |
|
|
return [self compare:obj]; |
376 |
|
|
} |
377 |
|
|
@end |