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