]>
Commit | Line | Data |
---|---|---|
36bb2ca2 JF |
1 | /* Cydia - iPhone UIKit Front-End for Debian APT |
2 | * Copyright (C) 2008 Jay Freeman (saurik) | |
3 | */ | |
4 | ||
5 | /* | |
6 | * Redistribution and use in source and binary | |
7 | * forms, with or without modification, are permitted | |
8 | * provided that the following conditions are met: | |
9 | * | |
10 | * 1. Redistributions of source code must retain the | |
11 | * above copyright notice, this list of conditions | |
12 | * and the following disclaimer. | |
13 | * 2. Redistributions in binary form must reproduce the | |
14 | * above copyright notice, this list of conditions | |
15 | * and the following disclaimer in the documentation | |
16 | * and/or other materials provided with the | |
17 | * distribution. | |
18 | * 3. The name of the author may not be used to endorse | |
19 | * or promote products derived from this software | |
20 | * without specific prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' | |
23 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, | |
24 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
25 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE | |
27 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
28 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
29 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
32 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR | |
33 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | |
34 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |
35 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
36 | */ | |
37 | ||
dc5812ec | 38 | /* #include Directives {{{ */ |
ab398adf JF |
39 | #include <objc/objc.h> |
40 | #include <objc/runtime.h> | |
41 | ||
5f6bff8c | 42 | #include <CoreGraphics/CoreGraphics.h> |
9743c015 | 43 | #include <GraphicsServices/GraphicsServices.h> |
5f6bff8c JF |
44 | #include <Foundation/Foundation.h> |
45 | #include <UIKit/UIKit.h> | |
36bb2ca2 JF |
46 | #include <WebCore/DOMHTML.h> |
47 | ||
ab398adf JF |
48 | #import "BrowserView.h" |
49 | #import "ResetView.h" | |
50 | #import "UICaboodle.h" | |
7e9a36b6 | 51 | |
36bb2ca2 JF |
52 | #include <WebKit/WebFrame.h> |
53 | #include <WebKit/WebView.h> | |
9743c015 | 54 | |
2367a917 | 55 | #include <sstream> |
a0be02eb JF |
56 | #include <string> |
57 | ||
2367a917 JF |
58 | #include <ext/stdio_filebuf.h> |
59 | ||
dc5812ec JF |
60 | #include <apt-pkg/acquire.h> |
61 | #include <apt-pkg/acquire-item.h> | |
62 | #include <apt-pkg/algorithms.h> | |
63 | #include <apt-pkg/cachefile.h> | |
64 | #include <apt-pkg/configuration.h> | |
3178d79b | 65 | #include <apt-pkg/debmetaindex.h> |
dc5812ec JF |
66 | #include <apt-pkg/error.h> |
67 | #include <apt-pkg/init.h> | |
68 | #include <apt-pkg/pkgrecords.h> | |
69 | #include <apt-pkg/sourcelist.h> | |
2367a917 | 70 | #include <apt-pkg/sptr.h> |
dc5812ec | 71 | |
3178d79b | 72 | #include <sys/sysctl.h> |
2a8d9add | 73 | #include <notify.h> |
3178d79b | 74 | |
b4d89997 JF |
75 | extern "C" { |
76 | #include <mach-o/nlist.h> | |
77 | } | |
78 | ||
a0be02eb JF |
79 | #include <cstdio> |
80 | #include <cstdlib> | |
81 | #include <cstring> | |
b4d89997 | 82 | |
2367a917 | 83 | #include <errno.h> |
dc5812ec | 84 | #include <pcre.h> |
dc5812ec | 85 | /* }}} */ |
3178d79b | 86 | |
1e7a90f5 JF |
87 | /* iPhoneOS 2.0 Compatibility {{{ */ |
88 | #ifdef __OBJC2__ | |
89 | @interface UICGColor : NSObject { | |
90 | } | |
91 | ||
92 | - (id) initWithCGColor:(CGColorRef)color; | |
93 | @end | |
94 | ||
95 | @interface UIFont { | |
96 | } | |
97 | ||
98 | - (UIFont *) fontWithSize:(CGFloat)size; | |
99 | @end | |
100 | ||
101 | @interface NSObject (iPhoneOS) | |
102 | - (CGColorRef) cgColor; | |
ffdee4ec | 103 | - (CGColorRef) CGColor; |
1e7a90f5 JF |
104 | - (void) set; |
105 | @end | |
106 | ||
107 | @implementation NSObject (iPhoneOS) | |
108 | ||
109 | - (CGColorRef) cgColor { | |
ffdee4ec JF |
110 | return [self CGColor]; |
111 | } | |
112 | ||
113 | - (CGColorRef) CGColor { | |
1e7a90f5 JF |
114 | return (CGColorRef) self; |
115 | } | |
116 | ||
117 | - (void) set { | |
ffdee4ec | 118 | [[[[objc_getClass("UICGColor") alloc] initWithCGColor:[self CGColor]] autorelease] set]; |
1e7a90f5 JF |
119 | } |
120 | ||
121 | @end | |
122 | ||
123 | @interface UITextView (iPhoneOS) | |
124 | - (void) setTextSize:(float)size; | |
125 | @end | |
126 | ||
127 | @implementation UITextView (iPhoneOS) | |
128 | ||
129 | - (void) setTextSize:(float)size { | |
130 | [self setFont:[[self font] fontWithSize:size]]; | |
131 | } | |
132 | ||
133 | @end | |
49048579 | 134 | #endif |
1e7a90f5 | 135 | /* }}} */ |
49048579 | 136 | |
2388b078 JF |
137 | @interface NSString (UIKit) |
138 | - (NSString *) stringByAddingPercentEscapes; | |
139 | - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1; | |
140 | @end | |
141 | ||
142 | @interface NSString (Cydia) | |
143 | + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length; | |
a54b1c10 | 144 | - (NSComparisonResult) compareByPath:(NSString *)other; |
2388b078 JF |
145 | @end |
146 | ||
147 | @implementation NSString (Cydia) | |
148 | ||
149 | + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length { | |
150 | char data[length + 1]; | |
151 | memcpy(data, bytes, length); | |
152 | data[length] = '\0'; | |
153 | return [NSString stringWithUTF8String:data]; | |
154 | } | |
155 | ||
a54b1c10 JF |
156 | - (NSComparisonResult) compareByPath:(NSString *)other { |
157 | NSString *prefix = [self commonPrefixWithString:other options:0]; | |
158 | size_t length = [prefix length]; | |
159 | ||
160 | NSRange lrange = NSMakeRange(length, [self length] - length); | |
161 | NSRange rrange = NSMakeRange(length, [other length] - length); | |
162 | ||
163 | lrange = [self rangeOfString:@"/" options:0 range:lrange]; | |
164 | rrange = [other rangeOfString:@"/" options:0 range:rrange]; | |
165 | ||
166 | NSComparisonResult value; | |
167 | ||
168 | if (lrange.location == NSNotFound && rrange.location == NSNotFound) | |
169 | value = NSOrderedSame; | |
170 | else if (lrange.location == NSNotFound) | |
171 | value = NSOrderedAscending; | |
172 | else if (rrange.location == NSNotFound) | |
173 | value = NSOrderedDescending; | |
174 | else | |
175 | value = NSOrderedSame; | |
176 | ||
177 | NSString *lpath = lrange.location == NSNotFound ? [self substringFromIndex:length] : | |
178 | [self substringWithRange:NSMakeRange(length, lrange.location - length)]; | |
179 | NSString *rpath = rrange.location == NSNotFound ? [other substringFromIndex:length] : | |
180 | [other substringWithRange:NSMakeRange(length, rrange.location - length)]; | |
181 | ||
182 | NSComparisonResult result = [lpath compare:rpath]; | |
183 | return result == NSOrderedSame ? value : result; | |
184 | } | |
185 | ||
2388b078 JF |
186 | @end |
187 | ||
b4d89997 JF |
188 | /* Perl-Compatible RegEx {{{ */ |
189 | class Pcre { | |
190 | private: | |
191 | pcre *code_; | |
192 | pcre_extra *study_; | |
193 | int capture_; | |
194 | int *matches_; | |
195 | const char *data_; | |
196 | ||
197 | public: | |
198 | Pcre(const char *regex) : | |
199 | study_(NULL) | |
200 | { | |
201 | const char *error; | |
202 | int offset; | |
203 | code_ = pcre_compile(regex, 0, &error, &offset, NULL); | |
204 | ||
205 | if (code_ == NULL) { | |
206 | fprintf(stderr, "%d:%s\n", offset, error); | |
207 | _assert(false); | |
208 | } | |
209 | ||
210 | pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_); | |
211 | matches_ = new int[(capture_ + 1) * 3]; | |
212 | } | |
213 | ||
214 | ~Pcre() { | |
215 | pcre_free(code_); | |
216 | delete matches_; | |
217 | } | |
218 | ||
219 | NSString *operator [](size_t match) { | |
2388b078 | 220 | return [NSString stringWithUTF8Bytes:(data_ + matches_[match * 2]) length:(matches_[match * 2 + 1] - matches_[match * 2])]; |
b4d89997 JF |
221 | } |
222 | ||
8b29f8e6 JF |
223 | bool operator ()(NSString *data) { |
224 | // XXX: length is for characters, not for bytes | |
225 | return operator ()([data UTF8String], [data length]); | |
226 | } | |
227 | ||
b4d89997 JF |
228 | bool operator ()(const char *data, size_t size) { |
229 | data_ = data; | |
230 | return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0; | |
231 | } | |
232 | }; | |
233 | /* }}} */ | |
36bb2ca2 JF |
234 | /* Mime Addresses {{{ */ |
235 | Pcre email_r("^\"?(.*)\"? <([^>]*)>$"); | |
236 | ||
237 | @interface Address : NSObject { | |
238 | NSString *name_; | |
239 | NSString *email_; | |
240 | } | |
241 | ||
242 | - (NSString *) name; | |
243 | - (NSString *) email; | |
244 | ||
245 | + (Address *) addressWithString:(NSString *)string; | |
246 | - (Address *) initWithString:(NSString *)string; | |
247 | @end | |
248 | ||
249 | @implementation Address | |
250 | ||
251 | - (void) dealloc { | |
252 | [name_ release]; | |
253 | if (email_ != nil) | |
254 | [email_ release]; | |
255 | [super dealloc]; | |
256 | } | |
257 | ||
258 | - (NSString *) name { | |
259 | return name_; | |
260 | } | |
261 | ||
262 | - (NSString *) email { | |
263 | return email_; | |
264 | } | |
265 | ||
266 | + (Address *) addressWithString:(NSString *)string { | |
267 | return [[[Address alloc] initWithString:string] autorelease]; | |
268 | } | |
269 | ||
270 | - (Address *) initWithString:(NSString *)string { | |
271 | if ((self = [super init]) != nil) { | |
272 | const char *data = [string UTF8String]; | |
273 | size_t size = [string length]; | |
274 | ||
275 | if (email_r(data, size)) { | |
276 | name_ = [email_r[1] retain]; | |
277 | email_ = [email_r[2] retain]; | |
278 | } else { | |
2388b078 JF |
279 | name_ = [[NSString alloc] |
280 | initWithBytes:data | |
281 | length:size | |
282 | encoding:kCFStringEncodingUTF8 | |
283 | ]; | |
284 | ||
36bb2ca2 JF |
285 | email_ = nil; |
286 | } | |
287 | } return self; | |
288 | } | |
289 | ||
290 | @end | |
291 | /* }}} */ | |
5f6bff8c | 292 | /* CoreGraphics Primitives {{{ */ |
b4d89997 JF |
293 | class CGColor { |
294 | private: | |
295 | CGColorRef color_; | |
296 | ||
297 | public: | |
36bb2ca2 JF |
298 | CGColor() : |
299 | color_(NULL) | |
300 | { | |
301 | } | |
302 | ||
303 | CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) : | |
304 | color_(NULL) | |
305 | { | |
306 | Set(space, red, green, blue, alpha); | |
307 | } | |
308 | ||
309 | void Clear() { | |
310 | if (color_ != NULL) | |
311 | CGColorRelease(color_); | |
b4d89997 JF |
312 | } |
313 | ||
314 | ~CGColor() { | |
36bb2ca2 JF |
315 | Clear(); |
316 | } | |
317 | ||
318 | void Set(CGColorSpaceRef space, float red, float green, float blue, float alpha) { | |
319 | Clear(); | |
320 | float color[] = {red, green, blue, alpha}; | |
321 | color_ = CGColorCreate(space, color); | |
b4d89997 JF |
322 | } |
323 | ||
324 | operator CGColorRef() { | |
325 | return color_; | |
326 | } | |
327 | }; | |
328 | ||
329 | class GSFont { | |
330 | private: | |
331 | GSFontRef font_; | |
332 | ||
333 | public: | |
334 | ~GSFont() { | |
b4d89997 JF |
335 | CFRelease(font_); |
336 | } | |
337 | }; | |
338 | /* }}} */ | |
36bb2ca2 JF |
339 | /* Right Alignment {{{ */ |
340 | @interface UIRightTextLabel : UITextLabel { | |
341 | float _savedRightEdgeX; | |
342 | BOOL _sizedtofit_flag; | |
343 | } | |
344 | ||
345 | - (void) setFrame:(CGRect)frame; | |
346 | - (void) setText:(NSString *)text; | |
347 | - (void) realignText; | |
348 | @end | |
349 | ||
350 | @implementation UIRightTextLabel | |
351 | ||
352 | - (void) setFrame:(CGRect)frame { | |
353 | [super setFrame:frame]; | |
354 | if (_sizedtofit_flag == NO) { | |
355 | _savedRightEdgeX = frame.origin.x; | |
356 | [self realignText]; | |
357 | } | |
358 | } | |
359 | ||
360 | - (void) setText:(NSString *)text { | |
361 | [super setText:text]; | |
362 | [self realignText]; | |
363 | } | |
364 | ||
365 | - (void) realignText { | |
366 | CGRect oldFrame = [self frame]; | |
367 | ||
368 | _sizedtofit_flag = YES; | |
369 | [self sizeToFit]; // shrink down size so I can right align it | |
370 | ||
371 | CGRect newFrame = [self frame]; | |
372 | ||
373 | oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width; | |
374 | oldFrame.size.width = newFrame.size.width; | |
375 | [super setFrame:oldFrame]; | |
376 | _sizedtofit_flag = NO; | |
377 | } | |
378 | ||
379 | @end | |
380 | /* }}} */ | |
b4d89997 | 381 | |
36bb2ca2 | 382 | /* Random Global Variables {{{ */ |
3178d79b | 383 | static const int PulseInterval_ = 50000; |
2388b078 JF |
384 | static const int ButtonBarHeight_ = 48; |
385 | static const float KeyboardTime_ = 0.4f; | |
2a8d9add | 386 | |
36bb2ca2 JF |
387 | static CGColor Black_; |
388 | static CGColor Clear_; | |
389 | static CGColor Red_; | |
390 | static CGColor White_; | |
391 | ||
d73cede2 JF |
392 | static NSString *Home_; |
393 | static BOOL Sounds_Keyboard_; | |
394 | ||
2388b078 | 395 | static BOOL Advanced_; |
a54b1c10 JF |
396 | static BOOL Loaded_; |
397 | static BOOL Ignored_; | |
2388b078 | 398 | |
2a8d9add | 399 | const char *Firmware_ = NULL; |
3178d79b JF |
400 | const char *Machine_ = NULL; |
401 | const char *SerialNumber_ = NULL; | |
402 | ||
2a8d9add JF |
403 | unsigned Major_; |
404 | unsigned Minor_; | |
405 | unsigned BugFix_; | |
406 | ||
36bb2ca2 JF |
407 | CGColorSpaceRef space_; |
408 | ||
2a8d9add | 409 | #define FW_LEAST(major, minor, bugfix) \ |
51a1ffdf JF |
410 | (major < Major_ || major == Major_ && \ |
411 | (minor < Minor_ || minor == Minor_ && \ | |
412 | bugfix <= BugFix_)) | |
2a8d9add | 413 | |
36bb2ca2 JF |
414 | bool bootstrap_; |
415 | bool restart_; | |
b31b87cc | 416 | |
b4d89997 JF |
417 | static NSMutableDictionary *Metadata_; |
418 | static NSMutableDictionary *Packages_; | |
bbb879fb | 419 | static bool Changed_; |
b4d89997 | 420 | static NSDate *now_; |
8da60fb7 | 421 | |
23672b39 JF |
422 | NSString *GetLastUpdate() { |
423 | NSDate *update = [Metadata_ objectForKey:@"LastUpdate"]; | |
424 | ||
425 | if (update == nil) | |
426 | return @"Never or Unknown"; | |
427 | ||
428 | CFLocaleRef locale = CFLocaleCopyCurrent(); | |
429 | CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle); | |
430 | CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update); | |
431 | ||
432 | CFRelease(formatter); | |
23672b39 JF |
433 | CFRelease(locale); |
434 | ||
435 | return [(NSString *) formatted autorelease]; | |
436 | } | |
36bb2ca2 JF |
437 | /* }}} */ |
438 | /* Display Helpers {{{ */ | |
439 | inline float Interpolate(float begin, float end, float fraction) { | |
440 | return (end - begin) * fraction + begin; | |
441 | } | |
2367a917 | 442 | |
8fe19fc1 JF |
443 | NSString *SizeString(double size) { |
444 | unsigned power = 0; | |
445 | while (size > 1024) { | |
446 | size /= 1024; | |
447 | ++power; | |
448 | } | |
449 | ||
450 | static const char *powers_[] = {"B", "kB", "MB", "GB"}; | |
451 | ||
452 | return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]]; | |
453 | } | |
454 | ||
b4d89997 JF |
455 | static const float TextViewOffset_ = 22; |
456 | ||
457 | UITextView *GetTextView(NSString *value, float left, bool html) { | |
458 | UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]); | |
459 | [text setEditable:NO]; | |
460 | [text setTextSize:16]; | |
1e7a90f5 | 461 | /*if (html) |
b4d89997 | 462 | [text setHTML:value]; |
1e7a90f5 | 463 | else*/ |
b4d89997 JF |
464 | [text setText:value]; |
465 | [text setEnabled:NO]; | |
466 | ||
36bb2ca2 | 467 | [text setBackgroundColor:Clear_]; |
b4d89997 JF |
468 | |
469 | CGRect frame = [text frame]; | |
470 | [text setFrame:frame]; | |
471 | CGRect rect = [text visibleTextRect]; | |
472 | frame.size.height = rect.size.height; | |
473 | [text setFrame:frame]; | |
474 | ||
475 | return text; | |
476 | } | |
4cf4165e JF |
477 | |
478 | NSString *Simplify(NSString *title) { | |
479 | const char *data = [title UTF8String]; | |
480 | size_t size = [title length]; | |
481 | ||
482 | Pcre title_r("^(.*?)( \\(.*\\))?$"); | |
483 | if (title_r(data, size)) | |
484 | return title_r[1]; | |
485 | else | |
486 | return title; | |
487 | } | |
36bb2ca2 JF |
488 | /* }}} */ |
489 | ||
d36e83a3 | 490 | /* Delegate Prototypes {{{ */ |
36bb2ca2 JF |
491 | @class Package; |
492 | @class Source; | |
493 | ||
494 | @protocol ProgressDelegate | |
495 | - (void) setProgressError:(NSString *)error; | |
496 | - (void) setProgressTitle:(NSString *)title; | |
497 | - (void) setProgressPercent:(float)percent; | |
498 | - (void) addProgressOutput:(NSString *)output; | |
499 | @end | |
500 | ||
8b29f8e6 | 501 | @protocol ConfigurationDelegate |
5a09ae08 | 502 | - (void) repairWithSelector:(SEL)selector; |
8b29f8e6 JF |
503 | - (void) setConfigurationData:(NSString *)data; |
504 | @end | |
505 | ||
36bb2ca2 JF |
506 | @protocol CydiaDelegate |
507 | - (void) installPackage:(Package *)package; | |
508 | - (void) removePackage:(Package *)package; | |
509 | - (void) slideUp:(UIAlertSheet *)alert; | |
510 | - (void) distUpgrade; | |
511 | @end | |
d36e83a3 | 512 | /* }}} */ |
b4d89997 | 513 | |
dc5812ec JF |
514 | /* Status Delegation {{{ */ |
515 | class Status : | |
516 | public pkgAcquireStatus | |
517 | { | |
518 | private: | |
36bb2ca2 | 519 | _transient id<ProgressDelegate> delegate_; |
dc5812ec JF |
520 | |
521 | public: | |
522 | Status() : | |
523 | delegate_(nil) | |
524 | { | |
525 | } | |
526 | ||
527 | void setDelegate(id delegate) { | |
528 | delegate_ = delegate; | |
529 | } | |
530 | ||
531 | virtual bool MediaChange(std::string media, std::string drive) { | |
532 | return false; | |
533 | } | |
534 | ||
535 | virtual void IMSHit(pkgAcquire::ItemDesc &item) { | |
dc5812ec JF |
536 | } |
537 | ||
538 | virtual void Fetch(pkgAcquire::ItemDesc &item) { | |
2388b078 | 539 | [delegate_ setProgressTitle:[NSString stringWithUTF8String:("Downloading " + item.ShortDesc).c_str()]]; |
dc5812ec JF |
540 | } |
541 | ||
542 | virtual void Done(pkgAcquire::ItemDesc &item) { | |
dc5812ec JF |
543 | } |
544 | ||
545 | virtual void Fail(pkgAcquire::ItemDesc &item) { | |
1d80f6b9 JF |
546 | if ( |
547 | item.Owner->Status == pkgAcquire::Item::StatIdle || | |
548 | item.Owner->Status == pkgAcquire::Item::StatDone | |
549 | ) | |
550 | return; | |
551 | ||
2388b078 | 552 | [delegate_ setProgressError:[NSString stringWithUTF8String:item.Owner->ErrorText.c_str()]]; |
dc5812ec JF |
553 | } |
554 | ||
555 | virtual bool Pulse(pkgAcquire *Owner) { | |
2367a917 JF |
556 | bool value = pkgAcquireStatus::Pulse(Owner); |
557 | ||
558 | float percent( | |
559 | double(CurrentBytes + CurrentItems) / | |
560 | double(TotalBytes + TotalItems) | |
561 | ); | |
562 | ||
36bb2ca2 | 563 | [delegate_ setProgressPercent:percent]; |
2367a917 | 564 | return value; |
dc5812ec JF |
565 | } |
566 | ||
567 | virtual void Start() { | |
dc5812ec JF |
568 | } |
569 | ||
570 | virtual void Stop() { | |
dc5812ec JF |
571 | } |
572 | }; | |
573 | /* }}} */ | |
574 | /* Progress Delegation {{{ */ | |
575 | class Progress : | |
576 | public OpProgress | |
577 | { | |
578 | private: | |
36bb2ca2 | 579 | _transient id<ProgressDelegate> delegate_; |
dc5812ec JF |
580 | |
581 | protected: | |
582 | virtual void Update() { | |
2388b078 | 583 | [delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]]; |
36bb2ca2 | 584 | [delegate_ setProgressPercent:(Percent / 100)]; |
dc5812ec JF |
585 | } |
586 | ||
587 | public: | |
588 | Progress() : | |
589 | delegate_(nil) | |
590 | { | |
591 | } | |
592 | ||
593 | void setDelegate(id delegate) { | |
594 | delegate_ = delegate; | |
595 | } | |
596 | ||
597 | virtual void Done() { | |
36bb2ca2 | 598 | [delegate_ setProgressPercent:1]; |
dc5812ec JF |
599 | } |
600 | }; | |
601 | /* }}} */ | |
602 | ||
36bb2ca2 JF |
603 | /* Database Interface {{{ */ |
604 | @interface Database : NSObject { | |
605 | pkgCacheFile cache_; | |
5a09ae08 | 606 | pkgDepCache::Policy *policy_; |
36bb2ca2 JF |
607 | pkgRecords *records_; |
608 | pkgProblemResolver *resolver_; | |
609 | pkgAcquire *fetcher_; | |
610 | FileFd *lock_; | |
611 | SPtr<pkgPackageManager> manager_; | |
612 | pkgSourceList *list_; | |
5f6bff8c | 613 | |
36bb2ca2 JF |
614 | NSMutableDictionary *sources_; |
615 | NSMutableArray *packages_; | |
b4d89997 | 616 | |
8b29f8e6 | 617 | _transient id<ConfigurationDelegate, ProgressDelegate> delegate_; |
36bb2ca2 JF |
618 | Status status_; |
619 | Progress progress_; | |
8b29f8e6 | 620 | |
36bb2ca2 | 621 | int statusfd_; |
8b29f8e6 | 622 | FILE *input_; |
dc5812ec JF |
623 | } |
624 | ||
36bb2ca2 JF |
625 | - (void) _readStatus:(NSNumber *)fd; |
626 | - (void) _readOutput:(NSNumber *)fd; | |
2367a917 | 627 | |
8b29f8e6 JF |
628 | - (FILE *) input; |
629 | ||
36bb2ca2 | 630 | - (Package *) packageWithName:(NSString *)name; |
dc5812ec | 631 | |
36bb2ca2 JF |
632 | - (Database *) init; |
633 | - (pkgCacheFile &) cache; | |
5a09ae08 | 634 | - (pkgDepCache::Policy *) policy; |
36bb2ca2 JF |
635 | - (pkgRecords *) records; |
636 | - (pkgProblemResolver *) resolver; | |
637 | - (pkgAcquire &) fetcher; | |
638 | - (NSArray *) packages; | |
639 | - (void) reloadData; | |
640 | ||
5a09ae08 | 641 | - (void) configure; |
36bb2ca2 JF |
642 | - (void) prepare; |
643 | - (void) perform; | |
644 | - (void) upgrade; | |
645 | - (void) update; | |
646 | ||
647 | - (void) updateWithStatus:(Status &)status; | |
648 | ||
649 | - (void) setDelegate:(id)delegate; | |
650 | - (Source *) getSource:(const pkgCache::PkgFileIterator &)file; | |
dc5812ec | 651 | @end |
36bb2ca2 | 652 | /* }}} */ |
dc5812ec | 653 | |
36bb2ca2 JF |
654 | /* Source Class {{{ */ |
655 | @interface Source : NSObject { | |
656 | NSString *description_; | |
657 | NSString *label_; | |
658 | NSString *origin_; | |
dc5812ec | 659 | |
36bb2ca2 JF |
660 | NSString *uri_; |
661 | NSString *distribution_; | |
662 | NSString *type_; | |
663 | NSString *version_; | |
2367a917 | 664 | |
36bb2ca2 | 665 | NSString *defaultIcon_; |
dc5812ec | 666 | |
36bb2ca2 | 667 | BOOL trusted_; |
dc5812ec JF |
668 | } |
669 | ||
36bb2ca2 | 670 | - (Source *) initWithMetaIndex:(metaIndex *)index; |
dc5812ec | 671 | |
36bb2ca2 | 672 | - (BOOL) trusted; |
dc5812ec | 673 | |
36bb2ca2 JF |
674 | - (NSString *) uri; |
675 | - (NSString *) distribution; | |
676 | - (NSString *) type; | |
677 | ||
678 | - (NSString *) description; | |
679 | - (NSString *) label; | |
680 | - (NSString *) origin; | |
681 | - (NSString *) version; | |
dc5812ec | 682 | |
36bb2ca2 | 683 | - (NSString *) defaultIcon; |
dc5812ec | 684 | @end |
dc5812ec | 685 | |
36bb2ca2 | 686 | @implementation Source |
dc5812ec | 687 | |
36bb2ca2 JF |
688 | - (void) dealloc { |
689 | [uri_ release]; | |
690 | [distribution_ release]; | |
691 | [type_ release]; | |
dc5812ec | 692 | |
36bb2ca2 JF |
693 | if (description_ != nil) |
694 | [description_ release]; | |
695 | if (label_ != nil) | |
696 | [label_ release]; | |
697 | if (origin_ != nil) | |
698 | [origin_ release]; | |
699 | if (version_ != nil) | |
700 | [version_ release]; | |
701 | if (defaultIcon_ != nil) | |
702 | [defaultIcon_ release]; | |
dc5812ec | 703 | |
36bb2ca2 | 704 | [super dealloc]; |
dc5812ec JF |
705 | } |
706 | ||
36bb2ca2 JF |
707 | - (Source *) initWithMetaIndex:(metaIndex *)index { |
708 | if ((self = [super init]) != nil) { | |
709 | trusted_ = index->IsTrusted(); | |
dc5812ec | 710 | |
2388b078 JF |
711 | uri_ = [[NSString stringWithUTF8String:index->GetURI().c_str()] retain]; |
712 | distribution_ = [[NSString stringWithUTF8String:index->GetDist().c_str()] retain]; | |
713 | type_ = [[NSString stringWithUTF8String:index->GetType()] retain]; | |
dc5812ec | 714 | |
36bb2ca2 JF |
715 | description_ = nil; |
716 | label_ = nil; | |
717 | origin_ = nil; | |
718 | version_ = nil; | |
719 | defaultIcon_ = nil; | |
dc5812ec | 720 | |
36bb2ca2 JF |
721 | debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index)); |
722 | if (dindex != NULL) { | |
723 | std::ifstream release(dindex->MetaIndexFile("Release").c_str()); | |
724 | std::string line; | |
725 | while (std::getline(release, line)) { | |
726 | std::string::size_type colon(line.find(':')); | |
727 | if (colon == std::string::npos) | |
728 | continue; | |
dc5812ec | 729 | |
36bb2ca2 JF |
730 | std::string name(line.substr(0, colon)); |
731 | std::string value(line.substr(colon + 1)); | |
732 | while (!value.empty() && value[0] == ' ') | |
733 | value = value.substr(1); | |
dc5812ec | 734 | |
36bb2ca2 | 735 | if (name == "Default-Icon") |
2388b078 | 736 | defaultIcon_ = [[NSString stringWithUTF8String:value.c_str()] retain]; |
36bb2ca2 | 737 | else if (name == "Description") |
2388b078 | 738 | description_ = [[NSString stringWithUTF8String:value.c_str()] retain]; |
36bb2ca2 | 739 | else if (name == "Label") |
2388b078 | 740 | label_ = [[NSString stringWithUTF8String:value.c_str()] retain]; |
36bb2ca2 | 741 | else if (name == "Origin") |
2388b078 | 742 | origin_ = [[NSString stringWithUTF8String:value.c_str()] retain]; |
36bb2ca2 | 743 | else if (name == "Version") |
2388b078 | 744 | version_ = [[NSString stringWithUTF8String:value.c_str()] retain]; |
36bb2ca2 JF |
745 | } |
746 | } | |
747 | } return self; | |
2367a917 | 748 | } |
dc5812ec | 749 | |
36bb2ca2 JF |
750 | - (BOOL) trusted { |
751 | return trusted_; | |
752 | } | |
3178d79b | 753 | |
36bb2ca2 JF |
754 | - (NSString *) uri { |
755 | return uri_; | |
756 | } | |
ec97ef06 | 757 | |
36bb2ca2 JF |
758 | - (NSString *) distribution { |
759 | return distribution_; | |
760 | } | |
dc5812ec | 761 | |
36bb2ca2 JF |
762 | - (NSString *) type { |
763 | return type_; | |
dc5812ec JF |
764 | } |
765 | ||
36bb2ca2 JF |
766 | - (NSString *) description { |
767 | return description_; | |
768 | } | |
b4d89997 | 769 | |
36bb2ca2 JF |
770 | - (NSString *) label { |
771 | return label_; | |
772 | } | |
3178d79b | 773 | |
36bb2ca2 JF |
774 | - (NSString *) origin { |
775 | return origin_; | |
776 | } | |
3178d79b | 777 | |
36bb2ca2 JF |
778 | - (NSString *) version { |
779 | return version_; | |
780 | } | |
2367a917 | 781 | |
36bb2ca2 JF |
782 | - (NSString *) defaultIcon { |
783 | return defaultIcon_; | |
784 | } | |
2367a917 | 785 | |
2388b078 JF |
786 | @end |
787 | /* }}} */ | |
788 | /* Relationship Class {{{ */ | |
789 | @interface Relationship : NSObject { | |
790 | NSString *type_; | |
791 | NSString *id_; | |
792 | } | |
793 | ||
794 | - (NSString *) type; | |
795 | - (NSString *) id; | |
796 | - (NSString *) name; | |
797 | ||
798 | @end | |
799 | ||
800 | @implementation Relationship | |
801 | ||
802 | - (void) dealloc { | |
803 | [type_ release]; | |
804 | [id_ release]; | |
805 | [super dealloc]; | |
806 | } | |
807 | ||
808 | - (NSString *) type { | |
809 | return type_; | |
810 | } | |
811 | ||
812 | - (NSString *) id { | |
813 | return id_; | |
814 | } | |
815 | ||
816 | - (NSString *) name { | |
817 | _assert(false); | |
818 | return nil; | |
819 | } | |
820 | ||
dc5812ec | 821 | @end |
b4d89997 | 822 | /* }}} */ |
36bb2ca2 JF |
823 | /* Package Class {{{ */ |
824 | NSString *Scour(const char *field, const char *begin, const char *end) { | |
825 | size_t i(0), l(strlen(field)); | |
dc5812ec | 826 | |
36bb2ca2 JF |
827 | for (;;) { |
828 | const char *name = begin + i; | |
829 | const char *colon = name + l; | |
830 | const char *value = colon + 1; | |
06aa974d | 831 | |
36bb2ca2 JF |
832 | if ( |
833 | value < end && | |
834 | *colon == ':' && | |
835 | memcmp(name, field, l) == 0 | |
836 | ) { | |
837 | while (value != end && value[0] == ' ') | |
838 | ++value; | |
839 | const char *line = std::find(value, end, '\n'); | |
840 | while (line != value && line[-1] == ' ') | |
841 | --line; | |
2388b078 JF |
842 | |
843 | return [NSString stringWithUTF8Bytes:value length:(line - value)]; | |
36bb2ca2 JF |
844 | } else { |
845 | begin = std::find(begin, end, '\n'); | |
846 | if (begin == end) | |
847 | return nil; | |
848 | ++begin; | |
849 | } | |
850 | } | |
851 | } | |
b4d89997 | 852 | |
36bb2ca2 JF |
853 | @interface Package : NSObject { |
854 | pkgCache::PkgIterator iterator_; | |
855 | _transient Database *database_; | |
856 | pkgCache::VerIterator version_; | |
857 | pkgCache::VerFileIterator file_; | |
bbb879fb | 858 | |
36bb2ca2 | 859 | Source *source_; |
bbb879fb | 860 | bool cached_; |
dc5812ec | 861 | |
36bb2ca2 JF |
862 | NSString *latest_; |
863 | NSString *installed_; | |
dc5812ec | 864 | |
36bb2ca2 JF |
865 | NSString *id_; |
866 | NSString *name_; | |
867 | NSString *tagline_; | |
868 | NSString *icon_; | |
869 | NSString *website_; | |
2388b078 JF |
870 | |
871 | NSArray *relationships_; | |
b4d89997 JF |
872 | } |
873 | ||
5a09ae08 | 874 | - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database; |
36bb2ca2 | 875 | + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database; |
b4d89997 | 876 | |
2388b078 JF |
877 | - (pkgCache::PkgIterator) iterator; |
878 | ||
36bb2ca2 JF |
879 | - (NSString *) section; |
880 | - (Address *) maintainer; | |
881 | - (size_t) size; | |
882 | - (NSString *) description; | |
883 | - (NSString *) index; | |
dc5812ec | 884 | |
36bb2ca2 | 885 | - (NSDate *) seen; |
9e98e020 | 886 | |
36bb2ca2 JF |
887 | - (NSString *) latest; |
888 | - (NSString *) installed; | |
5a09ae08 JF |
889 | |
890 | - (BOOL) valid; | |
36bb2ca2 JF |
891 | - (BOOL) upgradable; |
892 | - (BOOL) essential; | |
893 | - (BOOL) broken; | |
b4d89997 | 894 | |
36bb2ca2 JF |
895 | - (NSString *) id; |
896 | - (NSString *) name; | |
897 | - (NSString *) tagline; | |
898 | - (NSString *) icon; | |
899 | - (NSString *) website; | |
b4d89997 | 900 | |
2388b078 JF |
901 | - (NSArray *) relationships; |
902 | ||
36bb2ca2 | 903 | - (Source *) source; |
b4d89997 | 904 | |
36bb2ca2 | 905 | - (BOOL) matches:(NSString *)text; |
b4d89997 | 906 | |
36bb2ca2 JF |
907 | - (NSComparisonResult) compareByName:(Package *)package; |
908 | - (NSComparisonResult) compareBySection:(Package *)package; | |
909 | - (NSComparisonResult) compareBySectionAndName:(Package *)package; | |
910 | - (NSComparisonResult) compareForChanges:(Package *)package; | |
b4d89997 | 911 | |
36bb2ca2 JF |
912 | - (void) install; |
913 | - (void) remove; | |
06aa974d | 914 | |
36bb2ca2 JF |
915 | - (NSNumber *) isSearchedForBy:(NSString *)search; |
916 | - (NSNumber *) isInstalledInSection:(NSString *)section; | |
917 | - (NSNumber *) isUninstalledInSection:(NSString *)section; | |
b4d89997 | 918 | |
36bb2ca2 | 919 | @end |
b4d89997 | 920 | |
36bb2ca2 | 921 | @implementation Package |
b4d89997 | 922 | |
36bb2ca2 | 923 | - (void) dealloc { |
bbb879fb JF |
924 | if (source_ != nil) |
925 | [source_ release]; | |
926 | ||
36bb2ca2 JF |
927 | [latest_ release]; |
928 | if (installed_ != nil) | |
929 | [installed_ release]; | |
b4d89997 | 930 | |
36bb2ca2 JF |
931 | [id_ release]; |
932 | if (name_ != nil) | |
933 | [name_ release]; | |
934 | [tagline_ release]; | |
935 | if (icon_ != nil) | |
936 | [icon_ release]; | |
937 | if (website_ != nil) | |
938 | [website_ release]; | |
9e98e020 | 939 | |
2388b078 JF |
940 | if (relationships_ != nil) |
941 | [relationships_ release]; | |
942 | ||
36bb2ca2 | 943 | [super dealloc]; |
b4d89997 JF |
944 | } |
945 | ||
5a09ae08 | 946 | - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database { |
36bb2ca2 JF |
947 | if ((self = [super init]) != nil) { |
948 | iterator_ = iterator; | |
949 | database_ = database; | |
b4d89997 | 950 | |
5a09ae08 JF |
951 | version_ = [database_ policy]->GetCandidateVer(iterator_); |
952 | latest_ = version_.end() ? nil : [[NSString stringWithUTF8String:version_.VerStr()] retain]; | |
bbb879fb | 953 | |
5a09ae08 JF |
954 | if (!version_.end()) |
955 | file_ = version_.FileList(); | |
956 | else { | |
957 | pkgCache &cache([database_ cache]); | |
958 | file_ = pkgCache::VerFileIterator(cache, cache.VerFileP); | |
959 | } | |
b4d89997 | 960 | |
5a09ae08 JF |
961 | pkgCache::VerIterator current = iterator_.CurrentVer(); |
962 | installed_ = current.end() ? nil : [[NSString stringWithUTF8String:current.VerStr()] retain]; | |
b4d89997 | 963 | |
2388b078 | 964 | id_ = [[[NSString stringWithUTF8String:iterator_.Name()] lowercaseString] retain]; |
5a09ae08 JF |
965 | |
966 | if (!file_.end()) { | |
967 | pkgRecords::Parser *parser = &[database_ records]->Lookup(file_); | |
968 | ||
969 | const char *begin, *end; | |
970 | parser->GetRec(begin, end); | |
971 | ||
972 | name_ = Scour("Name", begin, end); | |
973 | if (name_ != nil) | |
974 | name_ = [name_ retain]; | |
975 | tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain]; | |
976 | icon_ = Scour("Icon", begin, end); | |
977 | if (icon_ != nil) | |
978 | icon_ = [icon_ retain]; | |
979 | website_ = Scour("Website", begin, end); | |
980 | if (website_ != nil) | |
981 | website_ = [website_ retain]; | |
982 | } | |
06aa974d | 983 | |
36bb2ca2 JF |
984 | NSMutableDictionary *metadata = [Packages_ objectForKey:id_]; |
985 | if (metadata == nil || [metadata count] == 0) { | |
986 | metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys: | |
987 | now_, @"FirstSeen", | |
988 | nil]; | |
b4d89997 | 989 | |
36bb2ca2 | 990 | [Packages_ setObject:metadata forKey:id_]; |
bbb879fb | 991 | Changed_ = true; |
36bb2ca2 JF |
992 | } |
993 | } return self; | |
dc5812ec JF |
994 | } |
995 | ||
36bb2ca2 | 996 | + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database { |
5a09ae08 JF |
997 | return [[[Package alloc] |
998 | initWithIterator:iterator | |
999 | database:database | |
1000 | ] autorelease]; | |
dc5812ec JF |
1001 | } |
1002 | ||
2388b078 JF |
1003 | - (pkgCache::PkgIterator) iterator { |
1004 | return iterator_; | |
1005 | } | |
1006 | ||
36bb2ca2 JF |
1007 | - (NSString *) section { |
1008 | const char *section = iterator_.Section(); | |
2388b078 | 1009 | return section == NULL ? nil : [[NSString stringWithUTF8String:section] stringByReplacingCharacter:'_' withCharacter:' ']; |
dc5812ec JF |
1010 | } |
1011 | ||
36bb2ca2 | 1012 | - (Address *) maintainer { |
5a09ae08 JF |
1013 | if (file_.end()) |
1014 | return nil; | |
36bb2ca2 | 1015 | pkgRecords::Parser *parser = &[database_ records]->Lookup(file_); |
2388b078 | 1016 | return [Address addressWithString:[NSString stringWithUTF8String:parser->Maintainer().c_str()]]; |
8fe19fc1 JF |
1017 | } |
1018 | ||
36bb2ca2 | 1019 | - (size_t) size { |
5a09ae08 | 1020 | return version_.end() ? 0 : version_->InstalledSize; |
dc5812ec JF |
1021 | } |
1022 | ||
36bb2ca2 | 1023 | - (NSString *) description { |
5a09ae08 JF |
1024 | if (file_.end()) |
1025 | return nil; | |
36bb2ca2 | 1026 | pkgRecords::Parser *parser = &[database_ records]->Lookup(file_); |
2388b078 | 1027 | NSString *description([NSString stringWithUTF8String:parser->LongDesc().c_str()]); |
8fe19fc1 | 1028 | |
36bb2ca2 JF |
1029 | NSArray *lines = [description componentsSeparatedByString:@"\n"]; |
1030 | NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)]; | |
1031 | if ([lines count] < 2) | |
1032 | return nil; | |
3178d79b | 1033 | |
36bb2ca2 JF |
1034 | NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet]; |
1035 | for (size_t i(1); i != [lines count]; ++i) { | |
1036 | NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace]; | |
1037 | [trimmed addObject:trim]; | |
1038 | } | |
3178d79b | 1039 | |
36bb2ca2 JF |
1040 | return [trimmed componentsJoinedByString:@"\n"]; |
1041 | } | |
dc5812ec | 1042 | |
36bb2ca2 JF |
1043 | - (NSString *) index { |
1044 | NSString *index = [[[self name] substringToIndex:1] uppercaseString]; | |
1045 | return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123"; | |
1046 | } | |
3178d79b | 1047 | |
36bb2ca2 JF |
1048 | - (NSDate *) seen { |
1049 | return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"]; | |
3178d79b JF |
1050 | } |
1051 | ||
36bb2ca2 JF |
1052 | - (NSString *) latest { |
1053 | return latest_; | |
8fe19fc1 JF |
1054 | } |
1055 | ||
36bb2ca2 JF |
1056 | - (NSString *) installed { |
1057 | return installed_; | |
3178d79b JF |
1058 | } |
1059 | ||
5a09ae08 JF |
1060 | - (BOOL) valid { |
1061 | return !version_.end(); | |
1062 | } | |
1063 | ||
36bb2ca2 | 1064 | - (BOOL) upgradable { |
a54b1c10 JF |
1065 | pkgCache::VerIterator current = iterator_.CurrentVer(); |
1066 | ||
1067 | if (current.end()) | |
36bb2ca2 | 1068 | return [self essential]; |
a54b1c10 | 1069 | else { |
5a09ae08 | 1070 | pkgCache::VerIterator candidate = [database_ policy]->GetCandidateVer(iterator_); |
a54b1c10 JF |
1071 | return !candidate.end() && candidate != current; |
1072 | } | |
36bb2ca2 | 1073 | } |
3178d79b | 1074 | |
36bb2ca2 JF |
1075 | - (BOOL) essential { |
1076 | return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES; | |
3178d79b JF |
1077 | } |
1078 | ||
36bb2ca2 JF |
1079 | - (BOOL) broken { |
1080 | return (*[database_ cache])[iterator_].InstBroken(); | |
8fe19fc1 JF |
1081 | } |
1082 | ||
36bb2ca2 JF |
1083 | - (NSString *) id { |
1084 | return id_; | |
8fe19fc1 JF |
1085 | } |
1086 | ||
36bb2ca2 JF |
1087 | - (NSString *) name { |
1088 | return name_ == nil ? id_ : name_; | |
1089 | } | |
8fe19fc1 | 1090 | |
36bb2ca2 JF |
1091 | - (NSString *) tagline { |
1092 | return tagline_; | |
8fe19fc1 JF |
1093 | } |
1094 | ||
36bb2ca2 JF |
1095 | - (NSString *) icon { |
1096 | return icon_; | |
1097 | } | |
8fe19fc1 | 1098 | |
36bb2ca2 JF |
1099 | - (NSString *) website { |
1100 | return website_; | |
8fe19fc1 JF |
1101 | } |
1102 | ||
2388b078 JF |
1103 | - (NSArray *) relationships { |
1104 | return relationships_; | |
1105 | } | |
1106 | ||
36bb2ca2 | 1107 | - (Source *) source { |
bbb879fb | 1108 | if (!cached_) { |
5a09ae08 | 1109 | source_ = file_.end() ? nil : [[database_ getSource:file_.File()] retain]; |
bbb879fb JF |
1110 | cached_ = true; |
1111 | } | |
1112 | ||
36bb2ca2 | 1113 | return source_; |
8fe19fc1 JF |
1114 | } |
1115 | ||
36bb2ca2 JF |
1116 | - (BOOL) matches:(NSString *)text { |
1117 | if (text == nil) | |
1118 | return NO; | |
8fe19fc1 | 1119 | |
36bb2ca2 | 1120 | NSRange range; |
8fe19fc1 | 1121 | |
36bb2ca2 JF |
1122 | range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch]; |
1123 | if (range.location != NSNotFound) | |
1124 | return YES; | |
8fe19fc1 | 1125 | |
36bb2ca2 JF |
1126 | range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch]; |
1127 | if (range.location != NSNotFound) | |
1128 | return YES; | |
8fe19fc1 | 1129 | |
36bb2ca2 JF |
1130 | range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch]; |
1131 | if (range.location != NSNotFound) | |
1132 | return YES; | |
8fe19fc1 | 1133 | |
36bb2ca2 JF |
1134 | return NO; |
1135 | } | |
8fe19fc1 | 1136 | |
36bb2ca2 JF |
1137 | - (NSComparisonResult) compareByName:(Package *)package { |
1138 | NSString *lhs = [self name]; | |
1139 | NSString *rhs = [package name]; | |
8fe19fc1 | 1140 | |
36bb2ca2 JF |
1141 | if ([lhs length] != 0 && [rhs length] != 0) { |
1142 | unichar lhc = [lhs characterAtIndex:0]; | |
1143 | unichar rhc = [rhs characterAtIndex:0]; | |
1144 | ||
1145 | if (isalpha(lhc) && !isalpha(rhc)) | |
1146 | return NSOrderedAscending; | |
1147 | else if (!isalpha(lhc) && isalpha(rhc)) | |
1148 | return NSOrderedDescending; | |
8fe19fc1 JF |
1149 | } |
1150 | ||
36bb2ca2 | 1151 | return [lhs caseInsensitiveCompare:rhs]; |
8fe19fc1 JF |
1152 | } |
1153 | ||
36bb2ca2 JF |
1154 | - (NSComparisonResult) compareBySection:(Package *)package { |
1155 | NSString *lhs = [self section]; | |
1156 | NSString *rhs = [package section]; | |
3178d79b | 1157 | |
36bb2ca2 JF |
1158 | if (lhs == NULL && rhs != NULL) |
1159 | return NSOrderedAscending; | |
1160 | else if (lhs != NULL && rhs == NULL) | |
1161 | return NSOrderedDescending; | |
1162 | else if (lhs != NULL && rhs != NULL) { | |
a72074b2 | 1163 | NSComparisonResult result = [lhs caseInsensitiveCompare:rhs]; |
36bb2ca2 JF |
1164 | if (result != NSOrderedSame) |
1165 | return result; | |
1166 | } | |
3178d79b | 1167 | |
36bb2ca2 JF |
1168 | return NSOrderedSame; |
1169 | } | |
3178d79b | 1170 | |
36bb2ca2 JF |
1171 | - (NSComparisonResult) compareBySectionAndName:(Package *)package { |
1172 | NSString *lhs = [self section]; | |
1173 | NSString *rhs = [package section]; | |
3178d79b | 1174 | |
36bb2ca2 JF |
1175 | if (lhs == NULL && rhs != NULL) |
1176 | return NSOrderedAscending; | |
1177 | else if (lhs != NULL && rhs == NULL) | |
1178 | return NSOrderedDescending; | |
1179 | else if (lhs != NULL && rhs != NULL) { | |
1180 | NSComparisonResult result = [lhs compare:rhs]; | |
1181 | if (result != NSOrderedSame) | |
1182 | return result; | |
1183 | } | |
3178d79b | 1184 | |
36bb2ca2 JF |
1185 | return [self compareByName:package]; |
1186 | } | |
3178d79b | 1187 | |
36bb2ca2 JF |
1188 | - (NSComparisonResult) compareForChanges:(Package *)package { |
1189 | BOOL lhs = [self upgradable]; | |
1190 | BOOL rhs = [package upgradable]; | |
8fe19fc1 | 1191 | |
36bb2ca2 JF |
1192 | if (lhs != rhs) |
1193 | return lhs ? NSOrderedAscending : NSOrderedDescending; | |
1194 | else if (!lhs) { | |
1195 | switch ([[self seen] compare:[package seen]]) { | |
1196 | case NSOrderedAscending: | |
1197 | return NSOrderedDescending; | |
1198 | case NSOrderedSame: | |
1199 | break; | |
1200 | case NSOrderedDescending: | |
1201 | return NSOrderedAscending; | |
1202 | default: | |
1203 | _assert(false); | |
1204 | } | |
1205 | } | |
8fe19fc1 | 1206 | |
36bb2ca2 JF |
1207 | return [self compareByName:package]; |
1208 | } | |
8fe19fc1 | 1209 | |
36bb2ca2 JF |
1210 | - (void) install { |
1211 | pkgProblemResolver *resolver = [database_ resolver]; | |
1212 | resolver->Clear(iterator_); | |
1213 | resolver->Protect(iterator_); | |
1214 | pkgCacheFile &cache([database_ cache]); | |
1215 | cache->MarkInstall(iterator_, false); | |
1216 | pkgDepCache::StateCache &state((*cache)[iterator_]); | |
1217 | if (!state.Install()) | |
1218 | cache->SetReInstall(iterator_, true); | |
1219 | } | |
68a238ec | 1220 | |
36bb2ca2 JF |
1221 | - (void) remove { |
1222 | pkgProblemResolver *resolver = [database_ resolver]; | |
1223 | resolver->Clear(iterator_); | |
1224 | resolver->Protect(iterator_); | |
1225 | resolver->Remove(iterator_); | |
1226 | [database_ cache]->MarkDelete(iterator_, true); | |
1227 | } | |
8fe19fc1 | 1228 | |
36bb2ca2 | 1229 | - (NSNumber *) isSearchedForBy:(NSString *)search { |
5a09ae08 | 1230 | return [NSNumber numberWithBool:([self valid] && [self matches:search])]; |
36bb2ca2 | 1231 | } |
8fe19fc1 | 1232 | |
36bb2ca2 JF |
1233 | - (NSNumber *) isInstalledInSection:(NSString *)section { |
1234 | return [NSNumber numberWithBool:([self installed] != nil && (section == nil || [section isEqualToString:[self section]]))]; | |
1235 | } | |
8fe19fc1 | 1236 | |
5a09ae08 JF |
1237 | - (NSNumber *) isUninstalledInSection:(NSString *)name { |
1238 | NSString *section = [self section]; | |
1239 | ||
1240 | return [NSNumber numberWithBool:([self valid] && [self installed] == nil && ( | |
1241 | (name == nil || | |
1242 | section == nil && [name length] == 0 || | |
1243 | [name isEqualToString:section]) | |
1244 | ))]; | |
36bb2ca2 | 1245 | } |
8fe19fc1 | 1246 | |
36bb2ca2 JF |
1247 | @end |
1248 | /* }}} */ | |
1249 | /* Section Class {{{ */ | |
1250 | @interface Section : NSObject { | |
1251 | NSString *name_; | |
1252 | size_t row_; | |
1253 | size_t count_; | |
1254 | } | |
3178d79b | 1255 | |
36bb2ca2 JF |
1256 | - (Section *) initWithName:(NSString *)name row:(size_t)row; |
1257 | - (NSString *) name; | |
1258 | - (size_t) row; | |
1259 | - (size_t) count; | |
1260 | - (void) addToCount; | |
b19871dd | 1261 | |
36bb2ca2 | 1262 | @end |
b19871dd | 1263 | |
36bb2ca2 | 1264 | @implementation Section |
b19871dd | 1265 | |
36bb2ca2 JF |
1266 | - (void) dealloc { |
1267 | [name_ release]; | |
1268 | [super dealloc]; | |
1269 | } | |
b19871dd | 1270 | |
36bb2ca2 JF |
1271 | - (Section *) initWithName:(NSString *)name row:(size_t)row { |
1272 | if ((self = [super init]) != nil) { | |
1273 | name_ = [name retain]; | |
1274 | row_ = row; | |
b19871dd JF |
1275 | } return self; |
1276 | } | |
1277 | ||
36bb2ca2 JF |
1278 | - (NSString *) name { |
1279 | return name_; | |
1280 | } | |
1281 | ||
1282 | - (size_t) row { | |
1283 | return row_; | |
1284 | } | |
1285 | ||
1286 | - (size_t) count { | |
1287 | return count_; | |
1288 | } | |
1289 | ||
1290 | - (void) addToCount { | |
1291 | ++count_; | |
1292 | } | |
1293 | ||
b19871dd JF |
1294 | @end |
1295 | /* }}} */ | |
1296 | ||
36bb2ca2 JF |
1297 | /* Database Implementation {{{ */ |
1298 | @implementation Database | |
ec97ef06 | 1299 | |
36bb2ca2 JF |
1300 | - (void) dealloc { |
1301 | _assert(false); | |
1302 | [super dealloc]; | |
1303 | } | |
ec97ef06 | 1304 | |
36bb2ca2 JF |
1305 | - (void) _readStatus:(NSNumber *)fd { |
1306 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
c7c6384e | 1307 | |
36bb2ca2 JF |
1308 | __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in); |
1309 | std::istream is(&ib); | |
1310 | std::string line; | |
ec97ef06 | 1311 | |
5a09ae08 JF |
1312 | Pcre conffile_r("^status: [^ ]* : conffile-prompt : (.*?) *$"); |
1313 | Pcre pmstatus_r("^([^:]*):([^:]*):([^:]*):(.*)$"); | |
ec97ef06 | 1314 | |
36bb2ca2 JF |
1315 | while (std::getline(is, line)) { |
1316 | const char *data(line.c_str()); | |
5a09ae08 | 1317 | size_t size = line.size(); |
8b29f8e6 | 1318 | fprintf(stderr, "%s\n", data); |
ec97ef06 | 1319 | |
5a09ae08 JF |
1320 | if (conffile_r(data, size)) { |
1321 | [delegate_ setConfigurationData:conffile_r[1]]; | |
1322 | } else if (strncmp(data, "status: ", 8) == 0) { | |
1323 | NSString *string = [NSString stringWithUTF8String:(data + 8)]; | |
36bb2ca2 | 1324 | [delegate_ setProgressTitle:string]; |
5a09ae08 JF |
1325 | } else if (pmstatus_r(data, size)) { |
1326 | float percent([pmstatus_r[3] floatValue]); | |
1327 | [delegate_ setProgressPercent:(percent / 100)]; | |
1328 | ||
1329 | NSString *string = pmstatus_r[4]; | |
1330 | std::string type([pmstatus_r[1] UTF8String]); | |
1331 | ||
1332 | if (type == "pmerror") | |
1333 | [delegate_ setProgressError:string]; | |
1334 | else if (type == "pmstatus") | |
1335 | [delegate_ setProgressTitle:string]; | |
1336 | else if (type == "pmconffile") | |
1337 | [delegate_ setConfigurationData:string]; | |
1338 | else _assert(false); | |
1339 | } else _assert(false); | |
36bb2ca2 | 1340 | } |
ec97ef06 | 1341 | |
36bb2ca2 JF |
1342 | [pool release]; |
1343 | _assert(false); | |
1344 | } | |
ec97ef06 | 1345 | |
36bb2ca2 JF |
1346 | - (void) _readOutput:(NSNumber *)fd { |
1347 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
ec97ef06 | 1348 | |
36bb2ca2 JF |
1349 | __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in); |
1350 | std::istream is(&ib); | |
1351 | std::string line; | |
1352 | ||
5a09ae08 JF |
1353 | while (std::getline(is, line)) { |
1354 | fprintf(stderr, "%s\n", line.c_str()); | |
2388b078 | 1355 | [delegate_ addProgressOutput:[NSString stringWithUTF8String:line.c_str()]]; |
5a09ae08 | 1356 | } |
36bb2ca2 JF |
1357 | |
1358 | [pool release]; | |
1359 | _assert(false); | |
ec97ef06 JF |
1360 | } |
1361 | ||
8b29f8e6 JF |
1362 | - (FILE *) input { |
1363 | return input_; | |
1364 | } | |
1365 | ||
36bb2ca2 | 1366 | - (Package *) packageWithName:(NSString *)name { |
5a09ae08 JF |
1367 | if (static_cast<pkgDepCache *>(cache_) == NULL) |
1368 | return nil; | |
36bb2ca2 JF |
1369 | pkgCache::PkgIterator iterator(cache_->FindPkg([name UTF8String])); |
1370 | return iterator.end() ? nil : [Package packageWithIterator:iterator database:self]; | |
1371 | } | |
1372 | ||
1373 | - (Database *) init { | |
ec97ef06 | 1374 | if ((self = [super init]) != nil) { |
5a09ae08 | 1375 | policy_ = NULL; |
36bb2ca2 JF |
1376 | records_ = NULL; |
1377 | resolver_ = NULL; | |
1378 | fetcher_ = NULL; | |
1379 | lock_ = NULL; | |
ec97ef06 | 1380 | |
36bb2ca2 JF |
1381 | sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain]; |
1382 | packages_ = [[NSMutableArray arrayWithCapacity:16] retain]; | |
ec97ef06 | 1383 | |
36bb2ca2 | 1384 | int fds[2]; |
ec97ef06 | 1385 | |
36bb2ca2 JF |
1386 | _assert(pipe(fds) != -1); |
1387 | statusfd_ = fds[1]; | |
ec97ef06 | 1388 | |
36bb2ca2 JF |
1389 | [NSThread |
1390 | detachNewThreadSelector:@selector(_readStatus:) | |
1391 | toTarget:self | |
1392 | withObject:[[NSNumber numberWithInt:fds[0]] retain] | |
1393 | ]; | |
ec97ef06 | 1394 | |
8b29f8e6 JF |
1395 | _assert(pipe(fds) != -1); |
1396 | _assert(dup2(fds[0], 0) != -1); | |
1397 | _assert(close(fds[0]) != -1); | |
1398 | ||
1399 | input_ = fdopen(fds[1], "a"); | |
1400 | ||
36bb2ca2 JF |
1401 | _assert(pipe(fds) != -1); |
1402 | _assert(dup2(fds[1], 1) != -1); | |
1403 | _assert(close(fds[1]) != -1); | |
1404 | ||
1405 | [NSThread | |
1406 | detachNewThreadSelector:@selector(_readOutput:) | |
1407 | toTarget:self | |
1408 | withObject:[[NSNumber numberWithInt:fds[0]] retain] | |
1409 | ]; | |
ec97ef06 JF |
1410 | } return self; |
1411 | } | |
1412 | ||
36bb2ca2 JF |
1413 | - (pkgCacheFile &) cache { |
1414 | return cache_; | |
ec97ef06 JF |
1415 | } |
1416 | ||
5a09ae08 JF |
1417 | - (pkgDepCache::Policy *) policy { |
1418 | return policy_; | |
1419 | } | |
1420 | ||
36bb2ca2 JF |
1421 | - (pkgRecords *) records { |
1422 | return records_; | |
ec97ef06 JF |
1423 | } |
1424 | ||
36bb2ca2 JF |
1425 | - (pkgProblemResolver *) resolver { |
1426 | return resolver_; | |
ec97ef06 JF |
1427 | } |
1428 | ||
36bb2ca2 JF |
1429 | - (pkgAcquire &) fetcher { |
1430 | return *fetcher_; | |
ec97ef06 JF |
1431 | } |
1432 | ||
36bb2ca2 JF |
1433 | - (NSArray *) packages { |
1434 | return packages_; | |
ec97ef06 JF |
1435 | } |
1436 | ||
36bb2ca2 JF |
1437 | - (void) reloadData { |
1438 | _error->Discard(); | |
5a09ae08 | 1439 | |
36bb2ca2 | 1440 | delete list_; |
5a09ae08 | 1441 | list_ = NULL; |
36bb2ca2 JF |
1442 | manager_ = NULL; |
1443 | delete lock_; | |
5a09ae08 | 1444 | lock_ = NULL; |
36bb2ca2 | 1445 | delete fetcher_; |
5a09ae08 | 1446 | fetcher_ = NULL; |
36bb2ca2 | 1447 | delete resolver_; |
5a09ae08 | 1448 | resolver_ = NULL; |
36bb2ca2 | 1449 | delete records_; |
5a09ae08 JF |
1450 | records_ = NULL; |
1451 | delete policy_; | |
1452 | policy_ = NULL; | |
36bb2ca2 | 1453 | |
5a09ae08 | 1454 | cache_.Close(); |
8b29f8e6 | 1455 | |
5a09ae08 | 1456 | if (!cache_.Open(progress_, true)) { |
8b29f8e6 JF |
1457 | std::string error; |
1458 | if (!_error->PopMessage(error)) | |
1459 | _assert(false); | |
5a09ae08 JF |
1460 | _error->Discard(); |
1461 | fprintf(stderr, "cache_.Open():[%s]\n", error.c_str()); | |
1462 | ||
1463 | if (error == "dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem. ") | |
1464 | [delegate_ repairWithSelector:@selector(configure)]; | |
1465 | else if (error == "The package lists or status file could not be parsed or opened.") | |
1466 | [delegate_ repairWithSelector:@selector(update)]; | |
9ea8d159 JF |
1467 | // else if (error == "Could not open lock file /var/lib/dpkg/lock - open (13 Permission denied)") |
1468 | // else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)") | |
1469 | // else if (error == "The list of sources could not be read.") | |
5a09ae08 JF |
1470 | else _assert(false); |
1471 | ||
1472 | return; | |
36bb2ca2 JF |
1473 | } |
1474 | ||
1475 | now_ = [[NSDate date] retain]; | |
1476 | ||
5a09ae08 | 1477 | policy_ = new pkgDepCache::Policy(); |
36bb2ca2 JF |
1478 | records_ = new pkgRecords(cache_); |
1479 | resolver_ = new pkgProblemResolver(cache_); | |
1480 | fetcher_ = new pkgAcquire(&status_); | |
1481 | lock_ = NULL; | |
1482 | ||
1483 | list_ = new pkgSourceList(); | |
1484 | _assert(list_->ReadMainList()); | |
1485 | ||
1486 | [sources_ removeAllObjects]; | |
1487 | for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) { | |
1488 | std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles(); | |
1489 | for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index) | |
1490 | [sources_ | |
1491 | setObject:[[[Source alloc] initWithMetaIndex:*source] autorelease] | |
1492 | forKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(*index)] | |
1493 | ]; | |
1494 | } | |
1495 | ||
1496 | [packages_ removeAllObjects]; | |
1497 | for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator) | |
5a09ae08 JF |
1498 | if (Package *package = [Package packageWithIterator:iterator database:self]) |
1499 | [packages_ addObject:package]; | |
ab398adf JF |
1500 | |
1501 | [packages_ sortUsingSelector:@selector(compareByName:)]; | |
ec97ef06 JF |
1502 | } |
1503 | ||
5a09ae08 JF |
1504 | - (void) configure { |
1505 | NSString *dpkg = [NSString stringWithFormat:@"dpkg --configure -a --status-fd %u", statusfd_]; | |
1506 | system([dpkg UTF8String]); | |
1507 | } | |
1508 | ||
36bb2ca2 JF |
1509 | - (void) prepare { |
1510 | pkgRecords records(cache_); | |
1511 | ||
1512 | lock_ = new FileFd(); | |
1513 | lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock")); | |
1514 | _assert(!_error->PendingError()); | |
1515 | ||
1516 | pkgSourceList list; | |
1517 | // XXX: explain this with an error message | |
1518 | _assert(list.ReadMainList()); | |
1519 | ||
1520 | manager_ = (_system->CreatePM(cache_)); | |
1521 | _assert(manager_->GetArchives(fetcher_, &list, &records)); | |
1522 | _assert(!_error->PendingError()); | |
ec97ef06 JF |
1523 | } |
1524 | ||
36bb2ca2 | 1525 | - (void) perform { |
a72074b2 JF |
1526 | NSMutableArray *before = [NSMutableArray arrayWithCapacity:16]; { |
1527 | pkgSourceList list; | |
1528 | _assert(list.ReadMainList()); | |
1529 | for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source) | |
1530 | [before addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]]; | |
1531 | } | |
a0be02eb | 1532 | |
36bb2ca2 JF |
1533 | if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue) |
1534 | return; | |
1535 | ||
1536 | _system->UnLock(); | |
1537 | pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_); | |
1538 | ||
1539 | if (result == pkgPackageManager::Failed) | |
1540 | return; | |
1541 | if (_error->PendingError()) | |
1542 | return; | |
1543 | if (result != pkgPackageManager::Completed) | |
1544 | return; | |
a0be02eb | 1545 | |
a72074b2 JF |
1546 | NSMutableArray *after = [NSMutableArray arrayWithCapacity:16]; { |
1547 | pkgSourceList list; | |
1548 | _assert(list.ReadMainList()); | |
1549 | for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source) | |
1550 | [after addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]]; | |
1551 | } | |
1552 | ||
1553 | if (![before isEqualToArray:after]) | |
1554 | [self update]; | |
ec97ef06 JF |
1555 | } |
1556 | ||
36bb2ca2 JF |
1557 | - (void) upgrade { |
1558 | _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0); | |
1559 | _assert(pkgApplyStatus(cache_)); | |
1560 | ||
1561 | if (cache_->BrokenCount() != 0) { | |
1562 | _assert(pkgFixBroken(cache_)); | |
1563 | _assert(cache_->BrokenCount() == 0); | |
1564 | _assert(pkgMinimizeUpgrade(cache_)); | |
1565 | } | |
1566 | ||
1567 | _assert(pkgDistUpgrade(cache_)); | |
c7c6384e JF |
1568 | } |
1569 | ||
36bb2ca2 JF |
1570 | - (void) update { |
1571 | [self updateWithStatus:status_]; | |
1572 | } | |
b4d89997 | 1573 | |
36bb2ca2 JF |
1574 | - (void) updateWithStatus:(Status &)status { |
1575 | pkgSourceList list; | |
1576 | _assert(list.ReadMainList()); | |
b4d89997 | 1577 | |
36bb2ca2 JF |
1578 | FileFd lock; |
1579 | lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock")); | |
1580 | _assert(!_error->PendingError()); | |
1581 | ||
1582 | pkgAcquire fetcher(&status); | |
1583 | _assert(list.GetIndexes(&fetcher)); | |
1584 | ||
1585 | if (fetcher.Run(PulseInterval_) != pkgAcquire::Failed) { | |
1586 | bool failed = false; | |
1587 | for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++) | |
1588 | if ((*item)->Status != pkgAcquire::Item::StatDone) { | |
1589 | (*item)->Finished(); | |
1590 | failed = true; | |
1591 | } | |
1592 | ||
1593 | if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) { | |
1594 | _assert(fetcher.Clean(_config->FindDir("Dir::State::lists"))); | |
1595 | _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/")); | |
b4d89997 | 1596 | } |
36bb2ca2 JF |
1597 | |
1598 | [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"]; | |
bbb879fb | 1599 | Changed_ = true; |
b4d89997 JF |
1600 | } |
1601 | } | |
1602 | ||
36bb2ca2 JF |
1603 | - (void) setDelegate:(id)delegate { |
1604 | delegate_ = delegate; | |
1605 | status_.setDelegate(delegate); | |
1606 | progress_.setDelegate(delegate); | |
1607 | } | |
b4d89997 | 1608 | |
36bb2ca2 JF |
1609 | - (Source *) getSource:(const pkgCache::PkgFileIterator &)file { |
1610 | pkgIndexFile *index(NULL); | |
1611 | list_->FindIndex(file, index); | |
1612 | return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(index)]]; | |
b19871dd JF |
1613 | } |
1614 | ||
36bb2ca2 JF |
1615 | @end |
1616 | /* }}} */ | |
b4d89997 | 1617 | |
36bb2ca2 JF |
1618 | /* Confirmation View {{{ */ |
1619 | void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) { | |
1620 | if ([packages count] == 0) | |
1621 | return; | |
b4d89997 | 1622 | |
36bb2ca2 JF |
1623 | UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 120, false); |
1624 | [fields setObject:text forKey:key]; | |
1625 | ||
1626 | CGColor blue(space_, 0, 0, 0.4, 1); | |
1627 | [text setTextColor:blue]; | |
dc5812ec JF |
1628 | } |
1629 | ||
36bb2ca2 JF |
1630 | @protocol ConfirmationViewDelegate |
1631 | - (void) cancel; | |
1632 | - (void) confirm; | |
1633 | @end | |
2367a917 | 1634 | |
36bb2ca2 JF |
1635 | @interface ConfirmationView : UIView { |
1636 | Database *database_; | |
1637 | id delegate_; | |
1638 | UITransitionView *transition_; | |
1639 | UIView *overlay_; | |
1640 | UINavigationBar *navbar_; | |
1641 | UIPreferencesTable *table_; | |
1642 | NSMutableDictionary *fields_; | |
1643 | UIAlertSheet *essential_; | |
1644 | } | |
dc5812ec | 1645 | |
36bb2ca2 | 1646 | - (void) cancel; |
8da60fb7 | 1647 | |
36bb2ca2 | 1648 | - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate; |
b4d89997 | 1649 | |
dc5812ec JF |
1650 | @end |
1651 | ||
36bb2ca2 | 1652 | @implementation ConfirmationView |
dc5812ec | 1653 | |
2367a917 | 1654 | - (void) dealloc { |
36bb2ca2 JF |
1655 | [navbar_ setDelegate:nil]; |
1656 | [transition_ setDelegate:nil]; | |
1657 | [table_ setDataSource:nil]; | |
1658 | ||
1659 | [transition_ release]; | |
1660 | [overlay_ release]; | |
1661 | [navbar_ release]; | |
8da60fb7 | 1662 | [table_ release]; |
36bb2ca2 JF |
1663 | [fields_ release]; |
1664 | if (essential_ != nil) | |
1665 | [essential_ release]; | |
2367a917 JF |
1666 | [super dealloc]; |
1667 | } | |
1668 | ||
36bb2ca2 JF |
1669 | - (void) cancel { |
1670 | [transition_ transition:7 toView:nil]; | |
1671 | [delegate_ cancel]; | |
1672 | } | |
1673 | ||
1674 | - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to { | |
1675 | if (from != nil && to == nil) | |
1676 | [self removeFromSuperview]; | |
1677 | } | |
1678 | ||
1679 | - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button { | |
1680 | switch (button) { | |
1681 | case 0: | |
1682 | if (essential_ != nil) | |
1683 | [essential_ popupAlertAnimated:YES]; | |
1684 | else | |
1685 | [delegate_ confirm]; | |
1686 | break; | |
1687 | ||
1688 | case 1: | |
1689 | [self cancel]; | |
1690 | break; | |
1691 | } | |
1692 | } | |
1693 | ||
1694 | - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button { | |
1695 | [essential_ dismiss]; | |
1696 | [self cancel]; | |
1697 | } | |
1698 | ||
dc5812ec | 1699 | - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table { |
36bb2ca2 | 1700 | return 2; |
dc5812ec JF |
1701 | } |
1702 | ||
1703 | - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group { | |
1704 | switch (group) { | |
36bb2ca2 JF |
1705 | case 0: return @"Statistics"; |
1706 | case 1: return @"Modifications"; | |
dc5812ec JF |
1707 | |
1708 | default: _assert(false); | |
1709 | } | |
1710 | } | |
1711 | ||
1712 | - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group { | |
1713 | switch (group) { | |
36bb2ca2 JF |
1714 | case 0: return 3; |
1715 | case 1: return [fields_ count]; | |
dc5812ec JF |
1716 | |
1717 | default: _assert(false); | |
1718 | } | |
1719 | } | |
1720 | ||
36bb2ca2 JF |
1721 | - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed { |
1722 | if (group != 1 || row == -1) | |
1723 | return proposed; | |
1724 | else { | |
1725 | _assert(size_t(row) < [fields_ count]); | |
1726 | return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_; | |
1727 | } | |
1728 | } | |
1729 | ||
dc5812ec | 1730 | - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group { |
b4d89997 JF |
1731 | UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease]; |
1732 | [cell setShowSelection:NO]; | |
dc5812ec JF |
1733 | |
1734 | switch (group) { | |
1735 | case 0: switch (row) { | |
36bb2ca2 JF |
1736 | case 0: { |
1737 | [cell setTitle:@"Downloading"]; | |
1738 | [cell setValue:SizeString([database_ fetcher].FetchNeeded())]; | |
1739 | } break; | |
1740 | ||
1741 | case 1: { | |
1742 | [cell setTitle:@"Resuming At"]; | |
1743 | [cell setValue:SizeString([database_ fetcher].PartialPresent())]; | |
1744 | } break; | |
1745 | ||
1746 | case 2: { | |
1747 | double size([database_ cache]->UsrSize()); | |
1748 | ||
1749 | if (size < 0) { | |
1750 | [cell setTitle:@"Disk Freeing"]; | |
1751 | [cell setValue:SizeString(-size)]; | |
1752 | } else { | |
1753 | [cell setTitle:@"Disk Using"]; | |
1754 | [cell setValue:SizeString(size)]; | |
1755 | } | |
1756 | } break; | |
1757 | ||
1758 | default: _assert(false); | |
1759 | } break; | |
1760 | ||
1761 | case 1: | |
1762 | _assert(size_t(row) < [fields_ count]); | |
1763 | [cell setTitle:[[fields_ allKeys] objectAtIndex:row]]; | |
1764 | [cell addSubview:[[fields_ allValues] objectAtIndex:row]]; | |
1765 | break; | |
1766 | ||
1767 | default: _assert(false); | |
1768 | } | |
1769 | ||
1770 | return cell; | |
1771 | } | |
1772 | ||
1773 | - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate { | |
1774 | if ((self = [super initWithFrame:[view bounds]]) != nil) { | |
1775 | database_ = database; | |
1776 | delegate_ = delegate; | |
b4d89997 | 1777 | |
36bb2ca2 JF |
1778 | transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]]; |
1779 | [self addSubview:transition_]; | |
b4d89997 | 1780 | |
36bb2ca2 | 1781 | overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]]; |
06aa974d | 1782 | |
36bb2ca2 JF |
1783 | CGSize navsize = [UINavigationBar defaultSize]; |
1784 | CGRect navrect = {{0, 0}, navsize}; | |
1785 | CGRect bounds = [overlay_ bounds]; | |
b4d89997 | 1786 | |
36bb2ca2 | 1787 | navbar_ = [[UINavigationBar alloc] initWithFrame:navrect]; |
9ea8d159 JF |
1788 | if (Advanced_) |
1789 | [navbar_ setBarStyle:1]; | |
36bb2ca2 | 1790 | [navbar_ setDelegate:self]; |
dc5812ec | 1791 | |
36bb2ca2 JF |
1792 | UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease]; |
1793 | [navbar_ pushNavigationItem:navitem]; | |
1794 | [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"]; | |
dc5812ec | 1795 | |
36bb2ca2 | 1796 | fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain]; |
dc5812ec | 1797 | |
36bb2ca2 JF |
1798 | NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16]; |
1799 | NSMutableArray *reinstalling = [NSMutableArray arrayWithCapacity:16]; | |
1800 | NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16]; | |
1801 | NSMutableArray *downgrading = [NSMutableArray arrayWithCapacity:16]; | |
1802 | NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16]; | |
dc5812ec | 1803 | |
36bb2ca2 | 1804 | bool remove(false); |
dc5812ec | 1805 | |
36bb2ca2 | 1806 | pkgCacheFile &cache([database_ cache]); |
2388b078 JF |
1807 | NSArray *packages = [database_ packages]; |
1808 | for (size_t i(0), e = [packages count]; i != e; ++i) { | |
1809 | Package *package = [packages objectAtIndex:i]; | |
1810 | pkgCache::PkgIterator iterator = [package iterator]; | |
36bb2ca2 | 1811 | pkgDepCache::StateCache &state(cache[iterator]); |
dc5812ec | 1812 | |
2388b078 JF |
1813 | NSString *name([package name]); |
1814 | ||
36bb2ca2 JF |
1815 | if (state.NewInstall()) |
1816 | [installing addObject:name]; | |
1817 | else if (!state.Delete() && (state.iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall) | |
1818 | [reinstalling addObject:name]; | |
1819 | else if (state.Upgrade()) | |
1820 | [upgrading addObject:name]; | |
1821 | else if (state.Downgrade()) | |
1822 | [downgrading addObject:name]; | |
1823 | else if (state.Delete()) { | |
2388b078 | 1824 | if ([package essential]) |
36bb2ca2 JF |
1825 | remove = true; |
1826 | [removing addObject:name]; | |
1827 | } | |
1828 | } | |
ec97ef06 | 1829 | |
36bb2ca2 JF |
1830 | if (!remove) |
1831 | essential_ = nil; | |
1832 | else { | |
1833 | essential_ = [[UIAlertSheet alloc] | |
1834 | initWithTitle:@"Unable to Comply" | |
1835 | buttons:[NSArray arrayWithObjects:@"Okay", nil] | |
1836 | defaultButtonIndex:0 | |
1837 | delegate:self | |
a54b1c10 | 1838 | context:@"remove" |
36bb2ca2 | 1839 | ]; |
ec97ef06 | 1840 | |
36bb2ca2 JF |
1841 | [essential_ setBodyText:@"One or more of the packages you are about to remove are marked 'Essential' and cannot be removed by Cydia. Please use apt-get."]; |
1842 | } | |
ec97ef06 | 1843 | |
36bb2ca2 JF |
1844 | AddTextView(fields_, installing, @"Installing"); |
1845 | AddTextView(fields_, reinstalling, @"Reinstalling"); | |
1846 | AddTextView(fields_, upgrading, @"Upgrading"); | |
1847 | AddTextView(fields_, downgrading, @"Downgrading"); | |
1848 | AddTextView(fields_, removing, @"Removing"); | |
dc5812ec | 1849 | |
36bb2ca2 JF |
1850 | table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake( |
1851 | 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height | |
1852 | )]; | |
dc5812ec | 1853 | |
36bb2ca2 JF |
1854 | [table_ setReusesTableCells:YES]; |
1855 | [table_ setDataSource:self]; | |
1856 | [table_ reloadData]; | |
dc5812ec | 1857 | |
36bb2ca2 JF |
1858 | [overlay_ addSubview:navbar_]; |
1859 | [overlay_ addSubview:table_]; | |
8da60fb7 | 1860 | |
36bb2ca2 | 1861 | [view addSubview:self]; |
99364ec4 | 1862 | |
36bb2ca2 | 1863 | [transition_ setDelegate:self]; |
8da60fb7 | 1864 | |
36bb2ca2 JF |
1865 | UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease]; |
1866 | [transition_ transition:0 toView:blank]; | |
1867 | [transition_ transition:3 toView:overlay_]; | |
1868 | } return self; | |
b4d89997 | 1869 | } |
8da60fb7 | 1870 | |
36bb2ca2 JF |
1871 | @end |
1872 | /* }}} */ | |
8da60fb7 | 1873 | |
36bb2ca2 JF |
1874 | /* Progress Data {{{ */ |
1875 | @interface ProgressData : NSObject { | |
1876 | SEL selector_; | |
1877 | id target_; | |
1878 | id object_; | |
dc5812ec JF |
1879 | } |
1880 | ||
36bb2ca2 | 1881 | - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object; |
b4d89997 | 1882 | |
36bb2ca2 JF |
1883 | - (SEL) selector; |
1884 | - (id) target; | |
1885 | - (id) object; | |
1886 | @end | |
b4d89997 | 1887 | |
36bb2ca2 | 1888 | @implementation ProgressData |
b4d89997 | 1889 | |
36bb2ca2 JF |
1890 | - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object { |
1891 | if ((self = [super init]) != nil) { | |
1892 | selector_ = selector; | |
1893 | target_ = target; | |
1894 | object_ = object; | |
1895 | } return self; | |
1896 | } | |
b4d89997 | 1897 | |
36bb2ca2 JF |
1898 | - (SEL) selector { |
1899 | return selector_; | |
1900 | } | |
b4d89997 | 1901 | |
36bb2ca2 JF |
1902 | - (id) target { |
1903 | return target_; | |
8da60fb7 JF |
1904 | } |
1905 | ||
36bb2ca2 JF |
1906 | - (id) object { |
1907 | return object_; | |
dc5812ec JF |
1908 | } |
1909 | ||
2367a917 JF |
1910 | @end |
1911 | /* }}} */ | |
36bb2ca2 | 1912 | /* Progress View {{{ */ |
8b29f8e6 JF |
1913 | Pcre conffile_r("^'(.*)' '(.*)' ([01]) ([01])$"); |
1914 | ||
36bb2ca2 | 1915 | @interface ProgressView : UIView < |
8b29f8e6 | 1916 | ConfigurationDelegate, |
36bb2ca2 JF |
1917 | ProgressDelegate |
1918 | > { | |
8b29f8e6 | 1919 | _transient Database *database_; |
36bb2ca2 JF |
1920 | UIView *view_; |
1921 | UIView *background_; | |
1922 | UITransitionView *transition_; | |
1923 | UIView *overlay_; | |
1924 | UINavigationBar *navbar_; | |
1925 | UIProgressBar *progress_; | |
1926 | UITextView *output_; | |
1927 | UITextLabel *status_; | |
1928 | id delegate_; | |
2367a917 JF |
1929 | } |
1930 | ||
36bb2ca2 | 1931 | - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to; |
2367a917 | 1932 | |
8b29f8e6 | 1933 | - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate; |
36bb2ca2 JF |
1934 | - (void) setContentView:(UIView *)view; |
1935 | - (void) resetView; | |
2367a917 | 1936 | |
36bb2ca2 JF |
1937 | - (void) _retachThread; |
1938 | - (void) _detachNewThreadData:(ProgressData *)data; | |
1939 | - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title; | |
2367a917 JF |
1940 | |
1941 | @end | |
1942 | ||
36bb2ca2 JF |
1943 | @protocol ProgressViewDelegate |
1944 | - (void) progressViewIsComplete:(ProgressView *)sender; | |
1945 | @end | |
1946 | ||
1947 | @implementation ProgressView | |
2367a917 JF |
1948 | |
1949 | - (void) dealloc { | |
36bb2ca2 JF |
1950 | [transition_ setDelegate:nil]; |
1951 | [navbar_ setDelegate:nil]; | |
1952 | ||
1953 | [view_ release]; | |
1954 | if (background_ != nil) | |
1955 | [background_ release]; | |
1956 | [transition_ release]; | |
1957 | [overlay_ release]; | |
1958 | [navbar_ release]; | |
1959 | [progress_ release]; | |
1960 | [output_ release]; | |
1961 | [status_ release]; | |
2367a917 JF |
1962 | [super dealloc]; |
1963 | } | |
1964 | ||
36bb2ca2 JF |
1965 | - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to { |
1966 | if (bootstrap_ && from == overlay_ && to == view_) | |
1967 | exit(0); | |
1968 | } | |
2367a917 | 1969 | |
8b29f8e6 | 1970 | - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate { |
36bb2ca2 | 1971 | if ((self = [super initWithFrame:frame]) != nil) { |
8b29f8e6 | 1972 | database_ = database; |
36bb2ca2 | 1973 | delegate_ = delegate; |
ec97ef06 | 1974 | |
36bb2ca2 JF |
1975 | transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]]; |
1976 | [transition_ setDelegate:self]; | |
2367a917 | 1977 | |
36bb2ca2 | 1978 | overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]]; |
ec97ef06 | 1979 | |
36bb2ca2 JF |
1980 | if (bootstrap_) |
1981 | [overlay_ setBackgroundColor:Black_]; | |
1982 | else { | |
1983 | background_ = [[UIView alloc] initWithFrame:[self bounds]]; | |
1984 | [background_ setBackgroundColor:Black_]; | |
1985 | [self addSubview:background_]; | |
1986 | } | |
ec97ef06 | 1987 | |
36bb2ca2 | 1988 | [self addSubview:transition_]; |
2367a917 | 1989 | |
36bb2ca2 JF |
1990 | CGSize navsize = [UINavigationBar defaultSize]; |
1991 | CGRect navrect = {{0, 0}, navsize}; | |
2367a917 | 1992 | |
36bb2ca2 JF |
1993 | navbar_ = [[UINavigationBar alloc] initWithFrame:navrect]; |
1994 | [overlay_ addSubview:navbar_]; | |
b4d89997 | 1995 | |
36bb2ca2 JF |
1996 | [navbar_ setBarStyle:1]; |
1997 | [navbar_ setDelegate:self]; | |
2367a917 | 1998 | |
36bb2ca2 JF |
1999 | UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease]; |
2000 | [navbar_ pushNavigationItem:navitem]; | |
c7c6384e | 2001 | |
36bb2ca2 JF |
2002 | CGRect bounds = [overlay_ bounds]; |
2003 | CGSize prgsize = [UIProgressBar defaultSize]; | |
ec97ef06 | 2004 | |
36bb2ca2 JF |
2005 | CGRect prgrect = {{ |
2006 | (bounds.size.width - prgsize.width) / 2, | |
2007 | bounds.size.height - prgsize.height - 20 | |
2008 | }, prgsize}; | |
ec97ef06 | 2009 | |
36bb2ca2 JF |
2010 | progress_ = [[UIProgressBar alloc] initWithFrame:prgrect]; |
2011 | [overlay_ addSubview:progress_]; | |
ec97ef06 | 2012 | |
36bb2ca2 JF |
2013 | status_ = [[UITextLabel alloc] initWithFrame:CGRectMake( |
2014 | 10, | |
2015 | bounds.size.height - prgsize.height - 50, | |
2016 | bounds.size.width - 20, | |
2017 | 24 | |
2018 | )]; | |
ec97ef06 | 2019 | |
36bb2ca2 JF |
2020 | [status_ setColor:White_]; |
2021 | [status_ setBackgroundColor:Clear_]; | |
ec97ef06 | 2022 | |
36bb2ca2 JF |
2023 | [status_ setCentersHorizontally:YES]; |
2024 | //[status_ setFont:font]; | |
ec97ef06 | 2025 | |
36bb2ca2 JF |
2026 | output_ = [[UITextView alloc] initWithFrame:CGRectMake( |
2027 | 10, | |
2028 | navrect.size.height + 20, | |
2029 | bounds.size.width - 20, | |
2030 | bounds.size.height - navsize.height - 62 - navrect.size.height | |
2031 | )]; | |
1d80f6b9 | 2032 | |
36bb2ca2 JF |
2033 | //[output_ setTextFont:@"Courier New"]; |
2034 | [output_ setTextSize:12]; | |
2367a917 | 2035 | |
36bb2ca2 JF |
2036 | [output_ setTextColor:White_]; |
2037 | [output_ setBackgroundColor:Clear_]; | |
2367a917 | 2038 | |
36bb2ca2 JF |
2039 | [output_ setMarginTop:0]; |
2040 | [output_ setAllowsRubberBanding:YES]; | |
b4d89997 | 2041 | |
36bb2ca2 JF |
2042 | [overlay_ addSubview:output_]; |
2043 | [overlay_ addSubview:status_]; | |
2367a917 | 2044 | |
36bb2ca2 JF |
2045 | [progress_ setStyle:0]; |
2046 | } return self; | |
2367a917 JF |
2047 | } |
2048 | ||
36bb2ca2 JF |
2049 | - (void) setContentView:(UIView *)view { |
2050 | view_ = [view retain]; | |
2367a917 JF |
2051 | } |
2052 | ||
36bb2ca2 JF |
2053 | - (void) resetView { |
2054 | [transition_ transition:6 toView:view_]; | |
2367a917 JF |
2055 | } |
2056 | ||
36bb2ca2 | 2057 | - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button { |
8b29f8e6 JF |
2058 | NSString *context = [sheet context]; |
2059 | if ([context isEqualToString:@"conffile"]) { | |
2060 | FILE *input = [database_ input]; | |
2061 | ||
2062 | switch (button) { | |
2063 | case 1: | |
2064 | fprintf(input, "N\n"); | |
2065 | fflush(input); | |
2066 | break; | |
2067 | ||
2068 | case 2: | |
2069 | fprintf(input, "Y\n"); | |
2070 | fflush(input); | |
2071 | break; | |
2072 | ||
2073 | default: _assert(false); | |
2074 | } | |
2075 | } | |
2076 | ||
36bb2ca2 | 2077 | [sheet dismiss]; |
2367a917 JF |
2078 | } |
2079 | ||
36bb2ca2 JF |
2080 | - (void) _retachThread { |
2081 | [delegate_ progressViewIsComplete:self]; | |
2082 | [self resetView]; | |
b19871dd JF |
2083 | } |
2084 | ||
36bb2ca2 | 2085 | - (void) _detachNewThreadData:(ProgressData *)data { |
b4d89997 JF |
2086 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
2087 | ||
36bb2ca2 JF |
2088 | [[data target] performSelector:[data selector] withObject:[data object]]; |
2089 | [data release]; | |
b19871dd | 2090 | |
36bb2ca2 | 2091 | [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES]; |
b19871dd | 2092 | |
b4d89997 | 2093 | [pool release]; |
b19871dd JF |
2094 | } |
2095 | ||
36bb2ca2 | 2096 | - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title { |
5a09ae08 JF |
2097 | UINavigationItem *item = [navbar_ topItem]; |
2098 | [item setTitle:title]; | |
b4d89997 | 2099 | |
36bb2ca2 JF |
2100 | [status_ setText:nil]; |
2101 | [output_ setText:@""]; | |
2102 | [progress_ setProgress:0]; | |
b19871dd | 2103 | |
36bb2ca2 | 2104 | [transition_ transition:6 toView:overlay_]; |
b19871dd | 2105 | |
36bb2ca2 JF |
2106 | [NSThread |
2107 | detachNewThreadSelector:@selector(_detachNewThreadData:) | |
2108 | toTarget:self | |
2109 | withObject:[[ProgressData alloc] | |
2110 | initWithSelector:selector | |
2111 | target:target | |
2112 | object:object | |
2113 | ] | |
2114 | ]; | |
b19871dd JF |
2115 | } |
2116 | ||
5a09ae08 JF |
2117 | - (void) repairWithSelector:(SEL)selector { |
2118 | [self | |
2119 | detachNewThreadSelector:selector | |
2120 | toTarget:database_ | |
2121 | withObject:nil | |
2122 | title:@"Repairing..." | |
2123 | ]; | |
2124 | } | |
2125 | ||
8b29f8e6 JF |
2126 | - (void) setConfigurationData:(NSString *)data { |
2127 | [self | |
2128 | performSelectorOnMainThread:@selector(_setConfigurationData:) | |
2129 | withObject:data | |
2130 | waitUntilDone:YES | |
2131 | ]; | |
2132 | } | |
2133 | ||
36bb2ca2 JF |
2134 | - (void) setProgressError:(NSString *)error { |
2135 | [self | |
2136 | performSelectorOnMainThread:@selector(_setProgressError:) | |
2137 | withObject:error | |
2138 | waitUntilDone:YES | |
2139 | ]; | |
b19871dd JF |
2140 | } |
2141 | ||
36bb2ca2 JF |
2142 | - (void) setProgressTitle:(NSString *)title { |
2143 | [self | |
2144 | performSelectorOnMainThread:@selector(_setProgressTitle:) | |
2145 | withObject:title | |
2146 | waitUntilDone:YES | |
2147 | ]; | |
b19871dd JF |
2148 | } |
2149 | ||
36bb2ca2 JF |
2150 | - (void) setProgressPercent:(float)percent { |
2151 | [self | |
2152 | performSelectorOnMainThread:@selector(_setProgressPercent:) | |
2153 | withObject:[NSNumber numberWithFloat:percent] | |
2154 | waitUntilDone:YES | |
2155 | ]; | |
b19871dd JF |
2156 | } |
2157 | ||
36bb2ca2 JF |
2158 | - (void) addProgressOutput:(NSString *)output { |
2159 | [self | |
2160 | performSelectorOnMainThread:@selector(_addProgressOutput:) | |
2161 | withObject:output | |
2162 | waitUntilDone:YES | |
2163 | ]; | |
b19871dd JF |
2164 | } |
2165 | ||
8b29f8e6 JF |
2166 | - (void) _setConfigurationData:(NSString *)data { |
2167 | _assert(conffile_r(data)); | |
2168 | ||
2169 | NSString *ofile = conffile_r[1]; | |
2170 | //NSString *nfile = conffile_r[2]; | |
2171 | ||
2172 | UIAlertSheet *sheet = [[[UIAlertSheet alloc] | |
2173 | initWithTitle:@"Configuration Upgrade" | |
2174 | buttons:[NSArray arrayWithObjects: | |
2175 | @"Keep My Old Copy", | |
2176 | @"Accept The New Copy", | |
2177 | // XXX: @"See What Changed", | |
2178 | nil] | |
2179 | defaultButtonIndex:0 | |
2180 | delegate:self | |
2181 | context:@"conffile" | |
2182 | ] autorelease]; | |
2183 | ||
2184 | [sheet setBodyText:[NSString stringWithFormat: | |
2185 | @"The following file has been changed by both the package maintainer and by you (or for you by a script).\n\n%@" | |
2186 | , ofile]]; | |
2187 | ||
2188 | [sheet popupAlertAnimated:YES]; | |
2189 | } | |
2190 | ||
36bb2ca2 JF |
2191 | - (void) _setProgressError:(NSString *)error { |
2192 | UIAlertSheet *sheet = [[[UIAlertSheet alloc] | |
2193 | initWithTitle:@"Package Error" | |
2194 | buttons:[NSArray arrayWithObjects:@"Okay", nil] | |
2195 | defaultButtonIndex:0 | |
2196 | delegate:self | |
a54b1c10 | 2197 | context:@"error" |
36bb2ca2 JF |
2198 | ] autorelease]; |
2199 | ||
2200 | [sheet setBodyText:error]; | |
2201 | [sheet popupAlertAnimated:YES]; | |
b19871dd JF |
2202 | } |
2203 | ||
36bb2ca2 JF |
2204 | - (void) _setProgressTitle:(NSString *)title { |
2205 | [status_ setText:[title stringByAppendingString:@"..."]]; | |
b4d89997 | 2206 | } |
b19871dd | 2207 | |
36bb2ca2 JF |
2208 | - (void) _setProgressPercent:(NSNumber *)percent { |
2209 | [progress_ setProgress:[percent floatValue]]; | |
49048579 JF |
2210 | } |
2211 | ||
36bb2ca2 JF |
2212 | - (void) _addProgressOutput:(NSString *)output { |
2213 | [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]]; | |
2214 | CGSize size = [output_ contentSize]; | |
2215 | CGRect rect = {{0, size.height}, {size.width, 0}}; | |
2216 | [output_ scrollRectToVisible:rect animated:YES]; | |
2217 | } | |
dc088e63 | 2218 | |
36bb2ca2 JF |
2219 | @end |
2220 | /* }}} */ | |
dc088e63 | 2221 | |
36bb2ca2 JF |
2222 | /* Package Cell {{{ */ |
2223 | @interface PackageCell : UITableCell { | |
2224 | UIImageView *icon_; | |
2225 | UITextLabel *name_; | |
2226 | UITextLabel *description_; | |
2227 | UITextLabel *source_; | |
2228 | UIImageView *trusted_; | |
2229 | } | |
723a0072 | 2230 | |
36bb2ca2 JF |
2231 | - (PackageCell *) init; |
2232 | - (void) setPackage:(Package *)package; | |
ec97ef06 | 2233 | |
36bb2ca2 JF |
2234 | - (void) _setSelected:(float)fraction; |
2235 | - (void) setSelected:(BOOL)selected; | |
2236 | - (void) setSelected:(BOOL)selected withFade:(BOOL)fade; | |
2237 | - (void) _setSelectionFadeFraction:(float)fraction; | |
ec97ef06 | 2238 | |
36bb2ca2 | 2239 | @end |
49048579 | 2240 | |
36bb2ca2 JF |
2241 | @implementation PackageCell |
2242 | ||
2243 | - (void) dealloc { | |
2244 | [icon_ release]; | |
2245 | [name_ release]; | |
2246 | [description_ release]; | |
2247 | [source_ release]; | |
2248 | [trusted_ release]; | |
2249 | [super dealloc]; | |
b4d89997 | 2250 | } |
b19871dd | 2251 | |
36bb2ca2 JF |
2252 | - (PackageCell *) init { |
2253 | if ((self = [super init]) != nil) { | |
2254 | GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 20); | |
2255 | GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12); | |
2256 | GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14); | |
b19871dd | 2257 | |
36bb2ca2 | 2258 | icon_ = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)]; |
b19871dd | 2259 | |
36bb2ca2 JF |
2260 | name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 8, 240, 25)]; |
2261 | [name_ setBackgroundColor:Clear_]; | |
2262 | [name_ setFont:bold]; | |
b19871dd | 2263 | |
36bb2ca2 JF |
2264 | source_ = [[UITextLabel alloc] initWithFrame:CGRectMake(58, 28, 225, 20)]; |
2265 | [source_ setBackgroundColor:Clear_]; | |
2266 | [source_ setFont:large]; | |
b19871dd | 2267 | |
36bb2ca2 JF |
2268 | description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 46, 280, 20)]; |
2269 | [description_ setBackgroundColor:Clear_]; | |
2270 | [description_ setFont:small]; | |
b19871dd | 2271 | |
36bb2ca2 JF |
2272 | trusted_ = [[UIImageView alloc] initWithFrame:CGRectMake(30, 30, 16, 16)]; |
2273 | [trusted_ setImage:[UIImage applicationImageNamed:@"trusted.png"]]; | |
b19871dd | 2274 | |
36bb2ca2 JF |
2275 | [self addSubview:icon_]; |
2276 | [self addSubview:name_]; | |
2277 | [self addSubview:description_]; | |
2278 | [self addSubview:source_]; | |
2279 | ||
2280 | CFRelease(small); | |
2281 | CFRelease(large); | |
2282 | CFRelease(bold); | |
2283 | } return self; | |
b4d89997 | 2284 | } |
b19871dd | 2285 | |
36bb2ca2 JF |
2286 | - (void) setPackage:(Package *)package { |
2287 | Source *source = [package source]; | |
b19871dd | 2288 | |
36bb2ca2 JF |
2289 | UIImage *image = nil; |
2290 | if (NSString *icon = [package icon]) | |
2291 | image = [UIImage imageAtPath:[icon substringFromIndex:6]]; | |
2292 | if (image == nil) if (NSString *icon = [source defaultIcon]) | |
2293 | image = [UIImage imageAtPath:[icon substringFromIndex:6]]; | |
2294 | if (image == nil) | |
2295 | image = [UIImage applicationImageNamed:@"unknown.png"]; | |
36bb2ca2 | 2296 | [icon_ setImage:image]; |
a0be02eb JF |
2297 | |
2298 | if (image != nil) { | |
2299 | CGSize size = [image size]; | |
2300 | float scale = 30 / std::max(size.width, size.height); | |
2301 | [icon_ zoomToScale:scale]; | |
2302 | } | |
2303 | ||
36bb2ca2 | 2304 | [icon_ setFrame:CGRectMake(10, 10, 30, 30)]; |
b19871dd | 2305 | |
36bb2ca2 JF |
2306 | [name_ setText:[package name]]; |
2307 | [description_ setText:[package tagline]]; | |
2308 | ||
a54b1c10 JF |
2309 | NSString *label = nil; |
2310 | bool trusted = false; | |
b19871dd | 2311 | |
36bb2ca2 JF |
2312 | if (source != nil) { |
2313 | label = [source label]; | |
2314 | trusted = [source trusted]; | |
a54b1c10 | 2315 | } else if ([[package id] isEqualToString:@"firmware"]) |
36bb2ca2 | 2316 | label = @"Apple"; |
a54b1c10 JF |
2317 | |
2318 | if (label == nil) | |
36bb2ca2 | 2319 | label = @"Unknown/Local"; |
b19871dd | 2320 | |
a54b1c10 JF |
2321 | NSString *from = [NSString stringWithFormat:@"from %@", label]; |
2322 | ||
2323 | NSString *section = Simplify([package section]); | |
2324 | if (section != nil && ![section isEqualToString:label]) | |
2325 | from = [from stringByAppendingString:[NSString stringWithFormat:@" (%@)", section]]; | |
2326 | ||
2327 | [source_ setText:from]; | |
36bb2ca2 JF |
2328 | |
2329 | if (trusted) | |
2330 | [self addSubview:trusted_]; | |
2331 | else | |
2332 | [trusted_ removeFromSuperview]; | |
b19871dd JF |
2333 | } |
2334 | ||
36bb2ca2 JF |
2335 | - (void) _setSelected:(float)fraction { |
2336 | CGColor black(space_, | |
2337 | Interpolate(0.0, 1.0, fraction), | |
2338 | Interpolate(0.0, 1.0, fraction), | |
2339 | Interpolate(0.0, 1.0, fraction), | |
2340 | 1.0); | |
b19871dd | 2341 | |
36bb2ca2 JF |
2342 | CGColor gray(space_, |
2343 | Interpolate(0.4, 1.0, fraction), | |
2344 | Interpolate(0.4, 1.0, fraction), | |
2345 | Interpolate(0.4, 1.0, fraction), | |
2346 | 1.0); | |
b19871dd | 2347 | |
36bb2ca2 JF |
2348 | [name_ setColor:black]; |
2349 | [description_ setColor:gray]; | |
2350 | [source_ setColor:black]; | |
b19871dd JF |
2351 | } |
2352 | ||
36bb2ca2 JF |
2353 | - (void) setSelected:(BOOL)selected { |
2354 | [self _setSelected:(selected ? 1.0 : 0.0)]; | |
2355 | [super setSelected:selected]; | |
b19871dd JF |
2356 | } |
2357 | ||
36bb2ca2 JF |
2358 | - (void) setSelected:(BOOL)selected withFade:(BOOL)fade { |
2359 | if (!fade) | |
2360 | [self _setSelected:(selected ? 1.0 : 0.0)]; | |
2361 | [super setSelected:selected withFade:fade]; | |
2362 | } | |
2363 | ||
2364 | - (void) _setSelectionFadeFraction:(float)fraction { | |
2365 | [self _setSelected:fraction]; | |
2366 | [super _setSelectionFadeFraction:fraction]; | |
ec97ef06 JF |
2367 | } |
2368 | ||
8da60fb7 JF |
2369 | @end |
2370 | /* }}} */ | |
36bb2ca2 JF |
2371 | /* Section Cell {{{ */ |
2372 | @interface SectionCell : UITableCell { | |
2373 | UITextLabel *name_; | |
2374 | UITextLabel *count_; | |
b4d89997 | 2375 | } |
b19871dd | 2376 | |
36bb2ca2 JF |
2377 | - (id) init; |
2378 | - (void) setSection:(Section *)section; | |
2379 | ||
2380 | - (void) _setSelected:(float)fraction; | |
2381 | - (void) setSelected:(BOOL)selected; | |
2382 | - (void) setSelected:(BOOL)selected withFade:(BOOL)fade; | |
2383 | - (void) _setSelectionFadeFraction:(float)fraction; | |
b19871dd | 2384 | |
8da60fb7 JF |
2385 | @end |
2386 | ||
36bb2ca2 | 2387 | @implementation SectionCell |
8da60fb7 | 2388 | |
36bb2ca2 JF |
2389 | - (void) dealloc { |
2390 | [name_ release]; | |
2391 | [count_ release]; | |
2392 | [super dealloc]; | |
2393 | } | |
2394 | ||
2395 | - (id) init { | |
b4d89997 | 2396 | if ((self = [super init]) != nil) { |
36bb2ca2 JF |
2397 | GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22); |
2398 | GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 12); | |
2399 | ||
2400 | name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 9, 250, 25)]; | |
2401 | [name_ setBackgroundColor:Clear_]; | |
2402 | [name_ setFont:bold]; | |
2403 | ||
2404 | count_ = [[UITextLabel alloc] initWithFrame:CGRectMake(11, 7, 29, 32)]; | |
2405 | [count_ setCentersHorizontally:YES]; | |
2406 | [count_ setBackgroundColor:Clear_]; | |
2407 | [count_ setFont:small]; | |
2408 | [count_ setColor:White_]; | |
2409 | ||
2410 | UIImageView *folder = [[[UIImageView alloc] initWithFrame:CGRectMake(8, 7, 32, 32)] autorelease]; | |
2411 | [folder setImage:[UIImage applicationImageNamed:@"folder.png"]]; | |
2412 | ||
2413 | [self addSubview:folder]; | |
2414 | [self addSubview:name_]; | |
2415 | [self addSubview:count_]; | |
2416 | ||
2417 | [self _setSelected:0]; | |
2418 | ||
2419 | CFRelease(small); | |
2420 | CFRelease(bold); | |
b4d89997 | 2421 | } return self; |
b19871dd JF |
2422 | } |
2423 | ||
36bb2ca2 JF |
2424 | - (void) setSection:(Section *)section { |
2425 | if (section == nil) { | |
2426 | [name_ setText:@"All Packages"]; | |
2427 | [count_ setText:nil]; | |
2428 | } else { | |
2429 | NSString *name = [section name]; | |
2430 | [name_ setText:(name == nil ? @"(No Section)" : name)]; | |
2431 | [count_ setText:[NSString stringWithFormat:@"%d", [section count]]]; | |
2432 | } | |
b19871dd JF |
2433 | } |
2434 | ||
36bb2ca2 JF |
2435 | - (void) _setSelected:(float)fraction { |
2436 | CGColor black(space_, | |
2437 | Interpolate(0.0, 1.0, fraction), | |
2438 | Interpolate(0.0, 1.0, fraction), | |
2439 | Interpolate(0.0, 1.0, fraction), | |
2440 | 1.0); | |
b19871dd | 2441 | |
36bb2ca2 | 2442 | [name_ setColor:black]; |
b19871dd JF |
2443 | } |
2444 | ||
36bb2ca2 JF |
2445 | - (void) setSelected:(BOOL)selected { |
2446 | [self _setSelected:(selected ? 1.0 : 0.0)]; | |
2447 | [super setSelected:selected]; | |
b19871dd JF |
2448 | } |
2449 | ||
36bb2ca2 JF |
2450 | - (void) setSelected:(BOOL)selected withFade:(BOOL)fade { |
2451 | if (!fade) | |
2452 | [self _setSelected:(selected ? 1.0 : 0.0)]; | |
2453 | [super setSelected:selected withFade:fade]; | |
2454 | } | |
b19871dd | 2455 | |
36bb2ca2 JF |
2456 | - (void) _setSelectionFadeFraction:(float)fraction { |
2457 | [self _setSelected:fraction]; | |
2458 | [super _setSelectionFadeFraction:fraction]; | |
2459 | } | |
b31b87cc | 2460 | |
36bb2ca2 JF |
2461 | @end |
2462 | /* }}} */ | |
b19871dd | 2463 | |
ab398adf JF |
2464 | /* File Table {{{ */ |
2465 | @interface FileTable : RVPage { | |
36bb2ca2 | 2466 | _transient Database *database_; |
ab398adf JF |
2467 | Package *package_; |
2468 | NSString *name_; | |
2469 | NSMutableArray *files_; | |
2470 | UITable *list_; | |
2471 | } | |
b19871dd | 2472 | |
ab398adf JF |
2473 | - (id) initWithBook:(RVBook *)book database:(Database *)database; |
2474 | - (void) setPackage:(Package *)package; | |
2475 | ||
2476 | @end | |
2477 | ||
2478 | @implementation FileTable | |
2479 | ||
2480 | - (void) dealloc { | |
2481 | if (package_ != nil) | |
2482 | [package_ release]; | |
2483 | if (name_ != nil) | |
2484 | [name_ release]; | |
2485 | [files_ release]; | |
2486 | [list_ release]; | |
2487 | [super dealloc]; | |
2488 | } | |
2489 | ||
2490 | - (int) numberOfRowsInTable:(UITable *)table { | |
2491 | return files_ == nil ? 0 : [files_ count]; | |
2492 | } | |
2493 | ||
2494 | - (float) table:(UITable *)table heightForRow:(int)row { | |
2495 | return 24; | |
2496 | } | |
2497 | ||
2498 | - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing { | |
2499 | if (reusing == nil) { | |
2500 | reusing = [[[UIImageAndTextTableCell alloc] init] autorelease]; | |
2501 | GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16); | |
2502 | [[(UIImageAndTextTableCell *)reusing titleTextLabel] setFont:font]; | |
2503 | CFRelease(font); | |
2504 | } | |
2505 | [(UIImageAndTextTableCell *)reusing setTitle:[files_ objectAtIndex:row]]; | |
2506 | return reusing; | |
36bb2ca2 | 2507 | } |
b19871dd | 2508 | |
ab398adf JF |
2509 | - (BOOL) canSelectRow:(int)row { |
2510 | return NO; | |
2511 | } | |
b19871dd | 2512 | |
ab398adf JF |
2513 | - (id) initWithBook:(RVBook *)book database:(Database *)database { |
2514 | if ((self = [super initWithBook:book]) != nil) { | |
2515 | database_ = database; | |
b19871dd | 2516 | |
ab398adf | 2517 | files_ = [[NSMutableArray arrayWithCapacity:32] retain]; |
8da60fb7 | 2518 | |
ab398adf JF |
2519 | list_ = [[UITable alloc] initWithFrame:[self bounds]]; |
2520 | [self addSubview:list_]; | |
2521 | ||
2522 | UITableColumn *column = [[[UITableColumn alloc] | |
2523 | initWithTitle:@"Name" | |
2524 | identifier:@"name" | |
2525 | width:[self frame].size.width | |
2526 | ] autorelease]; | |
2527 | ||
2528 | [list_ setDataSource:self]; | |
2529 | [list_ setSeparatorStyle:1]; | |
2530 | [list_ addTableColumn:column]; | |
2531 | [list_ setDelegate:self]; | |
2532 | [list_ setReusesTableCells:YES]; | |
2533 | } return self; | |
2534 | } | |
2535 | ||
2536 | - (void) setPackage:(Package *)package { | |
2537 | if (package_ != nil) { | |
2538 | [package_ autorelease]; | |
2539 | package_ = nil; | |
2540 | } | |
2541 | ||
2542 | if (name_ != nil) { | |
2543 | [name_ release]; | |
2544 | name_ = nil; | |
2545 | } | |
2546 | ||
2547 | [files_ removeAllObjects]; | |
2548 | ||
2549 | if (package != nil) { | |
2550 | package_ = [package retain]; | |
2551 | name_ = [[package id] retain]; | |
2552 | ||
9ea8d159 JF |
2553 | NSString *path = [NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", name_]; |
2554 | ||
2555 | { | |
2556 | std::ifstream fin([path UTF8String]); | |
2557 | std::string line; | |
2558 | while (std::getline(fin, line)) | |
2559 | [files_ addObject:[NSString stringWithUTF8String:line.c_str()]]; | |
2560 | } | |
ab398adf | 2561 | |
9ea8d159 JF |
2562 | if ([files_ count] != 0) { |
2563 | if ([[files_ objectAtIndex:0] isEqualToString:@"/."]) | |
2564 | [files_ removeObjectAtIndex:0]; | |
a54b1c10 | 2565 | [files_ sortUsingSelector:@selector(compareByPath:)]; |
2388b078 JF |
2566 | |
2567 | NSMutableArray *stack = [NSMutableArray arrayWithCapacity:8]; | |
2568 | [stack addObject:@"/"]; | |
2569 | ||
2570 | for (int i(0), e([files_ count]); i != e; ++i) { | |
2571 | NSString *file = [files_ objectAtIndex:i]; | |
2572 | while (![file hasPrefix:[stack lastObject]]) | |
2573 | [stack removeLastObject]; | |
2574 | NSString *directory = [stack lastObject]; | |
2575 | [stack addObject:[file stringByAppendingString:@"/"]]; | |
2576 | [files_ replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%*s%@", | |
a54b1c10 | 2577 | ([stack count] - 2) * 3, "", |
2388b078 JF |
2578 | [file substringFromIndex:[directory length]] |
2579 | ]]; | |
2580 | } | |
ab398adf JF |
2581 | } |
2582 | } | |
2583 | ||
2584 | [list_ reloadData]; | |
2585 | } | |
2586 | ||
2587 | - (void) resetViewAnimated:(BOOL)animated { | |
2588 | [list_ resetViewAnimated:animated]; | |
2589 | } | |
2590 | ||
2591 | - (void) reloadData { | |
2592 | [self setPackage:[database_ packageWithName:name_]]; | |
2593 | [self reloadButtons]; | |
2594 | } | |
2595 | ||
2596 | - (NSString *) title { | |
2388b078 JF |
2597 | return @"Installed Files"; |
2598 | } | |
2599 | ||
2600 | - (NSString *) backButtonTitle { | |
2601 | return @"Files"; | |
ab398adf | 2602 | } |
b4d89997 | 2603 | |
b4d89997 | 2604 | @end |
36bb2ca2 | 2605 | /* }}} */ |
36bb2ca2 JF |
2606 | /* Package View {{{ */ |
2607 | @protocol PackageViewDelegate | |
2608 | - (void) performPackage:(Package *)package; | |
2609 | @end | |
8da60fb7 | 2610 | |
36bb2ca2 JF |
2611 | @interface PackageView : RVPage { |
2612 | _transient Database *database_; | |
2613 | UIPreferencesTable *table_; | |
2614 | Package *package_; | |
2615 | NSString *name_; | |
2616 | UITextView *description_; | |
5a09ae08 | 2617 | NSMutableArray *buttons_; |
b31b87cc JF |
2618 | } |
2619 | ||
36bb2ca2 JF |
2620 | - (id) initWithBook:(RVBook *)book database:(Database *)database; |
2621 | - (void) setPackage:(Package *)package; | |
b4d89997 | 2622 | |
36bb2ca2 | 2623 | @end |
b4d89997 | 2624 | |
36bb2ca2 | 2625 | @implementation PackageView |
b4d89997 | 2626 | |
36bb2ca2 JF |
2627 | - (void) dealloc { |
2628 | [table_ setDataSource:nil]; | |
2629 | [table_ setDelegate:nil]; | |
b4d89997 | 2630 | |
36bb2ca2 JF |
2631 | if (package_ != nil) |
2632 | [package_ release]; | |
2633 | if (name_ != nil) | |
2634 | [name_ release]; | |
2635 | if (description_ != nil) | |
2636 | [description_ release]; | |
2637 | [table_ release]; | |
5a09ae08 | 2638 | [buttons_ release]; |
36bb2ca2 JF |
2639 | [super dealloc]; |
2640 | } | |
8da60fb7 | 2641 | |
36bb2ca2 | 2642 | - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table { |
ab398adf JF |
2643 | int number = 2; |
2644 | if ([package_ installed] != nil) | |
2645 | ++number; | |
2646 | if ([package_ source] != nil) | |
2647 | ++number; | |
2648 | return number; | |
36bb2ca2 | 2649 | } |
b31b87cc | 2650 | |
36bb2ca2 | 2651 | - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group { |
ab398adf JF |
2652 | if (group-- == 0) |
2653 | return nil; | |
2654 | else if ([package_ installed] != nil && group-- == 0) | |
2655 | return @"Installed Package"; | |
2656 | else if (group-- == 0) | |
2657 | return @"Package Details"; | |
2658 | else if ([package_ source] != nil && group-- == 0) | |
2659 | return @"Source Information"; | |
2660 | else _assert(false); | |
36bb2ca2 | 2661 | } |
8da60fb7 | 2662 | |
36bb2ca2 | 2663 | - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed { |
5a09ae08 | 2664 | if (description_ == nil || group != 0 || row != 1) |
36bb2ca2 JF |
2665 | return proposed; |
2666 | else | |
2667 | return [description_ visibleTextRect].size.height + TextViewOffset_; | |
2668 | } | |
8da60fb7 | 2669 | |
36bb2ca2 | 2670 | - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group { |
ab398adf | 2671 | if (group-- == 0) { |
5a09ae08 JF |
2672 | int number = 1; |
2673 | if (description_ != nil) | |
2674 | ++number; | |
ab398adf JF |
2675 | if ([package_ website] != nil) |
2676 | ++number; | |
2677 | if ([[package_ source] trusted]) | |
2678 | ++number; | |
2679 | return number; | |
2680 | } else if ([package_ installed] != nil && group-- == 0) | |
2681 | return 2; | |
2388b078 | 2682 | else if (group-- == 0) { |
5a09ae08 JF |
2683 | int number = 2; |
2684 | if ([package_ size] != 0) | |
2685 | ++number; | |
2686 | if ([package_ maintainer] != nil) | |
2687 | ++number; | |
2388b078 JF |
2688 | if ([package_ relationships] != nil) |
2689 | ++number; | |
2690 | return number; | |
a54b1c10 JF |
2691 | } else if ([package_ source] != nil && group-- == 0) { |
2692 | Source *source = [package_ source]; | |
2693 | NSString *description = [source description]; | |
5a09ae08 | 2694 | int number = 1; |
a54b1c10 JF |
2695 | if (description != nil && ![description isEqualToString:[source label]]) |
2696 | ++number; | |
5a09ae08 JF |
2697 | if ([source origin] != nil) |
2698 | ++number; | |
a54b1c10 JF |
2699 | return number; |
2700 | } else _assert(false); | |
36bb2ca2 | 2701 | } |
8da60fb7 | 2702 | |
36bb2ca2 JF |
2703 | - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group { |
2704 | UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease]; | |
2705 | [cell setShowSelection:NO]; | |
b4d89997 | 2706 | |
2388b078 JF |
2707 | if (group-- == 0) { |
2708 | if (row-- == 0) { | |
2709 | [cell setTitle:[package_ name]]; | |
2710 | [cell setValue:[package_ latest]]; | |
5a09ae08 | 2711 | } else if (description_ != nil && row-- == 0) { |
2388b078 JF |
2712 | [cell addSubview:description_]; |
2713 | } else if ([package_ website] != nil && row-- == 0) { | |
2714 | [cell setTitle:@"More Information"]; | |
2715 | [cell setShowDisclosure:YES]; | |
2716 | [cell setShowSelection:YES]; | |
2717 | } else if ([[package_ source] trusted] && row-- == 0) { | |
2718 | [cell setIcon:[UIImage applicationImageNamed:@"trusted.png"]]; | |
2719 | [cell setValue:@"This package has been signed."]; | |
2720 | } else _assert(false); | |
2721 | } else if ([package_ installed] != nil && group-- == 0) { | |
2722 | if (row-- == 0) { | |
2723 | [cell setTitle:@"Version"]; | |
2724 | NSString *installed([package_ installed]); | |
2725 | [cell setValue:(installed == nil ? @"n/a" : installed)]; | |
2726 | } else if (row-- == 0) { | |
2727 | [cell setTitle:@"Filesystem Content"]; | |
2728 | [cell setShowDisclosure:YES]; | |
2729 | [cell setShowSelection:YES]; | |
2730 | } else _assert(false); | |
2731 | } else if (group-- == 0) { | |
2732 | if (row-- == 0) { | |
2733 | [cell setTitle:@"Identifier"]; | |
2734 | [cell setValue:[package_ id]]; | |
2735 | } else if (row-- == 0) { | |
2736 | [cell setTitle:@"Section"]; | |
2737 | NSString *section([package_ section]); | |
2738 | [cell setValue:(section == nil ? @"n/a" : section)]; | |
5a09ae08 | 2739 | } else if ([package_ size] != 0 && row-- == 0) { |
2388b078 JF |
2740 | [cell setTitle:@"Expanded Size"]; |
2741 | [cell setValue:SizeString([package_ size])]; | |
5a09ae08 | 2742 | } else if ([package_ maintainer] != nil && row-- == 0) { |
2388b078 JF |
2743 | [cell setTitle:@"Maintainer"]; |
2744 | [cell setValue:[[package_ maintainer] name]]; | |
2745 | [cell setShowDisclosure:YES]; | |
2746 | [cell setShowSelection:YES]; | |
2747 | } else if ([package_ relationships] != nil && row-- == 0) { | |
2748 | [cell setTitle:@"Package Relationships"]; | |
2749 | [cell setShowDisclosure:YES]; | |
2750 | [cell setShowSelection:YES]; | |
2751 | } else _assert(false); | |
2752 | } else if ([package_ source] != nil && group-- == 0) { | |
a54b1c10 JF |
2753 | Source *source = [package_ source]; |
2754 | NSString *description = [source description]; | |
2755 | ||
2388b078 | 2756 | if (row-- == 0) { |
5a09ae08 JF |
2757 | NSString *label = [source label]; |
2758 | if (label == nil) | |
2759 | label = [source uri]; | |
2760 | [cell setTitle:label]; | |
a54b1c10 JF |
2761 | [cell setValue:[source version]]; |
2762 | } else if (description != nil && ![description isEqualToString:[source label]] && row-- == 0) { | |
2763 | [cell setValue:description]; | |
5a09ae08 | 2764 | } else if ([source origin] != nil && row-- == 0) { |
2388b078 | 2765 | [cell setTitle:@"Origin"]; |
a54b1c10 | 2766 | [cell setValue:[source origin]]; |
2388b078 JF |
2767 | } else _assert(false); |
2768 | } else _assert(false); | |
dc5812ec | 2769 | |
36bb2ca2 | 2770 | return cell; |
b4d89997 | 2771 | } |
dc5812ec | 2772 | |
36bb2ca2 JF |
2773 | - (BOOL) canSelectRow:(int)row { |
2774 | return YES; | |
2367a917 JF |
2775 | } |
2776 | ||
36bb2ca2 JF |
2777 | - (void) tableRowSelected:(NSNotification *)notification { |
2778 | int row = [table_ selectedRow]; | |
2779 | NSString *website = [package_ website]; | |
ab398adf JF |
2780 | BOOL trusted = [[package_ source] trusted]; |
2781 | NSString *installed = [package_ installed]; | |
2782 | ||
2783 | if (row == 7 | |
2784 | + (website == nil ? 0 : 1) | |
2785 | + (trusted ? 1 : 0) | |
2786 | + (installed == nil ? 0 : 3) | |
2787 | ) | |
36bb2ca2 JF |
2788 | [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@", |
2789 | [[package_ maintainer] email], | |
2790 | [[NSString stringWithFormat:@"regarding apt package \"%@\"", [package_ name]] stringByAddingPercentEscapes] | |
2791 | ]]]; | |
ab398adf JF |
2792 | else if (installed && row == 5 |
2793 | + (website == nil ? 0 : 1) | |
2794 | + (trusted ? 1 : 0) | |
2795 | ) { | |
2796 | FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease]; | |
2797 | [files setDelegate:delegate_]; | |
2798 | [files setPackage:package_]; | |
2799 | [book_ pushPage:files]; | |
2800 | } else if (website != nil && row == 3) { | |
36bb2ca2 JF |
2801 | NSURL *url = [NSURL URLWithString:website]; |
2802 | BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease]; | |
2803 | [browser setDelegate:delegate_]; | |
2804 | [book_ pushPage:browser]; | |
2805 | [browser loadURL:url]; | |
2806 | } | |
3178d79b JF |
2807 | } |
2808 | ||
5a09ae08 JF |
2809 | - (void) _clickButtonWithName:(NSString *)name { |
2810 | if ([name isEqualToString:@"Install"]) | |
2811 | [delegate_ installPackage:package_]; | |
2812 | else if ([name isEqualToString:@"Reinstall"]) | |
2813 | [delegate_ installPackage:package_]; | |
2814 | else if ([name isEqualToString:@"Remove"]) | |
2815 | [delegate_ removePackage:package_]; | |
2816 | else if ([name isEqualToString:@"Upgrade"]) | |
2817 | [delegate_ installPackage:package_]; | |
2818 | else _assert(false); | |
2819 | } | |
2820 | ||
36bb2ca2 | 2821 | - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button { |
5a09ae08 JF |
2822 | int count = [buttons_ count]; |
2823 | _assert(count != 0); | |
2824 | _assert(button <= count + 1); | |
2825 | ||
2826 | if (count != button - 1) | |
2827 | [self _clickButtonWithName:[buttons_ objectAtIndex:(button - 1)]]; | |
36bb2ca2 JF |
2828 | |
2829 | [sheet dismiss]; | |
b4d89997 | 2830 | } |
2367a917 | 2831 | |
36bb2ca2 | 2832 | - (void) _rightButtonClicked { |
5a09ae08 JF |
2833 | int count = [buttons_ count]; |
2834 | _assert(count != 0); | |
2367a917 | 2835 | |
5a09ae08 JF |
2836 | if (count == 1) |
2837 | [self _clickButtonWithName:[buttons_ objectAtIndex:0]]; | |
2838 | else { | |
2839 | NSMutableArray *buttons = [NSMutableArray arrayWithCapacity:(count + 1)]; | |
2840 | [buttons addObjectsFromArray:buttons_]; | |
36bb2ca2 JF |
2841 | [buttons addObject:@"Cancel"]; |
2842 | ||
2843 | [delegate_ slideUp:[[[UIAlertSheet alloc] | |
9ea8d159 | 2844 | initWithTitle:nil |
36bb2ca2 JF |
2845 | buttons:buttons |
2846 | defaultButtonIndex:2 | |
2847 | delegate:self | |
a54b1c10 | 2848 | context:@"manage" |
36bb2ca2 JF |
2849 | ] autorelease]]; |
2850 | } | |
b4d89997 | 2851 | } |
2367a917 | 2852 | |
36bb2ca2 | 2853 | - (NSString *) rightButtonTitle { |
5a09ae08 JF |
2854 | int count = [buttons_ count]; |
2855 | return count == 0 ? nil : count != 1 ? @"Modify" : [buttons_ objectAtIndex:0]; | |
b4d89997 | 2856 | } |
2367a917 | 2857 | |
36bb2ca2 JF |
2858 | - (NSString *) title { |
2859 | return @"Details"; | |
dc5812ec JF |
2860 | } |
2861 | ||
36bb2ca2 JF |
2862 | - (id) initWithBook:(RVBook *)book database:(Database *)database { |
2863 | if ((self = [super initWithBook:book]) != nil) { | |
2864 | database_ = database; | |
2865 | ||
2866 | table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]]; | |
2867 | [self addSubview:table_]; | |
2868 | ||
2869 | [table_ setDataSource:self]; | |
2870 | [table_ setDelegate:self]; | |
5a09ae08 JF |
2871 | |
2872 | buttons_ = [[NSMutableArray alloc] initWithCapacity:4]; | |
36bb2ca2 | 2873 | } return self; |
dc5812ec JF |
2874 | } |
2875 | ||
36bb2ca2 JF |
2876 | - (void) setPackage:(Package *)package { |
2877 | if (package_ != nil) { | |
2878 | [package_ autorelease]; | |
2879 | package_ = nil; | |
2880 | } | |
2881 | ||
2882 | if (name_ != nil) { | |
2883 | [name_ release]; | |
2884 | name_ = nil; | |
2885 | } | |
2886 | ||
2887 | if (description_ != nil) { | |
2888 | [description_ release]; | |
2889 | description_ = nil; | |
2890 | } | |
2891 | ||
5a09ae08 JF |
2892 | [buttons_ removeAllObjects]; |
2893 | ||
36bb2ca2 JF |
2894 | if (package != nil) { |
2895 | package_ = [package retain]; | |
2896 | name_ = [[package id] retain]; | |
2897 | ||
2898 | NSString *description([package description]); | |
2899 | if (description == nil) | |
2900 | description = [package tagline]; | |
5a09ae08 JF |
2901 | if (description != nil) { |
2902 | description_ = [GetTextView(description, 12, true) retain]; | |
2903 | [description_ setTextColor:Black_]; | |
2904 | } | |
36bb2ca2 JF |
2905 | |
2906 | [table_ reloadData]; | |
5a09ae08 JF |
2907 | |
2908 | if ([package_ source] == nil); | |
2909 | else if ([package_ installed] == nil) | |
2910 | [buttons_ addObject:@"Install"]; | |
2911 | else if ([package_ upgradable]) | |
2912 | [buttons_ addObject:@"Upgrade"]; | |
2913 | else | |
2914 | [buttons_ addObject:@"Reinstall"]; | |
2915 | if ([package_ installed] != nil) | |
2916 | [buttons_ addObject:@"Remove"]; | |
36bb2ca2 | 2917 | } |
dc5812ec JF |
2918 | } |
2919 | ||
36bb2ca2 JF |
2920 | - (void) resetViewAnimated:(BOOL)animated { |
2921 | [table_ resetViewAnimated:animated]; | |
dc5812ec JF |
2922 | } |
2923 | ||
36bb2ca2 JF |
2924 | - (void) reloadData { |
2925 | [self setPackage:[database_ packageWithName:name_]]; | |
2926 | [self reloadButtons]; | |
8fe19fc1 JF |
2927 | } |
2928 | ||
b4d89997 JF |
2929 | @end |
2930 | /* }}} */ | |
b4d89997 | 2931 | /* Package Table {{{ */ |
36bb2ca2 JF |
2932 | @interface PackageTable : RVPage { |
2933 | _transient Database *database_; | |
2934 | NSString *title_; | |
2935 | SEL filter_; | |
2936 | id object_; | |
2937 | NSMutableArray *packages_; | |
b4d89997 | 2938 | NSMutableArray *sections_; |
36bb2ca2 | 2939 | UISectionList *list_; |
dc5812ec JF |
2940 | } |
2941 | ||
36bb2ca2 | 2942 | - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object; |
b4d89997 JF |
2943 | |
2944 | - (void) setDelegate:(id)delegate; | |
a0be02eb JF |
2945 | - (void) setObject:(id)object; |
2946 | ||
36bb2ca2 | 2947 | - (void) reloadData; |
a0be02eb | 2948 | - (void) resetCursor; |
b4d89997 | 2949 | |
2388b078 JF |
2950 | - (UISectionList *) list; |
2951 | ||
ab398adf JF |
2952 | - (void) setShouldHideHeaderInShortLists:(BOOL)hide; |
2953 | ||
b4d89997 JF |
2954 | @end |
2955 | ||
2956 | @implementation PackageTable | |
2957 | ||
2958 | - (void) dealloc { | |
36bb2ca2 JF |
2959 | [list_ setDataSource:nil]; |
2960 | ||
2961 | [title_ release]; | |
2962 | if (object_ != nil) | |
2963 | [object_ release]; | |
2964 | [packages_ release]; | |
b4d89997 | 2965 | [sections_ release]; |
36bb2ca2 | 2966 | [list_ release]; |
b4d89997 | 2967 | [super dealloc]; |
8fe19fc1 JF |
2968 | } |
2969 | ||
b4d89997 JF |
2970 | - (int) numberOfSectionsInSectionList:(UISectionList *)list { |
2971 | return [sections_ count]; | |
2972 | } | |
2367a917 | 2973 | |
b4d89997 JF |
2974 | - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section { |
2975 | return [[sections_ objectAtIndex:section] name]; | |
2976 | } | |
dc5812ec | 2977 | |
b4d89997 JF |
2978 | - (int) sectionList:(UISectionList *)list rowForSection:(int)section { |
2979 | return [[sections_ objectAtIndex:section] row]; | |
2367a917 JF |
2980 | } |
2981 | ||
b4d89997 JF |
2982 | - (int) numberOfRowsInTable:(UITable *)table { |
2983 | return [packages_ count]; | |
2984 | } | |
dc5812ec | 2985 | |
b4d89997 | 2986 | - (float) table:(UITable *)table heightForRow:(int)row { |
36bb2ca2 | 2987 | return 73; |
b4d89997 | 2988 | } |
dc5812ec | 2989 | |
b4d89997 JF |
2990 | - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing { |
2991 | if (reusing == nil) | |
36bb2ca2 | 2992 | reusing = [[[PackageCell alloc] init] autorelease]; |
b4d89997 JF |
2993 | [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]]; |
2994 | return reusing; | |
2995 | } | |
dc5812ec | 2996 | |
b4d89997 JF |
2997 | - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row { |
2998 | return NO; | |
2999 | } | |
dc5812ec | 3000 | |
b4d89997 JF |
3001 | - (void) tableRowSelected:(NSNotification *)notification { |
3002 | int row = [[notification object] selectedRow]; | |
36bb2ca2 JF |
3003 | if (row == INT_MAX) |
3004 | return; | |
3005 | ||
3006 | Package *package = [packages_ objectAtIndex:row]; | |
3007 | PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease]; | |
3008 | [view setDelegate:delegate_]; | |
3009 | [view setPackage:package]; | |
3010 | [book_ pushPage:view]; | |
dc5812ec JF |
3011 | } |
3012 | ||
36bb2ca2 JF |
3013 | - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object { |
3014 | if ((self = [super initWithBook:book]) != nil) { | |
3015 | database_ = database; | |
3016 | title_ = [title retain]; | |
3017 | filter_ = filter; | |
3018 | object_ = object == nil ? nil : [object retain]; | |
3019 | ||
3020 | packages_ = [[NSMutableArray arrayWithCapacity:16] retain]; | |
b4d89997 | 3021 | sections_ = [[NSMutableArray arrayWithCapacity:16] retain]; |
dc5812ec | 3022 | |
b4d89997 JF |
3023 | list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES]; |
3024 | [list_ setDataSource:self]; | |
dc5812ec | 3025 | |
b4d89997 JF |
3026 | UITableColumn *column = [[[UITableColumn alloc] |
3027 | initWithTitle:@"Name" | |
3028 | identifier:@"name" | |
36bb2ca2 | 3029 | width:[self frame].size.width |
b4d89997 JF |
3030 | ] autorelease]; |
3031 | ||
3032 | UITable *table = [list_ table]; | |
3033 | [table setSeparatorStyle:1]; | |
3034 | [table addTableColumn:column]; | |
3035 | [table setDelegate:self]; | |
3036 | [table setReusesTableCells:YES]; | |
3037 | ||
3038 | [self addSubview:list_]; | |
36bb2ca2 | 3039 | [self reloadData]; |
b4d89997 | 3040 | } return self; |
dc5812ec JF |
3041 | } |
3042 | ||
3043 | - (void) setDelegate:(id)delegate { | |
2367a917 | 3044 | delegate_ = delegate; |
b4d89997 JF |
3045 | } |
3046 | ||
a0be02eb JF |
3047 | - (void) setObject:(id)object { |
3048 | if (object_ != nil) | |
3049 | [object_ release]; | |
3050 | if (object == nil) | |
3051 | object_ = nil; | |
3052 | else | |
3053 | object_ = [object retain]; | |
3054 | } | |
3055 | ||
36bb2ca2 JF |
3056 | - (void) reloadData { |
3057 | NSArray *packages = [database_ packages]; | |
b4d89997 | 3058 | |
36bb2ca2 | 3059 | [packages_ removeAllObjects]; |
b4d89997 JF |
3060 | [sections_ removeAllObjects]; |
3061 | ||
36bb2ca2 JF |
3062 | for (size_t i(0); i != [packages count]; ++i) { |
3063 | Package *package([packages objectAtIndex:i]); | |
3064 | if ([[package performSelector:filter_ withObject:object_] boolValue]) | |
3065 | [packages_ addObject:package]; | |
3066 | } | |
3067 | ||
b4d89997 JF |
3068 | Section *section = nil; |
3069 | ||
3070 | for (size_t offset(0); offset != [packages_ count]; ++offset) { | |
3071 | Package *package = [packages_ objectAtIndex:offset]; | |
3072 | NSString *name = [package index]; | |
3073 | ||
36bb2ca2 | 3074 | if (section == nil || ![[section name] isEqualToString:name]) { |
b4d89997 JF |
3075 | section = [[[Section alloc] initWithName:name row:offset] autorelease]; |
3076 | [sections_ addObject:section]; | |
3077 | } | |
3078 | ||
36bb2ca2 | 3079 | [section addToCount]; |
b4d89997 JF |
3080 | } |
3081 | ||
3082 | [list_ reloadData]; | |
3083 | } | |
3084 | ||
36bb2ca2 JF |
3085 | - (NSString *) title { |
3086 | return title_; | |
b4d89997 JF |
3087 | } |
3088 | ||
36bb2ca2 JF |
3089 | - (void) resetViewAnimated:(BOOL)animated { |
3090 | [list_ resetViewAnimated:animated]; | |
dc5812ec JF |
3091 | } |
3092 | ||
a0be02eb JF |
3093 | - (void) resetCursor { |
3094 | [[list_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO]; | |
3095 | } | |
3096 | ||
2388b078 JF |
3097 | - (UISectionList *) list { |
3098 | return list_; | |
3099 | } | |
3100 | ||
ab398adf JF |
3101 | - (void) setShouldHideHeaderInShortLists:(BOOL)hide { |
3102 | [list_ setShouldHideHeaderInShortLists:hide]; | |
3103 | } | |
3104 | ||
dc5812ec | 3105 | @end |
b4d89997 | 3106 | /* }}} */ |
dc5812ec | 3107 | |
36bb2ca2 JF |
3108 | /* Browser Implementation {{{ */ |
3109 | @implementation BrowserView | |
3110 | ||
3111 | - (void) dealloc { | |
3112 | WebView *webview = [webview_ webView]; | |
3113 | [webview setFrameLoadDelegate:nil]; | |
3114 | [webview setResourceLoadDelegate:nil]; | |
3115 | [webview setUIDelegate:nil]; | |
3116 | ||
3117 | [scroller_ setDelegate:nil]; | |
3118 | [webview_ setDelegate:nil]; | |
3119 | ||
3120 | [scroller_ release]; | |
3121 | [webview_ release]; | |
3122 | [urls_ release]; | |
3123 | [indicator_ release]; | |
3124 | if (title_ != nil) | |
3125 | [title_ release]; | |
3126 | [super dealloc]; | |
dc5812ec JF |
3127 | } |
3128 | ||
36bb2ca2 JF |
3129 | - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy { |
3130 | NSMutableURLRequest *request = [NSMutableURLRequest | |
3131 | requestWithURL:url | |
3132 | cachePolicy:policy | |
3133 | timeoutInterval:30.0 | |
3134 | ]; | |
b4d89997 | 3135 | |
2388b078 JF |
3136 | [request addValue:[NSString stringWithUTF8String:Firmware_] forHTTPHeaderField:@"X-Firmware"]; |
3137 | [request addValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"]; | |
3138 | [request addValue:[NSString stringWithUTF8String:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"]; | |
b4d89997 | 3139 | |
36bb2ca2 JF |
3140 | [self loadRequest:request]; |
3141 | } | |
dc5812ec | 3142 | |
dc5812ec | 3143 | |
36bb2ca2 JF |
3144 | - (void) loadURL:(NSURL *)url { |
3145 | [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy]; | |
3146 | } | |
dc5812ec | 3147 | |
36bb2ca2 JF |
3148 | // XXX: this needs to add the headers |
3149 | - (NSURLRequest *) _addHeadersToRequest:(NSURLRequest *)request { | |
3150 | return request; | |
b4d89997 JF |
3151 | } |
3152 | ||
36bb2ca2 JF |
3153 | - (void) loadRequest:(NSURLRequest *)request { |
3154 | [webview_ loadRequest:request]; | |
3155 | } | |
b4d89997 | 3156 | |
36bb2ca2 JF |
3157 | - (void) reloadURL { |
3158 | NSURL *url = [[[urls_ lastObject] retain] autorelease]; | |
3159 | [urls_ removeLastObject]; | |
3160 | [self loadURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData]; | |
3161 | } | |
b4d89997 | 3162 | |
36bb2ca2 JF |
3163 | - (WebView *) webView { |
3164 | return [webview_ webView]; | |
3165 | } | |
b4d89997 | 3166 | |
36bb2ca2 JF |
3167 | - (void) view:(UIView *)sender didSetFrame:(CGRect)frame { |
3168 | [scroller_ setContentSize:frame.size]; | |
3169 | } | |
b4d89997 | 3170 | |
36bb2ca2 JF |
3171 | - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old { |
3172 | [self view:sender didSetFrame:frame]; | |
3173 | } | |
b4d89997 | 3174 | |
36bb2ca2 JF |
3175 | - (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource { |
3176 | return [self _addHeadersToRequest:request]; | |
3177 | } | |
b4d89997 | 3178 | |
36bb2ca2 | 3179 | - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request { |
a07b2a71 JF |
3180 | if ([[[request URL] scheme] isEqualToString:@"apptapp"]) |
3181 | return nil; | |
36bb2ca2 JF |
3182 | [self setBackButtonTitle:title_]; |
3183 | BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease]; | |
3184 | [browser setDelegate:delegate_]; | |
3185 | [book_ pushPage:browser]; | |
3186 | [browser loadRequest:[self _addHeadersToRequest:request]]; | |
3187 | return [browser webView]; | |
3188 | } | |
3189 | ||
3190 | - (void) webView:(WebView *)sender willClickElement:(id)element { | |
3191 | if (![element respondsToSelector:@selector(href)]) | |
3192 | return; | |
3193 | NSString *href = [element href]; | |
3194 | if (href == nil) | |
3195 | return; | |
3196 | if ([href hasPrefix:@"apptapp://package/"]) { | |
3197 | NSString *name = [href substringFromIndex:18]; | |
3198 | Package *package = [database_ packageWithName:name]; | |
3199 | if (package == nil) { | |
3200 | UIAlertSheet *sheet = [[[UIAlertSheet alloc] | |
3201 | initWithTitle:@"Cannot Locate Package" | |
3202 | buttons:[NSArray arrayWithObjects:@"Close", nil] | |
3203 | defaultButtonIndex:0 | |
3204 | delegate:self | |
a54b1c10 | 3205 | context:@"missing" |
36bb2ca2 | 3206 | ] autorelease]; |
b4d89997 | 3207 | |
36bb2ca2 | 3208 | [sheet setBodyText:[NSString stringWithFormat: |
d36e83a3 | 3209 | @"The package %@ cannot be found in your current sources. I might recommend installing more sources." |
36bb2ca2 | 3210 | , name]]; |
b4d89997 | 3211 | |
36bb2ca2 JF |
3212 | [sheet popupAlertAnimated:YES]; |
3213 | } else { | |
3214 | [self setBackButtonTitle:title_]; | |
3215 | PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease]; | |
3216 | [view setDelegate:delegate_]; | |
3217 | [view setPackage:package]; | |
3218 | [book_ pushPage:view]; | |
3219 | } | |
3220 | } | |
dc5812ec JF |
3221 | } |
3222 | ||
36bb2ca2 JF |
3223 | - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame { |
3224 | title_ = [title retain]; | |
3225 | [self setTitle:title]; | |
3226 | } | |
3227 | ||
3228 | - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame { | |
3229 | if ([frame parentFrame] != nil) | |
3230 | return; | |
3231 | ||
1d3b229d | 3232 | reloading_ = false; |
36bb2ca2 JF |
3233 | loading_ = true; |
3234 | [indicator_ startAnimation]; | |
3235 | [self reloadButtons]; | |
3236 | ||
3237 | if (title_ != nil) { | |
3238 | [title_ release]; | |
3239 | title_ = nil; | |
b4d89997 | 3240 | } |
36bb2ca2 JF |
3241 | |
3242 | [self setTitle:@"Loading..."]; | |
3243 | ||
3244 | WebView *webview = [webview_ webView]; | |
3245 | NSString *href = [webview mainFrameURL]; | |
3246 | [urls_ addObject:[NSURL URLWithString:href]]; | |
3247 | ||
3248 | CGRect webrect = [scroller_ frame]; | |
3249 | webrect.size.height = 0; | |
3250 | [webview_ setFrame:webrect]; | |
dc5812ec JF |
3251 | } |
3252 | ||
36bb2ca2 | 3253 | - (void) _finishLoading { |
1d3b229d JF |
3254 | if (!reloading_) { |
3255 | loading_ = false; | |
3256 | [indicator_ stopAnimation]; | |
3257 | [self reloadButtons]; | |
3258 | } | |
36bb2ca2 | 3259 | } |
b4d89997 | 3260 | |
36bb2ca2 JF |
3261 | - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame { |
3262 | if ([frame parentFrame] != nil) | |
3263 | return; | |
3264 | [self _finishLoading]; | |
3265 | } | |
b4d89997 | 3266 | |
36bb2ca2 JF |
3267 | - (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame { |
3268 | if ([frame parentFrame] != nil) | |
3269 | return; | |
3270 | [self setTitle:[error localizedDescription]]; | |
3271 | [self _finishLoading]; | |
3272 | } | |
3273 | ||
3274 | - (id) initWithBook:(RVBook *)book database:(Database *)database { | |
3275 | if ((self = [super initWithBook:book]) != nil) { | |
3276 | database_ = database; | |
3277 | loading_ = false; | |
3278 | ||
3279 | struct CGRect bounds = [self bounds]; | |
3280 | ||
3281 | UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:bounds] autorelease]; | |
3282 | [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]]; | |
3283 | [self addSubview:pinstripe]; | |
3284 | ||
3285 | scroller_ = [[UIScroller alloc] initWithFrame:bounds]; | |
3286 | [self addSubview:scroller_]; | |
3287 | ||
3288 | [scroller_ setScrollingEnabled:YES]; | |
3289 | [scroller_ setAdjustForContentSizeChange:YES]; | |
3290 | [scroller_ setClipsSubviews:YES]; | |
3291 | [scroller_ setAllowsRubberBanding:YES]; | |
3292 | [scroller_ setScrollDecelerationFactor:0.99]; | |
3293 | [scroller_ setDelegate:self]; | |
3294 | ||
3295 | CGRect webrect = [scroller_ bounds]; | |
3296 | webrect.size.height = 0; | |
3297 | ||
3298 | webview_ = [[UIWebView alloc] initWithFrame:webrect]; | |
3299 | [scroller_ addSubview:webview_]; | |
3300 | ||
3301 | [webview_ setTilingEnabled:YES]; | |
3302 | [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)]; | |
3303 | [webview_ setAutoresizes:YES]; | |
3304 | [webview_ setDelegate:self]; | |
3305 | //[webview_ setEnabledGestures:2]; | |
b4d89997 | 3306 | |
36bb2ca2 | 3307 | CGSize indsize = [UIProgressIndicator defaultSizeForStyle:0]; |
a54b1c10 | 3308 | indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 42, indsize.width, indsize.height)]; |
36bb2ca2 JF |
3309 | [indicator_ setStyle:0]; |
3310 | ||
3311 | Package *package([database_ packageWithName:@"cydia"]); | |
3312 | NSString *application = package == nil ? @"Cydia" : [NSString | |
3313 | stringWithFormat:@"Cydia/%@", | |
3314 | [package installed] | |
3315 | ]; | |
3316 | ||
3317 | WebView *webview = [webview_ webView]; | |
3318 | [webview setApplicationNameForUserAgent:application]; | |
3319 | [webview setFrameLoadDelegate:self]; | |
3320 | [webview setResourceLoadDelegate:self]; | |
3321 | [webview setUIDelegate:self]; | |
3322 | ||
3323 | urls_ = [[NSMutableArray alloc] initWithCapacity:16]; | |
3324 | } return self; | |
dc5812ec JF |
3325 | } |
3326 | ||
36bb2ca2 JF |
3327 | - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button { |
3328 | [sheet dismiss]; | |
3329 | } | |
3330 | ||
3331 | - (void) _leftButtonClicked { | |
3332 | UIAlertSheet *sheet = [[[UIAlertSheet alloc] | |
3333 | initWithTitle:@"About Cydia Packager" | |
3334 | buttons:[NSArray arrayWithObjects:@"Close", nil] | |
3335 | defaultButtonIndex:0 | |
3336 | delegate:self | |
a54b1c10 | 3337 | context:@"about" |
36bb2ca2 JF |
3338 | ] autorelease]; |
3339 | ||
3340 | [sheet setBodyText: | |
3341 | @"Copyright (C) 2008\n" | |
3342 | "Jay Freeman (saurik)\n" | |
3343 | "saurik@saurik.com\n" | |
3344 | "http://www.saurik.com/\n" | |
3345 | "\n" | |
3346 | "The Okori Group\n" | |
3347 | "http://www.theokorigroup.com/\n" | |
3348 | "\n" | |
3349 | "College of Creative Studies,\n" | |
3350 | "University of California,\n" | |
3351 | "Santa Barbara\n" | |
3352 | "http://www.ccs.ucsb.edu/" | |
3353 | ]; | |
3354 | ||
3355 | [sheet popupAlertAnimated:YES]; | |
3356 | } | |
3357 | ||
3358 | - (void) _rightButtonClicked { | |
1d3b229d | 3359 | reloading_ = true; |
36bb2ca2 JF |
3360 | [self reloadURL]; |
3361 | } | |
3362 | ||
3363 | - (NSString *) leftButtonTitle { | |
3364 | return @"About"; | |
3365 | } | |
3366 | ||
3367 | - (NSString *) rightButtonTitle { | |
3368 | return loading_ ? @"" : @"Reload"; | |
3369 | } | |
3370 | ||
3371 | - (NSString *) title { | |
3372 | return nil; | |
3373 | } | |
3374 | ||
3375 | - (NSString *) backButtonTitle { | |
3376 | return @"Browser"; | |
dc5812ec JF |
3377 | } |
3378 | ||
36bb2ca2 JF |
3379 | - (void) setPageActive:(BOOL)active { |
3380 | if (active) | |
3381 | [book_ addSubview:indicator_]; | |
3382 | else | |
3383 | [indicator_ removeFromSuperview]; | |
dc5812ec JF |
3384 | } |
3385 | ||
36bb2ca2 | 3386 | - (void) resetViewAnimated:(BOOL)animated { |
b4d89997 | 3387 | } |
2367a917 | 3388 | |
b4d89997 JF |
3389 | @end |
3390 | /* }}} */ | |
36bb2ca2 | 3391 | |
9a7b04c5 JF |
3392 | @interface CYBook : RVBook < |
3393 | ProgressDelegate | |
3394 | > { | |
3395 | _transient Database *database_; | |
3396 | UIView *overlay_; | |
3397 | UIProgressIndicator *indicator_; | |
3398 | UITextLabel *prompt_; | |
3399 | UIProgressBar *progress_; | |
3400 | bool updating_; | |
3401 | } | |
3402 | ||
3403 | - (id) initWithFrame:(CGRect)frame database:(Database *)database; | |
3404 | - (void) update; | |
3405 | - (BOOL) updating; | |
3406 | ||
3407 | @end | |
3408 | ||
b4d89997 | 3409 | /* Install View {{{ */ |
36bb2ca2 JF |
3410 | @interface InstallView : RVPage { |
3411 | _transient Database *database_; | |
b4d89997 | 3412 | NSMutableArray *packages_; |
36bb2ca2 JF |
3413 | NSMutableArray *sections_; |
3414 | UITable *list_; | |
a54b1c10 | 3415 | UIView *accessory_; |
b4d89997 | 3416 | } |
dc5812ec | 3417 | |
36bb2ca2 JF |
3418 | - (id) initWithBook:(RVBook *)book database:(Database *)database; |
3419 | - (void) reloadData; | |
dc5812ec | 3420 | |
2367a917 JF |
3421 | @end |
3422 | ||
b4d89997 | 3423 | @implementation InstallView |
dc5812ec | 3424 | |
2367a917 | 3425 | - (void) dealloc { |
36bb2ca2 JF |
3426 | [list_ setDataSource:nil]; |
3427 | [list_ setDelegate:nil]; | |
3428 | ||
b4d89997 | 3429 | [packages_ release]; |
36bb2ca2 JF |
3430 | [sections_ release]; |
3431 | [list_ release]; | |
a54b1c10 | 3432 | [accessory_ release]; |
2367a917 JF |
3433 | [super dealloc]; |
3434 | } | |
3435 | ||
b4d89997 JF |
3436 | - (int) numberOfRowsInTable:(UITable *)table { |
3437 | return [sections_ count] + 1; | |
3438 | } | |
8da60fb7 | 3439 | |
b4d89997 JF |
3440 | - (float) table:(UITable *)table heightForRow:(int)row { |
3441 | return 45; | |
3442 | } | |
8da60fb7 | 3443 | |
b4d89997 JF |
3444 | - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing { |
3445 | if (reusing == nil) | |
3446 | reusing = [[[SectionCell alloc] init] autorelease]; | |
36bb2ca2 | 3447 | [(SectionCell *)reusing setSection:(row == 0 ? nil : [sections_ objectAtIndex:(row - 1)])]; |
b4d89997 JF |
3448 | return reusing; |
3449 | } | |
dc5812ec | 3450 | |
b4d89997 JF |
3451 | - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row { |
3452 | return YES; | |
3453 | } | |
dc5812ec | 3454 | |
b4d89997 JF |
3455 | - (void) tableRowSelected:(NSNotification *)notification { |
3456 | int row = [[notification object] selectedRow]; | |
36bb2ca2 JF |
3457 | if (row == INT_MAX) |
3458 | return; | |
dc5812ec | 3459 | |
36bb2ca2 | 3460 | Section *section; |
5a09ae08 | 3461 | NSString *name; |
36bb2ca2 | 3462 | NSString *title; |
dc5812ec | 3463 | |
36bb2ca2 JF |
3464 | if (row == 0) { |
3465 | section = nil; | |
5a09ae08 | 3466 | name = nil; |
36bb2ca2 | 3467 | title = @"All Packages"; |
b4d89997 | 3468 | } else { |
36bb2ca2 | 3469 | section = [sections_ objectAtIndex:(row - 1)]; |
5a09ae08 JF |
3470 | name = [section name]; |
3471 | ||
3472 | if (name != nil) | |
3473 | title = name; | |
3474 | else { | |
3475 | name = @""; | |
3476 | title = @"(No Section)"; | |
3477 | } | |
b4d89997 | 3478 | } |
2367a917 | 3479 | |
36bb2ca2 JF |
3480 | PackageTable *table = [[[PackageTable alloc] |
3481 | initWithBook:book_ | |
3482 | database:database_ | |
3483 | title:title | |
3484 | filter:@selector(isUninstalledInSection:) | |
5a09ae08 | 3485 | with:name |
36bb2ca2 | 3486 | ] autorelease]; |
2367a917 | 3487 | |
36bb2ca2 | 3488 | [table setDelegate:delegate_]; |
2367a917 | 3489 | |
36bb2ca2 | 3490 | [book_ pushPage:table]; |
b4d89997 | 3491 | } |
2367a917 | 3492 | |
36bb2ca2 JF |
3493 | - (id) initWithBook:(RVBook *)book database:(Database *)database { |
3494 | if ((self = [super initWithBook:book]) != nil) { | |
3495 | database_ = database; | |
3496 | ||
b4d89997 | 3497 | packages_ = [[NSMutableArray arrayWithCapacity:16] retain]; |
36bb2ca2 | 3498 | sections_ = [[NSMutableArray arrayWithCapacity:16] retain]; |
2367a917 | 3499 | |
36bb2ca2 JF |
3500 | list_ = [[UITable alloc] initWithFrame:[self bounds]]; |
3501 | [self addSubview:list_]; | |
dc5812ec | 3502 | |
b4d89997 JF |
3503 | UITableColumn *column = [[[UITableColumn alloc] |
3504 | initWithTitle:@"Name" | |
3505 | identifier:@"name" | |
36bb2ca2 | 3506 | width:[self frame].size.width |
b4d89997 | 3507 | ] autorelease]; |
dc5812ec | 3508 | |
b4d89997 JF |
3509 | [list_ setDataSource:self]; |
3510 | [list_ setSeparatorStyle:1]; | |
3511 | [list_ addTableColumn:column]; | |
3512 | [list_ setDelegate:self]; | |
3513 | [list_ setReusesTableCells:YES]; | |
2367a917 | 3514 | |
36bb2ca2 | 3515 | [self reloadData]; |
b4d89997 | 3516 | } return self; |
2367a917 JF |
3517 | } |
3518 | ||
36bb2ca2 JF |
3519 | - (void) reloadData { |
3520 | NSArray *packages = [database_ packages]; | |
3521 | ||
b4d89997 | 3522 | [packages_ removeAllObjects]; |
36bb2ca2 | 3523 | [sections_ removeAllObjects]; |
dc5812ec | 3524 | |
b4d89997 JF |
3525 | for (size_t i(0); i != [packages count]; ++i) { |
3526 | Package *package([packages objectAtIndex:i]); | |
5a09ae08 | 3527 | if ([package valid] && [package installed] == nil) |
b4d89997 JF |
3528 | [packages_ addObject:package]; |
3529 | } | |
dc5812ec | 3530 | |
36bb2ca2 | 3531 | [packages_ sortUsingSelector:@selector(compareBySection:)]; |
dc5812ec | 3532 | |
b4d89997 JF |
3533 | Section *section = nil; |
3534 | for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) { | |
3535 | Package *package = [packages_ objectAtIndex:offset]; | |
3536 | NSString *name = [package section]; | |
2367a917 | 3537 | |
36bb2ca2 | 3538 | if (section == nil || name != nil && ![[section name] isEqualToString:name]) { |
b4d89997 | 3539 | section = [[[Section alloc] initWithName:name row:offset] autorelease]; |
36bb2ca2 | 3540 | [sections_ addObject:section]; |
b4d89997 | 3541 | } |
dc5812ec | 3542 | |
36bb2ca2 | 3543 | [section addToCount]; |
b4d89997 | 3544 | } |
2367a917 | 3545 | |
b4d89997 | 3546 | [list_ reloadData]; |
36bb2ca2 | 3547 | } |
2367a917 | 3548 | |
36bb2ca2 JF |
3549 | - (void) resetViewAnimated:(BOOL)animated { |
3550 | [list_ resetViewAnimated:animated]; | |
3551 | } | |
2367a917 | 3552 | |
36bb2ca2 JF |
3553 | - (NSString *) title { |
3554 | return @"Install"; | |
2367a917 JF |
3555 | } |
3556 | ||
36bb2ca2 JF |
3557 | - (NSString *) backButtonTitle { |
3558 | return @"Sections"; | |
dc5812ec JF |
3559 | } |
3560 | ||
a54b1c10 JF |
3561 | - (UIView *) accessoryView { |
3562 | return accessory_; | |
3563 | } | |
3564 | ||
dc5812ec | 3565 | @end |
2367a917 | 3566 | /* }}} */ |
b4d89997 | 3567 | /* Changes View {{{ */ |
36bb2ca2 JF |
3568 | @interface ChangesView : RVPage { |
3569 | _transient Database *database_; | |
dc5812ec JF |
3570 | NSMutableArray *packages_; |
3571 | NSMutableArray *sections_; | |
36bb2ca2 JF |
3572 | UISectionList *list_; |
3573 | unsigned upgrades_; | |
dc5812ec JF |
3574 | } |
3575 | ||
36bb2ca2 JF |
3576 | - (id) initWithBook:(RVBook *)book database:(Database *)database; |
3577 | - (void) reloadData; | |
dc5812ec | 3578 | |
dc5812ec JF |
3579 | @end |
3580 | ||
b4d89997 JF |
3581 | @implementation ChangesView |
3582 | ||
3583 | - (void) dealloc { | |
36bb2ca2 JF |
3584 | [[list_ table] setDelegate:nil]; |
3585 | [list_ setDataSource:nil]; | |
3586 | ||
b4d89997 JF |
3587 | [packages_ release]; |
3588 | [sections_ release]; | |
36bb2ca2 | 3589 | [list_ release]; |
b4d89997 JF |
3590 | [super dealloc]; |
3591 | } | |
dc5812ec JF |
3592 | |
3593 | - (int) numberOfSectionsInSectionList:(UISectionList *)list { | |
3594 | return [sections_ count]; | |
3595 | } | |
3596 | ||
3597 | - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section { | |
3598 | return [[sections_ objectAtIndex:section] name]; | |
3599 | } | |
3600 | ||
3601 | - (int) sectionList:(UISectionList *)list rowForSection:(int)section { | |
3602 | return [[sections_ objectAtIndex:section] row]; | |
3603 | } | |
3604 | ||
3605 | - (int) numberOfRowsInTable:(UITable *)table { | |
3606 | return [packages_ count]; | |
3607 | } | |
3608 | ||
3609 | - (float) table:(UITable *)table heightForRow:(int)row { | |
36bb2ca2 | 3610 | return 73; |
dc5812ec JF |
3611 | } |
3612 | ||
1d80f6b9 JF |
3613 | - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing { |
3614 | if (reusing == nil) | |
36bb2ca2 | 3615 | reusing = [[[PackageCell alloc] init] autorelease]; |
1d80f6b9 JF |
3616 | [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]]; |
3617 | return reusing; | |
dc5812ec JF |
3618 | } |
3619 | ||
3620 | - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row { | |
b4d89997 | 3621 | return NO; |
dc5812ec JF |
3622 | } |
3623 | ||
b4d89997 JF |
3624 | - (void) tableRowSelected:(NSNotification *)notification { |
3625 | int row = [[notification object] selectedRow]; | |
36bb2ca2 JF |
3626 | if (row == INT_MAX) |
3627 | return; | |
3628 | Package *package = [packages_ objectAtIndex:row]; | |
3629 | PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease]; | |
3630 | [view setDelegate:delegate_]; | |
3631 | [view setPackage:package]; | |
3632 | [book_ pushPage:view]; | |
dc5812ec JF |
3633 | } |
3634 | ||
9a7b04c5 JF |
3635 | - (void) _leftButtonClicked { |
3636 | [(CYBook *)book_ update]; | |
3637 | [self reloadButtons]; | |
3638 | } | |
3639 | ||
36bb2ca2 JF |
3640 | - (void) _rightButtonClicked { |
3641 | [delegate_ distUpgrade]; | |
dc5812ec JF |
3642 | } |
3643 | ||
36bb2ca2 JF |
3644 | - (id) initWithBook:(RVBook *)book database:(Database *)database { |
3645 | if ((self = [super initWithBook:book]) != nil) { | |
3646 | database_ = database; | |
dc5812ec | 3647 | |
b4d89997 JF |
3648 | packages_ = [[NSMutableArray arrayWithCapacity:16] retain]; |
3649 | sections_ = [[NSMutableArray arrayWithCapacity:16] retain]; | |
dc5812ec | 3650 | |
36bb2ca2 JF |
3651 | list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO]; |
3652 | [self addSubview:list_]; | |
3653 | ||
3178d79b | 3654 | [list_ setShouldHideHeaderInShortLists:NO]; |
b4d89997 JF |
3655 | [list_ setDataSource:self]; |
3656 | //[list_ setSectionListStyle:1]; | |
dc5812ec | 3657 | |
b4d89997 | 3658 | UITableColumn *column = [[[UITableColumn alloc] |
dc5812ec JF |
3659 | initWithTitle:@"Name" |
3660 | identifier:@"name" | |
36bb2ca2 | 3661 | width:[self frame].size.width |
b4d89997 | 3662 | ] autorelease]; |
dc5812ec JF |
3663 | |
3664 | UITable *table = [list_ table]; | |
3665 | [table setSeparatorStyle:1]; | |
3666 | [table addTableColumn:column]; | |
3667 | [table setDelegate:self]; | |
1d80f6b9 | 3668 | [table setReusesTableCells:YES]; |
dc5812ec | 3669 | |
36bb2ca2 | 3670 | [self reloadData]; |
dc5812ec JF |
3671 | } return self; |
3672 | } | |
3673 | ||
36bb2ca2 JF |
3674 | - (void) reloadData { |
3675 | NSArray *packages = [database_ packages]; | |
3676 | ||
b4d89997 | 3677 | [packages_ removeAllObjects]; |
36bb2ca2 JF |
3678 | [sections_ removeAllObjects]; |
3679 | ||
b4d89997 JF |
3680 | for (size_t i(0); i != [packages count]; ++i) { |
3681 | Package *package([packages objectAtIndex:i]); | |
5a09ae08 | 3682 | if ([package installed] == nil && [package valid] || [package upgradable]) |
b4d89997 JF |
3683 | [packages_ addObject:package]; |
3684 | } | |
2367a917 | 3685 | |
b4d89997 | 3686 | [packages_ sortUsingSelector:@selector(compareForChanges:)]; |
dc5812ec | 3687 | |
b4d89997 | 3688 | Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades" row:0] autorelease]; |
dc5812ec | 3689 | Section *section = nil; |
b4d89997 | 3690 | |
36bb2ca2 JF |
3691 | upgrades_ = 0; |
3692 | bool unseens = false; | |
3693 | ||
3694 | CFLocaleRef locale = CFLocaleCopyCurrent(); | |
3695 | CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle); | |
3696 | ||
dc5812ec JF |
3697 | for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) { |
3698 | Package *package = [packages_ objectAtIndex:offset]; | |
dc5812ec | 3699 | |
36bb2ca2 JF |
3700 | if ([package upgradable]) { |
3701 | ++upgrades_; | |
3702 | [upgradable addToCount]; | |
3703 | } else { | |
3704 | unseens = true; | |
b4d89997 | 3705 | NSDate *seen = [package seen]; |
dc5812ec | 3706 | |
723a0072 | 3707 | NSString *name; |
723a0072 JF |
3708 | |
3709 | if (seen == nil) | |
36bb2ca2 | 3710 | name = [@"n/a ?" retain]; |
723a0072 | 3711 | else { |
36bb2ca2 | 3712 | name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen); |
723a0072 | 3713 | } |
b4d89997 | 3714 | |
36bb2ca2 | 3715 | if (section == nil || ![[section name] isEqualToString:name]) { |
b4d89997 JF |
3716 | section = [[[Section alloc] initWithName:name row:offset] autorelease]; |
3717 | [sections_ addObject:section]; | |
3718 | } | |
3719 | ||
36bb2ca2 JF |
3720 | [name release]; |
3721 | [section addToCount]; | |
b4d89997 | 3722 | } |
dc5812ec JF |
3723 | } |
3724 | ||
36bb2ca2 JF |
3725 | CFRelease(formatter); |
3726 | CFRelease(locale); | |
b4d89997 | 3727 | |
36bb2ca2 JF |
3728 | if (unseens) { |
3729 | Section *last = [sections_ lastObject]; | |
3730 | size_t count = [last count]; | |
3731 | [packages_ removeObjectsInRange:NSMakeRange([packages_ count] - count, count)]; | |
3732 | [sections_ removeLastObject]; | |
3733 | } | |
dc5812ec | 3734 | |
36bb2ca2 JF |
3735 | if (upgrades_ != 0) |
3736 | [sections_ insertObject:upgradable atIndex:0]; | |
c25a610d | 3737 | |
36bb2ca2 JF |
3738 | [list_ reloadData]; |
3739 | [self reloadButtons]; | |
3178d79b JF |
3740 | } |
3741 | ||
36bb2ca2 JF |
3742 | - (void) resetViewAnimated:(BOOL)animated { |
3743 | [list_ resetViewAnimated:animated]; | |
3178d79b JF |
3744 | } |
3745 | ||
9a7b04c5 JF |
3746 | - (NSString *) leftButtonTitle { |
3747 | return [(CYBook *)book_ updating] ? nil : @"Refresh"; | |
3748 | } | |
3749 | ||
36bb2ca2 JF |
3750 | - (NSString *) rightButtonTitle { |
3751 | return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade All (%u)", upgrades_]; | |
3178d79b JF |
3752 | } |
3753 | ||
36bb2ca2 JF |
3754 | - (NSString *) title { |
3755 | return @"Changes"; | |
8fe19fc1 JF |
3756 | } |
3757 | ||
559dec34 JF |
3758 | @end |
3759 | /* }}} */ | |
3760 | /* Manage View {{{ */ | |
3761 | @interface ManageView : PackageTable { | |
3762 | } | |
3763 | ||
3764 | - (id) initWithBook:(RVBook *)book database:(Database *)database; | |
3765 | ||
3766 | @end | |
3767 | ||
3768 | @implementation ManageView | |
3769 | ||
3770 | - (id) initWithBook:(RVBook *)book database:(Database *)database { | |
3771 | if ((self = [super | |
3772 | initWithBook:book | |
3773 | database:database | |
3774 | title:nil | |
3775 | filter:@selector(isInstalledInSection:) | |
3776 | with:nil | |
3777 | ]) != nil) { | |
3778 | } return self; | |
3779 | } | |
3780 | ||
3781 | - (NSString *) title { | |
3782 | return @"Installed Packages"; | |
3783 | } | |
3784 | ||
3785 | - (NSString *) backButtonTitle { | |
3786 | return @"All Packages"; | |
3787 | } | |
3788 | ||
3178d79b JF |
3789 | @end |
3790 | /* }}} */ | |
36bb2ca2 JF |
3791 | /* Search View {{{ */ |
3792 | @protocol SearchViewDelegate | |
3793 | - (void) showKeyboard:(BOOL)show; | |
3794 | @end | |
b4d89997 | 3795 | |
a0be02eb | 3796 | @interface SearchView : RVPage { |
36bb2ca2 JF |
3797 | UIView *accessory_; |
3798 | UISearchField *field_; | |
a0be02eb JF |
3799 | UITransitionView *transition_; |
3800 | PackageTable *table_; | |
3801 | UIPreferencesTable *advanced_; | |
9b619239 | 3802 | UIView *dimmed_; |
a0be02eb | 3803 | bool flipped_; |
ab398adf | 3804 | bool reload_; |
36bb2ca2 | 3805 | } |
b4d89997 | 3806 | |
36bb2ca2 JF |
3807 | - (id) initWithBook:(RVBook *)book database:(Database *)database; |
3808 | - (void) reloadData; | |
b4d89997 | 3809 | |
3178d79b JF |
3810 | @end |
3811 | ||
36bb2ca2 | 3812 | @implementation SearchView |
3178d79b | 3813 | |
b4d89997 | 3814 | - (void) dealloc { |
36bb2ca2 JF |
3815 | #ifndef __OBJC2__ |
3816 | [[field_ textTraits] setEditingDelegate:nil]; | |
3817 | #endif | |
3818 | [field_ setDelegate:nil]; | |
3178d79b | 3819 | |
36bb2ca2 JF |
3820 | [accessory_ release]; |
3821 | [field_ release]; | |
a0be02eb JF |
3822 | [transition_ release]; |
3823 | [table_ release]; | |
3824 | [advanced_ release]; | |
9b619239 | 3825 | [dimmed_ release]; |
36bb2ca2 | 3826 | [super dealloc]; |
b4d89997 JF |
3827 | } |
3828 | ||
ab398adf JF |
3829 | - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table { |
3830 | return 1; | |
3831 | } | |
3832 | ||
3833 | - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group { | |
3834 | switch (group) { | |
3835 | case 0: return @"Advanced Search (Coming Soon!)"; | |
3836 | ||
3837 | default: _assert(false); | |
3838 | } | |
3839 | } | |
3840 | ||
3841 | - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group { | |
3842 | switch (group) { | |
3843 | case 0: return 0; | |
3844 | ||
3845 | default: _assert(false); | |
3846 | } | |
3847 | } | |
3848 | ||
2388b078 JF |
3849 | - (void) _showKeyboard:(BOOL)show { |
3850 | CGSize keysize = [UIKeyboard defaultSize]; | |
3851 | CGRect keydown = [book_ pageBounds]; | |
3852 | CGRect keyup = keydown; | |
3853 | keyup.size.height -= keysize.height - ButtonBarHeight_; | |
3854 | ||
3855 | float delay = KeyboardTime_ * ButtonBarHeight_ / keysize.height; | |
3856 | ||
3857 | UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:[table_ list]] autorelease]; | |
3858 | [animation setSignificantRectFields:8]; | |
3859 | ||
3860 | if (show) { | |
3861 | [animation setStartFrame:keydown]; | |
3862 | [animation setEndFrame:keyup]; | |
3863 | } else { | |
3864 | [animation setStartFrame:keyup]; | |
3865 | [animation setEndFrame:keydown]; | |
3866 | } | |
3867 | ||
3868 | UIAnimator *animator = [UIAnimator sharedAnimator]; | |
3869 | ||
3870 | [animator | |
3871 | addAnimations:[NSArray arrayWithObjects:animation, nil] | |
3872 | withDuration:(KeyboardTime_ - delay) | |
3873 | start:!show | |
3874 | ]; | |
3875 | ||
3876 | if (show) | |
3877 | [animator performSelector:@selector(startAnimation:) withObject:animation afterDelay:delay]; | |
3878 | ||
3879 | [delegate_ showKeyboard:show]; | |
3880 | } | |
3881 | ||
36bb2ca2 | 3882 | - (void) textFieldDidBecomeFirstResponder:(UITextField *)field { |
2388b078 | 3883 | [self _showKeyboard:YES]; |
36bb2ca2 | 3884 | } |
b4d89997 | 3885 | |
36bb2ca2 | 3886 | - (void) textFieldDidResignFirstResponder:(UITextField *)field { |
2388b078 | 3887 | [self _showKeyboard:NO]; |
36bb2ca2 | 3888 | } |
b4d89997 | 3889 | |
36bb2ca2 | 3890 | - (void) keyboardInputChanged:(UIFieldEditor *)editor { |
ab398adf JF |
3891 | if (reload_) { |
3892 | NSString *text([field_ text]); | |
3893 | [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)]; | |
3894 | [self reloadData]; | |
3895 | reload_ = false; | |
3896 | } | |
3897 | } | |
3898 | ||
3899 | - (void) textFieldClearButtonPressed:(UITextField *)field { | |
3900 | reload_ = true; | |
3901 | } | |
3902 | ||
3903 | - (void) keyboardInputShouldDelete:(id)input { | |
3904 | reload_ = true; | |
36bb2ca2 | 3905 | } |
b4d89997 | 3906 | |
36bb2ca2 | 3907 | - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked { |
ab398adf JF |
3908 | if ([text length] != 1 || [text characterAtIndex:0] != '\n') { |
3909 | reload_ = true; | |
36bb2ca2 | 3910 | return YES; |
ab398adf JF |
3911 | } else { |
3912 | [field_ resignFirstResponder]; | |
3913 | return NO; | |
3914 | } | |
b4d89997 JF |
3915 | } |
3916 | ||
36bb2ca2 | 3917 | - (id) initWithBook:(RVBook *)book database:(Database *)database { |
a0be02eb JF |
3918 | if ((self = [super initWithBook:book]) != nil) { |
3919 | CGRect pageBounds = [book_ pageBounds]; | |
3920 | ||
7fea16f2 | 3921 | /*UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:pageBounds] autorelease]; |
a0be02eb | 3922 | [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]]; |
7fea16f2 | 3923 | [self addSubview:pinstripe];*/ |
a0be02eb | 3924 | |
a0be02eb JF |
3925 | transition_ = [[UITransitionView alloc] initWithFrame:pageBounds]; |
3926 | [self addSubview:transition_]; | |
3927 | ||
3928 | advanced_ = [[UIPreferencesTable alloc] initWithFrame:pageBounds]; | |
3929 | ||
ab398adf JF |
3930 | [advanced_ setReusesTableCells:YES]; |
3931 | [advanced_ setDataSource:self]; | |
3932 | [advanced_ reloadData]; | |
3933 | ||
9b619239 JF |
3934 | dimmed_ = [[UIView alloc] initWithFrame:pageBounds]; |
3935 | CGColor dimmed(space_, 0, 0, 0, 0.5); | |
3936 | [dimmed_ setBackgroundColor:dimmed]; | |
3937 | ||
a0be02eb JF |
3938 | table_ = [[PackageTable alloc] |
3939 | initWithBook:book | |
3940 | database:database | |
3941 | title:nil | |
3942 | filter:@selector(isSearchedForBy:) | |
3943 | with:nil | |
3944 | ]; | |
3945 | ||
ab398adf | 3946 | [table_ setShouldHideHeaderInShortLists:NO]; |
a0be02eb JF |
3947 | [transition_ transition:0 toView:table_]; |
3948 | ||
1d3b229d | 3949 | CGRect cnfrect = {{1, 38}, {17, 18}}; |
b4d89997 | 3950 | |
36bb2ca2 | 3951 | CGRect area; |
1d3b229d | 3952 | area.origin.x = cnfrect.size.width + 15; |
36bb2ca2 | 3953 | area.origin.y = 30; |
9a7b04c5 | 3954 | area.size.width = [self bounds].size.width - area.origin.x - 18; |
36bb2ca2 | 3955 | area.size.height = [UISearchField defaultHeight]; |
3178d79b | 3956 | |
36bb2ca2 | 3957 | field_ = [[UISearchField alloc] initWithFrame:area]; |
b4d89997 | 3958 | |
36bb2ca2 JF |
3959 | GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16); |
3960 | [field_ setFont:font]; | |
3961 | CFRelease(font); | |
b4d89997 | 3962 | |
36bb2ca2 JF |
3963 | [field_ setPlaceholder:@"Package Names & Descriptions"]; |
3964 | [field_ setPaddingTop:5]; | |
3965 | [field_ setDelegate:self]; | |
b4d89997 | 3966 | |
36bb2ca2 JF |
3967 | #ifndef __OBJC2__ |
3968 | UITextTraits *traits = [field_ textTraits]; | |
3969 | [traits setEditingDelegate:self]; | |
3970 | [traits setReturnKeyType:6]; | |
3971 | [traits setAutoCapsType:0]; | |
3972 | [traits setAutoCorrectionType:1]; | |
3973 | #endif | |
b4d89997 | 3974 | |
36bb2ca2 JF |
3975 | UIPushButton *configure = [[[UIPushButton alloc] initWithFrame:cnfrect] autorelease]; |
3976 | [configure setShowPressFeedback:YES]; | |
559dec34 | 3977 | [configure setImage:[UIImage applicationImageNamed:@"advanced.png"]]; |
36bb2ca2 | 3978 | [configure addTarget:self action:@selector(configurePushed) forEvents:1]; |
b4d89997 | 3979 | |
36bb2ca2 JF |
3980 | accessory_ = [[UIView alloc] initWithFrame:CGRectMake(0, 6, cnfrect.size.width + area.size.width + 6 * 3, area.size.height + 30)]; |
3981 | [accessory_ addSubview:field_]; | |
3982 | [accessory_ addSubview:configure]; | |
3983 | } return self; | |
3178d79b JF |
3984 | } |
3985 | ||
a0be02eb JF |
3986 | - (void) flipPage { |
3987 | LKAnimation *animation = [LKTransition animation]; | |
3988 | [animation setType:@"oglFlip"]; | |
3989 | [animation setTimingFunction:[LKTimingFunction functionWithName:@"easeInEaseOut"]]; | |
3990 | [animation setFillMode:@"extended"]; | |
3991 | [animation setTransitionFlags:3]; | |
3992 | [animation setDuration:10]; | |
3993 | [animation setSpeed:0.35]; | |
7fea16f2 JF |
3994 | [animation setSubtype:(flipped_ ? @"fromLeft" : @"fromRight")]; |
3995 | [[transition_ _layer] addAnimation:animation forKey:0]; | |
a0be02eb JF |
3996 | [transition_ transition:0 toView:(flipped_ ? (UIView *) table_ : (UIView *) advanced_)]; |
3997 | flipped_ = !flipped_; | |
3998 | } | |
3999 | ||
36bb2ca2 | 4000 | - (void) configurePushed { |
a0be02eb JF |
4001 | [field_ resignFirstResponder]; |
4002 | [self flipPage]; | |
4003 | } | |
4004 | ||
4005 | - (void) resetViewAnimated:(BOOL)animated { | |
4006 | if (flipped_) | |
4007 | [self flipPage]; | |
4008 | [table_ resetViewAnimated:animated]; | |
8fe19fc1 JF |
4009 | } |
4010 | ||
36bb2ca2 | 4011 | - (void) reloadData { |
a0be02eb JF |
4012 | if (flipped_) |
4013 | [self flipPage]; | |
4014 | [table_ setObject:[field_ text]]; | |
4015 | [table_ reloadData]; | |
4016 | [table_ resetCursor]; | |
3178d79b JF |
4017 | } |
4018 | ||
36bb2ca2 JF |
4019 | - (UIView *) accessoryView { |
4020 | return accessory_; | |
4021 | } | |
b4d89997 | 4022 | |
a0be02eb JF |
4023 | - (NSString *) title { |
4024 | return nil; | |
4025 | } | |
4026 | ||
36bb2ca2 JF |
4027 | - (NSString *) backButtonTitle { |
4028 | return @"Search"; | |
4029 | } | |
74127566 | 4030 | |
51e95165 JF |
4031 | - (void) setDelegate:(id)delegate { |
4032 | [table_ setDelegate:delegate]; | |
4033 | [super setDelegate:delegate]; | |
4034 | } | |
4035 | ||
3178d79b | 4036 | @end |
36bb2ca2 | 4037 | /* }}} */ |
3178d79b | 4038 | |
36bb2ca2 | 4039 | @implementation CYBook |
b4d89997 | 4040 | |
36bb2ca2 JF |
4041 | - (void) dealloc { |
4042 | [overlay_ release]; | |
4043 | [indicator_ release]; | |
4044 | [prompt_ release]; | |
4045 | [progress_ release]; | |
4046 | [super dealloc]; | |
4047 | } | |
b4d89997 | 4048 | |
7e9a36b6 JF |
4049 | - (NSString *) getTitleForPage:(RVPage *)page { |
4050 | return Simplify([super getTitleForPage:page]); | |
4051 | } | |
4052 | ||
9a7b04c5 JF |
4053 | - (BOOL) updating { |
4054 | return updating_; | |
4055 | } | |
4056 | ||
36bb2ca2 | 4057 | - (void) update { |
9a7b04c5 | 4058 | [navbar_ setPrompt:@""]; |
36bb2ca2 JF |
4059 | [navbar_ addSubview:overlay_]; |
4060 | [indicator_ startAnimation]; | |
4061 | [prompt_ setText:@"Updating Database..."]; | |
4062 | [progress_ setProgress:0]; | |
b4d89997 | 4063 | |
9a7b04c5 JF |
4064 | updating_ = true; |
4065 | ||
36bb2ca2 JF |
4066 | [NSThread |
4067 | detachNewThreadSelector:@selector(_update) | |
4068 | toTarget:self | |
4069 | withObject:nil | |
4070 | ]; | |
3178d79b JF |
4071 | } |
4072 | ||
36bb2ca2 | 4073 | - (void) _update_ { |
9a7b04c5 JF |
4074 | updating_ = false; |
4075 | ||
36bb2ca2 JF |
4076 | [overlay_ removeFromSuperview]; |
4077 | [indicator_ stopAnimation]; | |
4078 | [delegate_ reloadData]; | |
b4d89997 | 4079 | |
36bb2ca2 | 4080 | [self setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]]; |
3178d79b JF |
4081 | } |
4082 | ||
36bb2ca2 JF |
4083 | - (id) initWithFrame:(CGRect)frame database:(Database *)database { |
4084 | if ((self = [super initWithFrame:frame]) != nil) { | |
4085 | database_ = database; | |
3178d79b | 4086 | |
2388b078 JF |
4087 | if (Advanced_) |
4088 | [navbar_ setBarStyle:1]; | |
4089 | ||
36bb2ca2 JF |
4090 | CGRect ovrrect = [navbar_ bounds]; |
4091 | ovrrect.size.height = [UINavigationBar defaultSizeWithPrompt].height - [UINavigationBar defaultSize].height; | |
3178d79b | 4092 | |
36bb2ca2 | 4093 | overlay_ = [[UIView alloc] initWithFrame:ovrrect]; |
b4d89997 | 4094 | |
36bb2ca2 JF |
4095 | CGSize indsize = [UIProgressIndicator defaultSizeForStyle:2]; |
4096 | unsigned indoffset = (ovrrect.size.height - indsize.height) / 2; | |
4097 | CGRect indrect = {{indoffset, indoffset}, indsize}; | |
8fe19fc1 | 4098 | |
36bb2ca2 | 4099 | indicator_ = [[UIProgressIndicator alloc] initWithFrame:indrect]; |
2388b078 | 4100 | [indicator_ setStyle:(Advanced_ ? 2 : 3)]; |
36bb2ca2 | 4101 | [overlay_ addSubview:indicator_]; |
b4d89997 | 4102 | |
36bb2ca2 | 4103 | CGSize prmsize = {200, indsize.width}; |
b4d89997 | 4104 | |
36bb2ca2 JF |
4105 | CGRect prmrect = {{ |
4106 | indoffset * 2 + indsize.width, | |
4107 | (ovrrect.size.height - prmsize.height) / 2 | |
4108 | }, prmsize}; | |
b4d89997 | 4109 | |
36bb2ca2 | 4110 | GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12); |
b4d89997 | 4111 | |
36bb2ca2 | 4112 | prompt_ = [[UITextLabel alloc] initWithFrame:prmrect]; |
b4d89997 | 4113 | |
2388b078 | 4114 | [prompt_ setColor:(Advanced_ ? White_ : Black_)]; |
36bb2ca2 JF |
4115 | [prompt_ setBackgroundColor:Clear_]; |
4116 | [prompt_ setFont:font]; | |
b4d89997 | 4117 | |
36bb2ca2 | 4118 | CFRelease(font); |
b4d89997 | 4119 | |
36bb2ca2 | 4120 | [overlay_ addSubview:prompt_]; |
b4d89997 | 4121 | |
36bb2ca2 | 4122 | CGSize prgsize = {75, 100}; |
b4d89997 | 4123 | |
36bb2ca2 JF |
4124 | CGRect prgrect = {{ |
4125 | ovrrect.size.width - prgsize.width - 10, | |
4126 | (ovrrect.size.height - prgsize.height) / 2 | |
4127 | } , prgsize}; | |
4128 | ||
4129 | progress_ = [[UIProgressBar alloc] initWithFrame:prgrect]; | |
4130 | [progress_ setStyle:0]; | |
4131 | [overlay_ addSubview:progress_]; | |
b4d89997 | 4132 | } return self; |
3178d79b JF |
4133 | } |
4134 | ||
36bb2ca2 JF |
4135 | - (void) _update { |
4136 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
dc5812ec | 4137 | |
36bb2ca2 JF |
4138 | Status status; |
4139 | status.setDelegate(self); | |
b4d89997 | 4140 | |
36bb2ca2 | 4141 | [database_ updateWithStatus:status]; |
3178d79b | 4142 | |
36bb2ca2 JF |
4143 | [self |
4144 | performSelectorOnMainThread:@selector(_update_) | |
4145 | withObject:nil | |
4146 | waitUntilDone:NO | |
4147 | ]; | |
b4d89997 | 4148 | |
36bb2ca2 | 4149 | [pool release]; |
dc5812ec JF |
4150 | } |
4151 | ||
36bb2ca2 JF |
4152 | - (void) setProgressError:(NSString *)error { |
4153 | [self | |
4154 | performSelectorOnMainThread:@selector(_setProgressError:) | |
4155 | withObject:error | |
4156 | waitUntilDone:YES | |
4157 | ]; | |
dc5812ec JF |
4158 | } |
4159 | ||
36bb2ca2 JF |
4160 | - (void) setProgressTitle:(NSString *)title { |
4161 | [self | |
4162 | performSelectorOnMainThread:@selector(_setProgressTitle:) | |
4163 | withObject:title | |
4164 | waitUntilDone:YES | |
4165 | ]; | |
3178d79b JF |
4166 | } |
4167 | ||
36bb2ca2 JF |
4168 | - (void) setProgressPercent:(float)percent { |
4169 | } | |
b4d89997 | 4170 | |
36bb2ca2 JF |
4171 | - (void) addProgressOutput:(NSString *)output { |
4172 | [self | |
4173 | performSelectorOnMainThread:@selector(_addProgressOutput:) | |
4174 | withObject:output | |
4175 | waitUntilDone:YES | |
4176 | ]; | |
4177 | } | |
b4d89997 | 4178 | |
36bb2ca2 JF |
4179 | - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button { |
4180 | [sheet dismiss]; | |
4181 | } | |
4182 | ||
4183 | - (void) _setProgressError:(NSString *)error { | |
4184 | [prompt_ setText:[NSString stringWithFormat:@"Error: %@", error]]; | |
4185 | } | |
4186 | ||
4187 | - (void) _setProgressTitle:(NSString *)title { | |
4188 | [prompt_ setText:[title stringByAppendingString:@"..."]]; | |
4189 | } | |
b4d89997 | 4190 | |
36bb2ca2 | 4191 | - (void) _addProgressOutput:(NSString *)output { |
8fe19fc1 JF |
4192 | } |
4193 | ||
3178d79b | 4194 | @end |
3178d79b | 4195 | |
2367a917 | 4196 | @interface Cydia : UIApplication < |
3178d79b | 4197 | ConfirmationViewDelegate, |
b4d89997 | 4198 | ProgressViewDelegate, |
5f6bff8c JF |
4199 | SearchViewDelegate, |
4200 | CydiaDelegate | |
2367a917 | 4201 | > { |
dc5812ec | 4202 | UIWindow *window_; |
36bb2ca2 | 4203 | |
3178d79b JF |
4204 | UIView *underlay_; |
4205 | UIView *overlay_; | |
36bb2ca2 | 4206 | CYBook *book_; |
2367a917 | 4207 | UIButtonBar *buttonbar_; |
3178d79b | 4208 | |
3178d79b | 4209 | ConfirmationView *confirm_; |
a54b1c10 | 4210 | NSMutableArray *essential_; |
dc5812ec JF |
4211 | |
4212 | Database *database_; | |
4213 | ProgressView *progress_; | |
4214 | ||
06aa974d | 4215 | unsigned tag_; |
b4d89997 JF |
4216 | |
4217 | UIKeyboard *keyboard_; | |
9b619239 JF |
4218 | |
4219 | InstallView *install_; | |
4220 | ChangesView *changes_; | |
4221 | ManageView *manage_; | |
4222 | SearchView *search_; | |
dc5812ec JF |
4223 | } |
4224 | ||
dc5812ec JF |
4225 | @end |
4226 | ||
4227 | @implementation Cydia | |
4228 | ||
36bb2ca2 JF |
4229 | - (void) _reloadData { |
4230 | /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_]; | |
4231 | [hud setText:@"Reloading Data"]; | |
4232 | [overlay_ addSubview:hud]; | |
4233 | [hud show:YES];*/ | |
dc5812ec | 4234 | |
dc5812ec | 4235 | [database_ reloadData]; |
c25a610d | 4236 | |
b4d89997 | 4237 | if (Packages_ == nil) { |
bbb879fb | 4238 | Packages_ = [[NSMutableDictionary alloc] initWithCapacity:128]; |
b4d89997 JF |
4239 | [Metadata_ setObject:Packages_ forKey:@"Packages"]; |
4240 | } | |
4241 | ||
36bb2ca2 | 4242 | size_t changes(0); |
a54b1c10 | 4243 | [essential_ removeAllObjects]; |
b4d89997 | 4244 | |
36bb2ca2 JF |
4245 | NSArray *packages = [database_ packages]; |
4246 | for (int i(0), e([packages count]); i != e; ++i) { | |
4247 | Package *package = [packages objectAtIndex:i]; | |
a54b1c10 JF |
4248 | if ([package upgradable]) { |
4249 | if ([package essential]) | |
4250 | [essential_ addObject:package]; | |
36bb2ca2 | 4251 | ++changes; |
a54b1c10 | 4252 | } |
36bb2ca2 | 4253 | } |
b4d89997 | 4254 | |
36bb2ca2 JF |
4255 | if (changes != 0) { |
4256 | NSString *badge([[NSNumber numberWithInt:changes] stringValue]); | |
c25a610d | 4257 | [buttonbar_ setBadgeValue:badge forButton:3]; |
9e98e020 JF |
4258 | if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)]) |
4259 | [buttonbar_ setBadgeAnimated:YES forButton:3]; | |
c25a610d JF |
4260 | [self setApplicationBadge:badge]; |
4261 | } else { | |
4262 | [buttonbar_ setBadgeValue:nil forButton:3]; | |
9e98e020 JF |
4263 | if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)]) |
4264 | [buttonbar_ setBadgeAnimated:NO forButton:3]; | |
c25a610d JF |
4265 | [self removeApplicationBadge]; |
4266 | } | |
b4d89997 | 4267 | |
bbb879fb JF |
4268 | if (Changed_) { |
4269 | _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES); | |
4270 | Changed_ = false; | |
4271 | } | |
36bb2ca2 | 4272 | |
9b619239 JF |
4273 | /* XXX: this is just stupid */ |
4274 | if (tag_ != 2) | |
4275 | [install_ reloadData]; | |
4276 | if (tag_ != 3) | |
4277 | [changes_ reloadData]; | |
4278 | if (tag_ != 4) | |
4279 | [manage_ reloadData]; | |
4280 | if (tag_ != 5) | |
4281 | [search_ reloadData]; | |
4282 | ||
36bb2ca2 | 4283 | [book_ reloadData]; |
bbb879fb | 4284 | |
5a09ae08 JF |
4285 | if ([packages count] == 0); |
4286 | else if (!Loaded_) { | |
a54b1c10 | 4287 | Loaded_ = YES; |
5a09ae08 JF |
4288 | [book_ update]; |
4289 | } else if (!Ignored_ && [essential_ count] != 0) { | |
a54b1c10 JF |
4290 | int count = [essential_ count]; |
4291 | ||
4292 | UIAlertSheet *sheet = [[[UIAlertSheet alloc] | |
4293 | initWithTitle:[NSString stringWithFormat:@"%d Essential Upgrade%@", count, (count == 1 ? @"" : @"s")] | |
4294 | buttons:[NSArray arrayWithObjects:@"Upgrade Essential", @"Ignore (Temporary)", nil] | |
4295 | defaultButtonIndex:0 | |
4296 | delegate:self | |
4297 | context:@"upgrade" | |
4298 | ] autorelease]; | |
4299 | ||
4300 | [sheet setBodyText:@"One or more essential packages are currently out of date. If these packages are not upgraded you are likely to encounter errors."]; | |
4301 | [sheet popupAlertAnimated:YES]; | |
4302 | } | |
4303 | ||
36bb2ca2 JF |
4304 | /*[hud show:NO]; |
4305 | [hud removeFromSuperview];*/ | |
b4d89997 JF |
4306 | } |
4307 | ||
36bb2ca2 JF |
4308 | - (void) reloadData { |
4309 | @synchronized (self) { | |
4310 | if (confirm_ == nil) | |
4311 | [self _reloadData]; | |
4312 | } | |
b4d89997 JF |
4313 | } |
4314 | ||
4315 | - (void) resolve { | |
4316 | pkgProblemResolver *resolver = [database_ resolver]; | |
4317 | ||
4318 | resolver->InstallProtect(); | |
4319 | if (!resolver->Resolve(true)) | |
4320 | _error->Discard(); | |
2367a917 JF |
4321 | } |
4322 | ||
4323 | - (void) perform { | |
8fe19fc1 | 4324 | [database_ prepare]; |
49048579 JF |
4325 | |
4326 | if ([database_ cache]->BrokenCount() == 0) | |
4327 | confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self]; | |
4328 | else { | |
4329 | NSMutableArray *broken = [NSMutableArray arrayWithCapacity:16]; | |
4330 | NSArray *packages = [database_ packages]; | |
4331 | ||
4332 | for (size_t i(0); i != [packages count]; ++i) { | |
4333 | Package *package = [packages objectAtIndex:i]; | |
4334 | if ([package broken]) | |
4335 | [broken addObject:[package name]]; | |
4336 | } | |
4337 | ||
4338 | UIAlertSheet *sheet = [[[UIAlertSheet alloc] | |
4339 | initWithTitle:[NSString stringWithFormat:@"%d Broken Packages", [database_ cache]->BrokenCount()] | |
4340 | buttons:[NSArray arrayWithObjects:@"Okay", nil] | |
4341 | defaultButtonIndex:0 | |
4342 | delegate:self | |
a54b1c10 | 4343 | context:@"broken" |
49048579 JF |
4344 | ] autorelease]; |
4345 | ||
4346 | [sheet setBodyText:[NSString stringWithFormat:@"The following packages have unmet dependencies:\n\n%@", [broken componentsJoinedByString:@"\n"]]]; | |
4347 | [sheet popupAlertAnimated:YES]; | |
4348 | ||
36bb2ca2 | 4349 | [self _reloadData]; |
49048579 | 4350 | } |
3178d79b JF |
4351 | } |
4352 | ||
36bb2ca2 JF |
4353 | - (void) installPackage:(Package *)package { |
4354 | @synchronized (self) { | |
4355 | [package install]; | |
4356 | [self resolve]; | |
4357 | [self perform]; | |
4358 | } | |
4359 | } | |
4360 | ||
4361 | - (void) removePackage:(Package *)package { | |
4362 | @synchronized (self) { | |
4363 | [package remove]; | |
4364 | [self resolve]; | |
4365 | [self perform]; | |
4366 | } | |
4367 | } | |
4368 | ||
4369 | - (void) distUpgrade { | |
4370 | @synchronized (self) { | |
4371 | [database_ upgrade]; | |
4372 | [self perform]; | |
4373 | } | |
b4d89997 JF |
4374 | } |
4375 | ||
3178d79b | 4376 | - (void) cancel { |
36bb2ca2 JF |
4377 | @synchronized (self) { |
4378 | [confirm_ release]; | |
4379 | confirm_ = nil; | |
4380 | [self _reloadData]; | |
4381 | } | |
3178d79b JF |
4382 | } |
4383 | ||
4384 | - (void) confirm { | |
4385 | [overlay_ removeFromSuperview]; | |
b4d89997 | 4386 | restart_ = true; |
3178d79b | 4387 | |
2367a917 JF |
4388 | [progress_ |
4389 | detachNewThreadSelector:@selector(perform) | |
4390 | toTarget:database_ | |
4391 | withObject:nil | |
b4d89997 | 4392 | title:@"Running..." |
2367a917 JF |
4393 | ]; |
4394 | } | |
4395 | ||
b31b87cc JF |
4396 | - (void) bootstrap_ { |
4397 | [database_ update]; | |
4398 | [database_ upgrade]; | |
4399 | [database_ prepare]; | |
4400 | [database_ perform]; | |
4401 | } | |
4402 | ||
4403 | - (void) bootstrap { | |
4404 | [progress_ | |
4405 | detachNewThreadSelector:@selector(bootstrap_) | |
4406 | toTarget:self | |
4407 | withObject:nil | |
4408 | title:@"Bootstrap Install..." | |
4409 | ]; | |
4410 | } | |
4411 | ||
2367a917 | 4412 | - (void) progressViewIsComplete:(ProgressView *)progress { |
36bb2ca2 JF |
4413 | @synchronized (self) { |
4414 | [self _reloadData]; | |
4415 | ||
4416 | if (confirm_ != nil) { | |
4417 | [underlay_ addSubview:overlay_]; | |
4418 | [confirm_ removeFromSuperview]; | |
4419 | [confirm_ release]; | |
4420 | confirm_ = nil; | |
4421 | } | |
3178d79b | 4422 | } |
dc5812ec JF |
4423 | } |
4424 | ||
36bb2ca2 | 4425 | - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button { |
a54b1c10 JF |
4426 | NSString *context = [sheet context]; |
4427 | if ([context isEqualToString:@"upgrade"]) | |
4428 | switch (button) { | |
4429 | case 1: | |
4430 | @synchronized (self) { | |
4431 | for (int i = 0, e = [essential_ count]; i != e; ++i) { | |
4432 | Package *essential = [essential_ objectAtIndex:i]; | |
4433 | [essential install]; | |
4434 | } | |
4435 | ||
4436 | [self resolve]; | |
4437 | [self perform]; | |
4438 | } | |
4439 | break; | |
4440 | ||
4441 | case 2: | |
4442 | Ignored_ = YES; | |
4443 | break; | |
4444 | ||
4445 | default: _assert(false); | |
4446 | } | |
4447 | ||
36bb2ca2 JF |
4448 | [sheet dismiss]; |
4449 | } | |
2367a917 | 4450 | |
36bb2ca2 | 4451 | - (void) setPage:(RVPage *)page { |
9b619239 | 4452 | [page resetViewAnimated:NO]; |
36bb2ca2 JF |
4453 | [page setDelegate:self]; |
4454 | [book_ setPage:page]; | |
dc5812ec JF |
4455 | } |
4456 | ||
9b619239 | 4457 | - (RVPage *) _setHomePage { |
36bb2ca2 JF |
4458 | BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease]; |
4459 | [self setPage:browser]; | |
4460 | [browser loadURL:[NSURL URLWithString:@"http://cydia.saurik.com/"]]; | |
4461 | return browser; | |
2367a917 JF |
4462 | } |
4463 | ||
dc5812ec | 4464 | - (void) buttonBarItemTapped:(id)sender { |
06aa974d | 4465 | unsigned tag = [sender tag]; |
559dec34 JF |
4466 | if (tag == tag_) { |
4467 | [book_ resetViewAnimated:YES]; | |
4468 | return; | |
4469 | } | |
dc5812ec | 4470 | |
06aa974d | 4471 | switch (tag) { |
11108eb6 | 4472 | case 1: [self _setHomePage]; break; |
36bb2ca2 | 4473 | |
11108eb6 JF |
4474 | case 2: [self setPage:install_]; break; |
4475 | case 3: [self setPage:changes_]; break; | |
4476 | case 4: [self setPage:manage_]; break; | |
4477 | case 5: [self setPage:search_]; break; | |
36bb2ca2 | 4478 | |
11108eb6 | 4479 | default: _assert(false); |
dc5812ec JF |
4480 | } |
4481 | ||
06aa974d | 4482 | tag_ = tag; |
06aa974d JF |
4483 | } |
4484 | ||
b4d89997 | 4485 | - (void) applicationWillSuspend { |
36bb2ca2 JF |
4486 | [super applicationWillSuspend]; |
4487 | ||
b4d89997 | 4488 | if (restart_) |
ec97ef06 JF |
4489 | if (FW_LEAST(1,1,3)) |
4490 | notify_post("com.apple.language.changed"); | |
4491 | else | |
4492 | system("launchctl stop com.apple.SpringBoard"); | |
b4d89997 JF |
4493 | } |
4494 | ||
dc5812ec JF |
4495 | - (void) applicationDidFinishLaunching:(id)unused { |
4496 | _assert(pkgInitConfig(*_config)); | |
4497 | _assert(pkgInitSystem(*_config, _system)); | |
4498 | ||
3178d79b | 4499 | confirm_ = nil; |
06aa974d | 4500 | tag_ = 1; |
3178d79b | 4501 | |
a54b1c10 JF |
4502 | essential_ = [[NSMutableArray alloc] initWithCapacity:4]; |
4503 | ||
dc5812ec JF |
4504 | CGRect screenrect = [UIHardware fullScreenApplicationContentRect]; |
4505 | window_ = [[UIWindow alloc] initWithContentRect:screenrect]; | |
4506 | ||
4507 | [window_ orderFront: self]; | |
4508 | [window_ makeKey: self]; | |
4509 | [window_ _setHidden: NO]; | |
4510 | ||
8b29f8e6 JF |
4511 | database_ = [[Database alloc] init]; |
4512 | progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] database:database_ delegate:self]; | |
4513 | [database_ setDelegate:progress_]; | |
dc5812ec JF |
4514 | [window_ setContentView:progress_]; |
4515 | ||
3178d79b JF |
4516 | underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]]; |
4517 | [progress_ setContentView:underlay_]; | |
4518 | ||
4519 | overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]]; | |
b31b87cc JF |
4520 | |
4521 | if (!bootstrap_) | |
4522 | [underlay_ addSubview:overlay_]; | |
dc5812ec | 4523 | |
36bb2ca2 JF |
4524 | book_ = [[CYBook alloc] initWithFrame:CGRectMake( |
4525 | 0, 0, screenrect.size.width, screenrect.size.height - 48 | |
4526 | ) database:database_]; | |
dc5812ec | 4527 | |
36bb2ca2 | 4528 | [book_ setDelegate:self]; |
dc5812ec | 4529 | |
36bb2ca2 | 4530 | [overlay_ addSubview:book_]; |
b19871dd | 4531 | |
dc5812ec JF |
4532 | NSArray *buttonitems = [NSArray arrayWithObjects: |
4533 | [NSDictionary dictionaryWithObjectsAndKeys: | |
4534 | @"buttonBarItemTapped:", kUIButtonBarButtonAction, | |
9b619239 JF |
4535 | @"home-up.png", kUIButtonBarButtonInfo, |
4536 | @"home-dn.png", kUIButtonBarButtonSelectedInfo, | |
dc5812ec JF |
4537 | [NSNumber numberWithInt:1], kUIButtonBarButtonTag, |
4538 | self, kUIButtonBarButtonTarget, | |
9b619239 | 4539 | @"Home", kUIButtonBarButtonTitle, |
dc5812ec JF |
4540 | @"0", kUIButtonBarButtonType, |
4541 | nil], | |
4542 | ||
4543 | [NSDictionary dictionaryWithObjectsAndKeys: | |
4544 | @"buttonBarItemTapped:", kUIButtonBarButtonAction, | |
4545 | @"install-up.png", kUIButtonBarButtonInfo, | |
4546 | @"install-dn.png", kUIButtonBarButtonSelectedInfo, | |
4547 | [NSNumber numberWithInt:2], kUIButtonBarButtonTag, | |
4548 | self, kUIButtonBarButtonTarget, | |
4549 | @"Install", kUIButtonBarButtonTitle, | |
4550 | @"0", kUIButtonBarButtonType, | |
4551 | nil], | |
4552 | ||
4553 | [NSDictionary dictionaryWithObjectsAndKeys: | |
4554 | @"buttonBarItemTapped:", kUIButtonBarButtonAction, | |
b4d89997 JF |
4555 | @"changes-up.png", kUIButtonBarButtonInfo, |
4556 | @"changes-dn.png", kUIButtonBarButtonSelectedInfo, | |
dc5812ec JF |
4557 | [NSNumber numberWithInt:3], kUIButtonBarButtonTag, |
4558 | self, kUIButtonBarButtonTarget, | |
b4d89997 | 4559 | @"Changes", kUIButtonBarButtonTitle, |
dc5812ec JF |
4560 | @"0", kUIButtonBarButtonType, |
4561 | nil], | |
4562 | ||
4563 | [NSDictionary dictionaryWithObjectsAndKeys: | |
4564 | @"buttonBarItemTapped:", kUIButtonBarButtonAction, | |
b4d89997 JF |
4565 | @"manage-up.png", kUIButtonBarButtonInfo, |
4566 | @"manage-dn.png", kUIButtonBarButtonSelectedInfo, | |
dc5812ec JF |
4567 | [NSNumber numberWithInt:4], kUIButtonBarButtonTag, |
4568 | self, kUIButtonBarButtonTarget, | |
36bb2ca2 | 4569 | @"Manage", kUIButtonBarButtonTitle, |
dc5812ec JF |
4570 | @"0", kUIButtonBarButtonType, |
4571 | nil], | |
4572 | ||
4573 | [NSDictionary dictionaryWithObjectsAndKeys: | |
4574 | @"buttonBarItemTapped:", kUIButtonBarButtonAction, | |
b4d89997 JF |
4575 | @"search-up.png", kUIButtonBarButtonInfo, |
4576 | @"search-dn.png", kUIButtonBarButtonSelectedInfo, | |
dc5812ec JF |
4577 | [NSNumber numberWithInt:5], kUIButtonBarButtonTag, |
4578 | self, kUIButtonBarButtonTarget, | |
b4d89997 | 4579 | @"Search", kUIButtonBarButtonTitle, |
dc5812ec JF |
4580 | @"0", kUIButtonBarButtonType, |
4581 | nil], | |
4582 | nil]; | |
4583 | ||
2367a917 | 4584 | buttonbar_ = [[UIButtonBar alloc] |
3178d79b | 4585 | initInView:overlay_ |
dc5812ec | 4586 | withFrame:CGRectMake( |
2388b078 JF |
4587 | 0, screenrect.size.height - ButtonBarHeight_, |
4588 | screenrect.size.width, ButtonBarHeight_ | |
dc5812ec JF |
4589 | ) |
4590 | withItemList:buttonitems | |
4591 | ]; | |
4592 | ||
2367a917 JF |
4593 | [buttonbar_ setDelegate:self]; |
4594 | [buttonbar_ setBarStyle:1]; | |
4595 | [buttonbar_ setButtonBarTrackingMode:2]; | |
dc5812ec JF |
4596 | |
4597 | int buttons[5] = {1, 2, 3, 4, 5}; | |
2367a917 JF |
4598 | [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5]; |
4599 | [buttonbar_ showButtonGroup:0 withDuration:0]; | |
dc5812ec JF |
4600 | |
4601 | for (int i = 0; i != 5; ++i) | |
2367a917 | 4602 | [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake( |
2388b078 | 4603 | i * 64 + 2, 1, 60, ButtonBarHeight_ |
dc5812ec JF |
4604 | )]; |
4605 | ||
2367a917 | 4606 | [buttonbar_ showSelectionForButton:1]; |
3178d79b | 4607 | [overlay_ addSubview:buttonbar_]; |
dc5812ec | 4608 | |
b4d89997 | 4609 | [UIKeyboard initImplementationNow]; |
b4d89997 | 4610 | CGSize keysize = [UIKeyboard defaultSize]; |
ab398adf | 4611 | CGRect keyrect = {{0, [overlay_ bounds].size.height}, keysize}; |
b4d89997 | 4612 | keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect]; |
d73cede2 | 4613 | [[UIKeyboardImpl sharedInstance] setSoundsEnabled:(Sounds_Keyboard_ ? YES : NO)]; |
ab398adf | 4614 | [overlay_ addSubview:keyboard_]; |
b4d89997 | 4615 | |
9b619239 JF |
4616 | install_ = [[InstallView alloc] initWithBook:book_ database:database_]; |
4617 | changes_ = [[ChangesView alloc] initWithBook:book_ database:database_]; | |
4618 | manage_ = [[ManageView alloc] initWithBook:book_ database:database_]; | |
4619 | search_ = [[SearchView alloc] initWithBook:book_ database:database_]; | |
4620 | ||
b31b87cc | 4621 | [progress_ resetView]; |
5a09ae08 | 4622 | [self reloadData]; |
b31b87cc JF |
4623 | |
4624 | if (bootstrap_) | |
4625 | [self bootstrap]; | |
36bb2ca2 | 4626 | else |
9b619239 | 4627 | [self _setHomePage]; |
b4d89997 JF |
4628 | } |
4629 | ||
4630 | - (void) showKeyboard:(BOOL)show { | |
ab398adf JF |
4631 | CGSize keysize = [UIKeyboard defaultSize]; |
4632 | CGRect keydown = {{0, [overlay_ bounds].size.height}, keysize}; | |
4633 | CGRect keyup = keydown; | |
4634 | keyup.origin.y -= keysize.height; | |
4635 | ||
4636 | UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:keyboard_] autorelease]; | |
4637 | [animation setSignificantRectFields:2]; | |
4638 | ||
4639 | if (show) { | |
4640 | [animation setStartFrame:keydown]; | |
4641 | [animation setEndFrame:keyup]; | |
4642 | [keyboard_ activate]; | |
4643 | } else { | |
4644 | [animation setStartFrame:keyup]; | |
4645 | [animation setEndFrame:keydown]; | |
4646 | [keyboard_ deactivate]; | |
4647 | } | |
4648 | ||
4649 | [[UIAnimator sharedAnimator] | |
4650 | addAnimations:[NSArray arrayWithObjects:animation, nil] | |
2388b078 | 4651 | withDuration:KeyboardTime_ |
ab398adf JF |
4652 | start:YES |
4653 | ]; | |
dc5812ec JF |
4654 | } |
4655 | ||
36bb2ca2 | 4656 | - (void) slideUp:(UIAlertSheet *)alert { |
9ea8d159 | 4657 | [alert presentSheetInView:overlay_]; |
36bb2ca2 JF |
4658 | } |
4659 | ||
dc5812ec JF |
4660 | @end |
4661 | ||
b4d89997 JF |
4662 | void AddPreferences(NSString *plist) { |
4663 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
4664 | ||
4665 | NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease]; | |
4666 | _assert(settings != NULL); | |
4667 | NSMutableArray *items = [settings objectForKey:@"items"]; | |
4668 | ||
4669 | bool cydia(false); | |
4670 | ||
4671 | for (size_t i(0); i != [items count]; ++i) { | |
4672 | NSMutableDictionary *item([items objectAtIndex:i]); | |
4673 | NSString *label = [item objectForKey:@"label"]; | |
4674 | if (label != nil && [label isEqualToString:@"Cydia"]) { | |
4675 | cydia = true; | |
4676 | break; | |
4677 | } | |
4678 | } | |
4679 | ||
4680 | if (!cydia) { | |
4681 | for (size_t i(0); i != [items count]; ++i) { | |
4682 | NSDictionary *item([items objectAtIndex:i]); | |
4683 | NSString *label = [item objectForKey:@"label"]; | |
4684 | if (label != nil && [label isEqualToString:@"General"]) { | |
4685 | [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys: | |
4686 | @"CydiaSettings", @"bundle", | |
4687 | @"PSLinkCell", @"cell", | |
4688 | [NSNumber numberWithBool:YES], @"hasIcon", | |
4689 | [NSNumber numberWithBool:YES], @"isController", | |
4690 | @"Cydia", @"label", | |
4691 | nil] atIndex:(i + 1)]; | |
4692 | ||
4693 | break; | |
4694 | } | |
4695 | } | |
4696 | ||
4697 | _assert([settings writeToFile:plist atomically:YES] == YES); | |
4698 | } | |
4699 | ||
4700 | [pool release]; | |
4701 | } | |
4702 | ||
4703 | /*IMP alloc_; | |
4704 | id Alloc_(id self, SEL selector) { | |
4705 | id object = alloc_(self, selector); | |
4706 | fprintf(stderr, "[%s]A-%p\n", self->isa->name, object); | |
4707 | return object; | |
4708 | }*/ | |
4709 | ||
36bb2ca2 JF |
4710 | /*IMP dealloc_; |
4711 | id Dealloc_(id self, SEL selector) { | |
4712 | id object = dealloc_(self, selector); | |
4713 | fprintf(stderr, "[%s]D-%p\n", self->isa->name, object); | |
4714 | return object; | |
4715 | }*/ | |
b4d89997 | 4716 | |
36bb2ca2 | 4717 | int main(int argc, char *argv[]) { |
d73cede2 JF |
4718 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
4719 | ||
b31b87cc JF |
4720 | bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0; |
4721 | ||
d73cede2 JF |
4722 | Home_ = NSHomeDirectory(); |
4723 | ||
4724 | { | |
4725 | NSString *plist = [Home_ stringByAppendingString:@"/Library/Preferences/com.apple.preferences.sounds.plist"]; | |
4726 | if (NSDictionary *sounds = [NSDictionary dictionaryWithContentsOfFile:plist]) | |
4727 | if (NSNumber *keyboard = [sounds objectForKey:@"keyboard"]) | |
4728 | Sounds_Keyboard_ = [keyboard boolValue]; | |
4729 | } | |
4730 | ||
b4d89997 JF |
4731 | setuid(0); |
4732 | setgid(0); | |
4733 | ||
4734 | /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc)); | |
4735 | alloc_ = alloc->method_imp; | |
4736 | alloc->method_imp = (IMP) &Alloc_;*/ | |
4737 | ||
36bb2ca2 JF |
4738 | /*Method dealloc = class_getClassMethod([NSObject class], @selector(dealloc)); |
4739 | dealloc_ = dealloc->method_imp; | |
4740 | dealloc->method_imp = (IMP) &Dealloc_;*/ | |
4741 | ||
2a8d9add JF |
4742 | if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) { |
4743 | if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) { | |
5f6bff8c | 4744 | Firmware_ = strdup([prover UTF8String]); |
2a8d9add JF |
4745 | NSArray *versions = [prover componentsSeparatedByString:@"."]; |
4746 | int count = [versions count]; | |
4747 | Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0; | |
51a1ffdf JF |
4748 | Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0; |
4749 | BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0; | |
2a8d9add JF |
4750 | } |
4751 | } | |
4752 | ||
3178d79b JF |
4753 | size_t size; |
4754 | sysctlbyname("hw.machine", NULL, &size, NULL, 0); | |
4755 | char *machine = new char[size]; | |
4756 | sysctlbyname("hw.machine", machine, &size, NULL, 0); | |
4757 | Machine_ = machine; | |
4758 | ||
4759 | if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice")) | |
4760 | if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) { | |
4761 | if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) { | |
4762 | SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding())); | |
4763 | CFRelease(serial); | |
4764 | } | |
4765 | ||
4766 | IOObjectRelease(service); | |
4767 | } | |
4768 | ||
99364ec4 JF |
4769 | /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist"); |
4770 | AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/ | |
b4d89997 JF |
4771 | |
4772 | if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL) | |
4773 | Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2]; | |
4774 | else | |
4775 | Packages_ = [Metadata_ objectForKey:@"Packages"]; | |
4776 | ||
68a238ec | 4777 | setenv("CYDIA", "", _not(int)); |
26c2dd8c JF |
4778 | if (access("/User", F_OK) != 0) |
4779 | system("/usr/libexec/cydia/firmware.sh"); | |
9e98e020 | 4780 | |
36bb2ca2 JF |
4781 | space_ = CGColorSpaceCreateDeviceRGB(); |
4782 | ||
4783 | Black_.Set(space_, 0.0, 0.0, 0.0, 1.0); | |
4784 | Clear_.Set(space_, 0.0, 0.0, 0.0, 0.0); | |
4785 | Red_.Set(space_, 1.0, 0.0, 0.0, 1.0); | |
4786 | White_.Set(space_, 1.0, 1.0, 1.0, 1.0); | |
4787 | ||
4788 | int value = UIApplicationMain(argc, argv, [Cydia class]); | |
4789 | ||
4790 | CGColorSpaceRelease(space_); | |
4791 | ||
dc5812ec | 4792 | [pool release]; |
36bb2ca2 | 4793 | return value; |
dc5812ec | 4794 | } |