]>
Commit | Line | Data |
---|---|---|
dc5812ec | 1 | /* #include Directives {{{ */ |
8da60fb7 | 2 | #include <Foundation/NSURL.h> |
dc5812ec JF |
3 | #include <UIKit/UIKit.h> |
4 | #import <GraphicsServices/GraphicsServices.h> | |
5 | ||
2367a917 JF |
6 | #include <sstream> |
7 | #include <ext/stdio_filebuf.h> | |
8 | ||
dc5812ec JF |
9 | #include <apt-pkg/acquire.h> |
10 | #include <apt-pkg/acquire-item.h> | |
11 | #include <apt-pkg/algorithms.h> | |
12 | #include <apt-pkg/cachefile.h> | |
13 | #include <apt-pkg/configuration.h> | |
3178d79b | 14 | #include <apt-pkg/debmetaindex.h> |
dc5812ec JF |
15 | #include <apt-pkg/error.h> |
16 | #include <apt-pkg/init.h> | |
17 | #include <apt-pkg/pkgrecords.h> | |
18 | #include <apt-pkg/sourcelist.h> | |
2367a917 | 19 | #include <apt-pkg/sptr.h> |
dc5812ec | 20 | |
3178d79b JF |
21 | #include <sys/sysctl.h> |
22 | ||
b4d89997 JF |
23 | extern "C" { |
24 | #include <mach-o/nlist.h> | |
25 | } | |
26 | ||
27 | #include <objc/objc-class.h> | |
28 | ||
2367a917 | 29 | #include <errno.h> |
dc5812ec JF |
30 | #include <pcre.h> |
31 | #include <string.h> | |
32 | /* }}} */ | |
33 | /* Extension Keywords {{{ */ | |
2367a917 | 34 | #define _trace() fprintf(stderr, "_trace()@%s:%u[%s]\n", __FILE__, __LINE__, __FUNCTION__) |
dc5812ec JF |
35 | |
36 | #define _assert(test) do \ | |
37 | if (!(test)) { \ | |
2367a917 | 38 | fprintf(stderr, "_assert(%d:%s)@%s:%u[%s]\n", errno, #test, __FILE__, __LINE__, __FUNCTION__); \ |
dc5812ec JF |
39 | exit(-1); \ |
40 | } \ | |
41 | while (false) | |
42 | /* }}} */ | |
b4d89997 | 43 | /* Miscellaneous Messages {{{ */ |
3178d79b JF |
44 | @interface WebView |
45 | - (void) setApplicationNameForUserAgent:(NSString *)applicationName; | |
46 | @end | |
47 | ||
b4d89997 JF |
48 | @interface NSString (Cydia) |
49 | - (NSString *) stringByAddingPercentEscapes; | |
50 | - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1; | |
51 | @end | |
52 | /* }}} */ | |
53 | ||
54 | /* Reset View (UIView) {{{ */ | |
55 | @interface UIView (CYResetView) | |
56 | - (void) resetViewAnimated:(BOOL)animated; | |
57 | @end | |
58 | ||
59 | @implementation UIView (CYResetView) | |
60 | ||
61 | - (void) resetViewAnimated:(BOOL)animated { | |
62 | fprintf(stderr, "%s\n", self->isa->name); | |
63 | _assert(false); | |
64 | } | |
65 | ||
66 | @end | |
67 | /* }}} */ | |
68 | /* Reset View (UITable) {{{ */ | |
69 | @interface UITable (CYResetView) | |
70 | - (void) resetViewAnimated:(BOOL)animated; | |
71 | @end | |
72 | ||
73 | @implementation UITable (CYResetView) | |
74 | ||
75 | - (void) resetViewAnimated:(BOOL)animated { | |
76 | [self selectRow:-1 byExtendingSelection:NO withFade:animated]; | |
77 | } | |
78 | ||
79 | @end | |
80 | /* }}} */ | |
81 | /* Reset View (UISectionList) {{{ */ | |
82 | @interface UISectionList (CYResetView) | |
83 | - (void) resetViewAnimated:(BOOL)animated; | |
84 | @end | |
85 | ||
86 | @implementation UISectionList (CYResetView) | |
87 | ||
88 | - (void) resetViewAnimated:(BOOL)animated { | |
89 | [[self table] resetViewAnimated:animated]; | |
90 | } | |
91 | ||
92 | @end | |
93 | /* }}} */ | |
94 | ||
95 | /* Perl-Compatible RegEx {{{ */ | |
96 | class Pcre { | |
97 | private: | |
98 | pcre *code_; | |
99 | pcre_extra *study_; | |
100 | int capture_; | |
101 | int *matches_; | |
102 | const char *data_; | |
103 | ||
104 | public: | |
105 | Pcre(const char *regex) : | |
106 | study_(NULL) | |
107 | { | |
108 | const char *error; | |
109 | int offset; | |
110 | code_ = pcre_compile(regex, 0, &error, &offset, NULL); | |
111 | ||
112 | if (code_ == NULL) { | |
113 | fprintf(stderr, "%d:%s\n", offset, error); | |
114 | _assert(false); | |
115 | } | |
116 | ||
117 | pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_); | |
118 | matches_ = new int[(capture_ + 1) * 3]; | |
119 | } | |
120 | ||
121 | ~Pcre() { | |
122 | pcre_free(code_); | |
123 | delete matches_; | |
124 | } | |
125 | ||
126 | NSString *operator [](size_t match) { | |
127 | return [NSString | |
128 | stringWithCString:(data_ + matches_[match * 2]) | |
129 | length:(matches_[match * 2 + 1] - matches_[match * 2]) | |
130 | ]; | |
131 | } | |
132 | ||
133 | bool operator ()(const char *data, size_t size) { | |
134 | data_ = data; | |
135 | return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0; | |
136 | } | |
137 | }; | |
138 | /* }}} */ | |
139 | /* CoreGraphicsServices Primitives {{{ */ | |
140 | class CGColor { | |
141 | private: | |
142 | CGColorRef color_; | |
143 | ||
144 | public: | |
145 | CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) { | |
146 | float color[] = {red, green, blue, alpha}; | |
147 | color_ = CGColorCreate(space, color); | |
148 | } | |
149 | ||
150 | ~CGColor() { | |
151 | CGColorRelease(color_); | |
152 | } | |
153 | ||
154 | operator CGColorRef() { | |
155 | return color_; | |
156 | } | |
157 | }; | |
158 | ||
159 | class GSFont { | |
160 | private: | |
161 | GSFontRef font_; | |
162 | ||
163 | public: | |
164 | ~GSFont() { | |
165 | /* XXX: no GSFontRelease()? */ | |
166 | CFRelease(font_); | |
167 | } | |
168 | }; | |
169 | /* }}} */ | |
170 | ||
3178d79b JF |
171 | static const int PulseInterval_ = 50000; |
172 | const char *Machine_ = NULL; | |
173 | const char *SerialNumber_ = NULL; | |
174 | ||
b31b87cc JF |
175 | bool bootstrap_ = false; |
176 | ||
b4d89997 JF |
177 | static NSMutableDictionary *Metadata_; |
178 | static NSMutableDictionary *Packages_; | |
179 | static NSDate *now_; | |
8da60fb7 | 180 | |
23672b39 JF |
181 | NSString *GetLastUpdate() { |
182 | NSDate *update = [Metadata_ objectForKey:@"LastUpdate"]; | |
183 | ||
184 | if (update == nil) | |
185 | return @"Never or Unknown"; | |
186 | ||
187 | CFLocaleRef locale = CFLocaleCopyCurrent(); | |
188 | CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle); | |
189 | CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update); | |
190 | ||
191 | CFRelease(formatter); | |
23672b39 JF |
192 | CFRelease(locale); |
193 | ||
194 | return [(NSString *) formatted autorelease]; | |
195 | } | |
196 | ||
2367a917 JF |
197 | @protocol ProgressDelegate |
198 | - (void) setError:(NSString *)error; | |
199 | - (void) setTitle:(NSString *)title; | |
200 | - (void) setPercent:(float)percent; | |
201 | - (void) addOutput:(NSString *)output; | |
202 | @end | |
203 | ||
8fe19fc1 JF |
204 | NSString *SizeString(double size) { |
205 | unsigned power = 0; | |
206 | while (size > 1024) { | |
207 | size /= 1024; | |
208 | ++power; | |
209 | } | |
210 | ||
211 | static const char *powers_[] = {"B", "kB", "MB", "GB"}; | |
212 | ||
213 | return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]]; | |
214 | } | |
215 | ||
b4d89997 JF |
216 | static const float TextViewOffset_ = 22; |
217 | ||
218 | UITextView *GetTextView(NSString *value, float left, bool html) { | |
219 | UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]); | |
220 | [text setEditable:NO]; | |
221 | [text setTextSize:16]; | |
222 | if (html) | |
223 | [text setHTML:value]; | |
224 | else | |
225 | [text setText:value]; | |
226 | [text setEnabled:NO]; | |
227 | ||
228 | CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); | |
229 | CGColor clear(space, 0, 0, 0, 0); | |
230 | [text setBackgroundColor:clear]; | |
231 | CGColorSpaceRelease(space); | |
232 | ||
233 | CGRect frame = [text frame]; | |
234 | [text setFrame:frame]; | |
235 | CGRect rect = [text visibleTextRect]; | |
236 | frame.size.height = rect.size.height; | |
237 | [text setFrame:frame]; | |
238 | ||
239 | return text; | |
240 | } | |
241 | ||
dc5812ec JF |
242 | /* Status Delegation {{{ */ |
243 | class Status : | |
244 | public pkgAcquireStatus | |
245 | { | |
246 | private: | |
247 | id delegate_; | |
248 | ||
249 | public: | |
250 | Status() : | |
251 | delegate_(nil) | |
252 | { | |
253 | } | |
254 | ||
255 | void setDelegate(id delegate) { | |
256 | delegate_ = delegate; | |
257 | } | |
258 | ||
259 | virtual bool MediaChange(std::string media, std::string drive) { | |
260 | return false; | |
261 | } | |
262 | ||
263 | virtual void IMSHit(pkgAcquire::ItemDesc &item) { | |
dc5812ec JF |
264 | } |
265 | ||
266 | virtual void Fetch(pkgAcquire::ItemDesc &item) { | |
8da60fb7 | 267 | [delegate_ setTitle:[NSString stringWithCString:("Downloading " + item.ShortDesc).c_str()]]; |
dc5812ec JF |
268 | } |
269 | ||
270 | virtual void Done(pkgAcquire::ItemDesc &item) { | |
dc5812ec JF |
271 | } |
272 | ||
273 | virtual void Fail(pkgAcquire::ItemDesc &item) { | |
1d80f6b9 JF |
274 | if ( |
275 | item.Owner->Status == pkgAcquire::Item::StatIdle || | |
276 | item.Owner->Status == pkgAcquire::Item::StatDone | |
277 | ) | |
278 | return; | |
279 | ||
280 | [delegate_ setError:[NSString stringWithCString:item.Owner->ErrorText.c_str()]]; | |
dc5812ec JF |
281 | } |
282 | ||
283 | virtual bool Pulse(pkgAcquire *Owner) { | |
2367a917 JF |
284 | bool value = pkgAcquireStatus::Pulse(Owner); |
285 | ||
286 | float percent( | |
287 | double(CurrentBytes + CurrentItems) / | |
288 | double(TotalBytes + TotalItems) | |
289 | ); | |
290 | ||
291 | [delegate_ setPercent:percent]; | |
292 | return value; | |
dc5812ec JF |
293 | } |
294 | ||
295 | virtual void Start() { | |
dc5812ec JF |
296 | } |
297 | ||
298 | virtual void Stop() { | |
dc5812ec JF |
299 | } |
300 | }; | |
301 | /* }}} */ | |
302 | /* Progress Delegation {{{ */ | |
303 | class Progress : | |
304 | public OpProgress | |
305 | { | |
306 | private: | |
307 | id delegate_; | |
308 | ||
309 | protected: | |
310 | virtual void Update() { | |
2367a917 JF |
311 | [delegate_ setTitle:[NSString stringWithCString:Op.c_str()]]; |
312 | [delegate_ setPercent:(Percent / 100)]; | |
dc5812ec JF |
313 | } |
314 | ||
315 | public: | |
316 | Progress() : | |
317 | delegate_(nil) | |
318 | { | |
319 | } | |
320 | ||
321 | void setDelegate(id delegate) { | |
322 | delegate_ = delegate; | |
323 | } | |
324 | ||
325 | virtual void Done() { | |
2367a917 | 326 | [delegate_ setPercent:1]; |
dc5812ec JF |
327 | } |
328 | }; | |
329 | /* }}} */ | |
330 | ||
331 | /* External Constants {{{ */ | |
332 | extern NSString *kUIButtonBarButtonAction; | |
333 | extern NSString *kUIButtonBarButtonInfo; | |
334 | extern NSString *kUIButtonBarButtonInfoOffset; | |
335 | extern NSString *kUIButtonBarButtonSelectedInfo; | |
336 | extern NSString *kUIButtonBarButtonStyle; | |
337 | extern NSString *kUIButtonBarButtonTag; | |
338 | extern NSString *kUIButtonBarButtonTarget; | |
339 | extern NSString *kUIButtonBarButtonTitle; | |
340 | extern NSString *kUIButtonBarButtonTitleVerticalHeight; | |
341 | extern NSString *kUIButtonBarButtonTitleWidth; | |
342 | extern NSString *kUIButtonBarButtonType; | |
343 | /* }}} */ | |
344 | /* Mime Addresses {{{ */ | |
b4d89997 JF |
345 | Pcre email_r("^\"?(.*)\"? <([^>]*)>$"); |
346 | ||
dc5812ec JF |
347 | @interface Address : NSObject { |
348 | NSString *name_; | |
349 | NSString *email_; | |
350 | } | |
351 | ||
2367a917 JF |
352 | - (void) dealloc; |
353 | ||
dc5812ec JF |
354 | - (NSString *) name; |
355 | - (NSString *) email; | |
356 | ||
357 | + (Address *) addressWithString:(NSString *)string; | |
358 | - (Address *) initWithString:(NSString *)string; | |
359 | @end | |
360 | ||
361 | @implementation Address | |
362 | ||
2367a917 JF |
363 | - (void) dealloc { |
364 | [name_ release]; | |
3178d79b JF |
365 | if (email_ != nil) |
366 | [email_ release]; | |
2367a917 JF |
367 | [super dealloc]; |
368 | } | |
369 | ||
dc5812ec JF |
370 | - (NSString *) name { |
371 | return name_; | |
372 | } | |
373 | ||
374 | - (NSString *) email { | |
375 | return email_; | |
376 | } | |
377 | ||
378 | + (Address *) addressWithString:(NSString *)string { | |
2367a917 | 379 | return [[[Address alloc] initWithString:string] autorelease]; |
dc5812ec JF |
380 | } |
381 | ||
382 | - (Address *) initWithString:(NSString *)string { | |
383 | if ((self = [super init]) != nil) { | |
dc5812ec | 384 | const char *data = [string UTF8String]; |
b4d89997 | 385 | size_t size = [string length]; |
dc5812ec | 386 | |
b4d89997 JF |
387 | if (email_r(data, size)) { |
388 | name_ = [email_r[1] retain]; | |
389 | email_ = [email_r[2] retain]; | |
3178d79b JF |
390 | } else { |
391 | name_ = [[NSString stringWithCString:data length:size] retain]; | |
392 | email_ = nil; | |
393 | } | |
dc5812ec JF |
394 | } return self; |
395 | } | |
396 | ||
397 | @end | |
398 | /* }}} */ | |
399 | ||
400 | /* Right Alignment {{{ */ | |
401 | @interface UIRightTextLabel : UITextLabel { | |
402 | float _savedRightEdgeX; | |
403 | BOOL _sizedtofit_flag; | |
404 | } | |
405 | ||
406 | - (void) setFrame:(CGRect)frame; | |
407 | - (void) setText:(NSString *)text; | |
408 | - (void) realignText; | |
409 | @end | |
410 | ||
411 | @implementation UIRightTextLabel | |
412 | ||
413 | - (void) setFrame:(CGRect)frame { | |
414 | [super setFrame:frame]; | |
415 | if (_sizedtofit_flag == NO) { | |
416 | _savedRightEdgeX = frame.origin.x; | |
417 | [self realignText]; | |
418 | } | |
419 | } | |
420 | ||
421 | - (void) setText:(NSString *)text { | |
422 | [super setText:text]; | |
423 | [self realignText]; | |
424 | } | |
425 | ||
426 | - (void) realignText { | |
427 | CGRect oldFrame = [self frame]; | |
428 | ||
429 | _sizedtofit_flag = YES; | |
430 | [self sizeToFit]; // shrink down size so I can right align it | |
431 | ||
432 | CGRect newFrame = [self frame]; | |
433 | ||
434 | oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width; | |
435 | oldFrame.size.width = newFrame.size.width; | |
436 | [super setFrame:oldFrame]; | |
437 | _sizedtofit_flag = NO; | |
438 | } | |
439 | ||
440 | @end | |
441 | /* }}} */ | |
2367a917 JF |
442 | /* Linear Algebra {{{ */ |
443 | inline float interpolate(float begin, float end, float fraction) { | |
444 | return (end - begin) * fraction + begin; | |
445 | } | |
446 | /* }}} */ | |
dc5812ec | 447 | |
3178d79b JF |
448 | @class Package; |
449 | ||
b4d89997 | 450 | /* Database Interface {{{ */ |
dc5812ec JF |
451 | @interface Database : NSObject { |
452 | pkgCacheFile cache_; | |
453 | pkgRecords *records_; | |
454 | pkgProblemResolver *resolver_; | |
8fe19fc1 JF |
455 | pkgAcquire *fetcher_; |
456 | FileFd *lock_; | |
457 | SPtr<pkgPackageManager> manager_; | |
dc5812ec | 458 | |
2367a917 | 459 | id delegate_; |
dc5812ec JF |
460 | Status status_; |
461 | Progress progress_; | |
2367a917 | 462 | int statusfd_; |
dc5812ec JF |
463 | } |
464 | ||
b4d89997 JF |
465 | - (void) dealloc; |
466 | ||
3178d79b JF |
467 | - (void) _readStatus:(NSNumber *)fd; |
468 | - (void) _readOutput:(NSNumber *)fd; | |
469 | ||
470 | - (Package *) packageWithName:(NSString *)name; | |
471 | ||
dc5812ec JF |
472 | - (Database *) init; |
473 | - (pkgCacheFile &) cache; | |
474 | - (pkgRecords *) records; | |
475 | - (pkgProblemResolver *) resolver; | |
8fe19fc1 | 476 | - (pkgAcquire &) fetcher; |
dc5812ec | 477 | - (void) reloadData; |
2367a917 | 478 | |
8fe19fc1 | 479 | - (void) prepare; |
2367a917 | 480 | - (void) perform; |
dc5812ec JF |
481 | - (void) update; |
482 | - (void) upgrade; | |
2367a917 | 483 | |
dc5812ec JF |
484 | - (void) setDelegate:(id)delegate; |
485 | @end | |
b4d89997 | 486 | /* }}} */ |
dc5812ec | 487 | |
b19871dd JF |
488 | /* Reset View {{{ */ |
489 | @interface ResetView : UIView { | |
b4d89997 JF |
490 | UIPushButton *reload_; |
491 | NSMutableArray *views_; | |
b19871dd | 492 | UINavigationBar *navbar_; |
b4d89997 | 493 | UITransitionView *transition_; |
b19871dd | 494 | bool resetting_; |
b4d89997 | 495 | id delegate_; |
dc5812ec JF |
496 | } |
497 | ||
b4d89997 JF |
498 | - (void) dealloc; |
499 | ||
b19871dd | 500 | - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item; |
dc5812ec | 501 | |
b4d89997 JF |
502 | - (id) initWithFrame:(CGRect)frame; |
503 | - (void) setDelegate:(id)delegate; | |
504 | - (void) reloadPushed; | |
505 | ||
506 | - (void) pushView:(UIView *)view withTitle:(NSString *)title backButtonTitle:(NSString *)back rightButton:(NSString *)right; | |
507 | - (void) popViews:(unsigned)views; | |
b19871dd JF |
508 | - (void) resetView; |
509 | - (void) _resetView; | |
b4d89997 | 510 | - (void) setPrompt; |
dc5812ec JF |
511 | @end |
512 | ||
b19871dd | 513 | @implementation ResetView |
dc5812ec | 514 | |
b4d89997 JF |
515 | - (void) dealloc { |
516 | [reload_ release]; | |
517 | [transition_ release]; | |
518 | [navbar_ release]; | |
519 | [views_ release]; | |
520 | [super dealloc]; | |
521 | } | |
522 | ||
b19871dd | 523 | - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item { |
b4d89997 JF |
524 | [views_ removeLastObject]; |
525 | UIView *view([views_ lastObject]); | |
526 | [view resetViewAnimated:!resetting_]; | |
527 | if (!resetting_) | |
528 | [transition_ transition:2 toView:view]; | |
529 | ||
530 | if ([views_ count] == 1) | |
b19871dd | 531 | [self _resetView]; |
dc5812ec JF |
532 | } |
533 | ||
b4d89997 JF |
534 | - (id) initWithFrame:(CGRect)frame { |
535 | if ((self = [super initWithFrame:frame]) != nil) { | |
536 | views_ = [[NSMutableArray arrayWithCapacity:4] retain]; | |
537 | ||
538 | struct CGRect bounds = [self bounds]; | |
539 | CGSize navsize = [UINavigationBar defaultSizeWithPrompt]; | |
540 | CGRect navrect = {{0, 0}, navsize}; | |
541 | ||
542 | navbar_ = [[UINavigationBar alloc] initWithFrame:navrect]; | |
543 | [self addSubview:navbar_]; | |
544 | ||
545 | [navbar_ setBarStyle:1]; | |
546 | [navbar_ setDelegate:self]; | |
547 | ||
548 | transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake( | |
549 | bounds.origin.x, bounds.origin.y + navsize.height, bounds.size.width, bounds.size.height - navsize.height | |
550 | )]; | |
551 | ||
552 | //reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(284, 8, 29, 23)]; | |
553 | reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(282, 5, 29, 23)]; | |
554 | [reload_ setShowPressFeedback:YES]; | |
555 | [reload_ setImage:[UIImage applicationImageNamed:@"reload.png"]]; | |
556 | [reload_ addTarget:self action:@selector(reloadPushed) forEvents:1]; | |
557 | ||
558 | [navbar_ addSubview:reload_]; | |
559 | ||
560 | [self addSubview:transition_]; | |
561 | } return self; | |
562 | } | |
563 | ||
564 | - (void) setDelegate:(id)delegate { | |
565 | delegate_ = delegate; | |
566 | } | |
567 | ||
568 | - (void) reloadPushed { | |
569 | [delegate_ update]; | |
570 | } | |
571 | ||
572 | - (void) pushView:(UIView *)view withTitle:(NSString *)title backButtonTitle:(NSString *)back rightButton:(NSString *)right { | |
573 | UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:title] autorelease]; | |
574 | [navbar_ pushNavigationItem:navitem]; | |
575 | [navitem setBackButtonTitle:back]; | |
576 | ||
577 | [navbar_ showButtonsWithLeftTitle:nil rightTitle:right]; | |
578 | ||
579 | [transition_ transition:([views_ count] == 0 ? 0 : 1) toView:view]; | |
580 | [views_ addObject:view]; | |
581 | } | |
582 | ||
583 | - (void) popViews:(unsigned)views { | |
584 | resetting_ = true; | |
585 | for (unsigned i(0); i != views; ++i) | |
586 | [navbar_ popNavigationItem]; | |
587 | resetting_ = false; | |
588 | ||
589 | [transition_ transition:2 toView:[views_ lastObject]]; | |
2367a917 JF |
590 | } |
591 | ||
b19871dd JF |
592 | - (void) resetView { |
593 | resetting_ = true; | |
594 | if ([[navbar_ navigationItems] count] == 1) | |
595 | [self _resetView]; | |
b4d89997 | 596 | else do |
b19871dd | 597 | [navbar_ popNavigationItem]; |
b4d89997 | 598 | while ([[navbar_ navigationItems] count] != 1); |
b19871dd | 599 | resetting_ = false; |
b4d89997 JF |
600 | |
601 | [transition_ transition:0 toView:[views_ lastObject]]; | |
dc5812ec JF |
602 | } |
603 | ||
b19871dd | 604 | - (void) _resetView { |
f62038bb | 605 | [navbar_ showButtonsWithLeftTitle:nil rightTitle:nil]; |
dc5812ec JF |
606 | } |
607 | ||
b4d89997 | 608 | - (void) setPrompt { |
23672b39 | 609 | [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]]; |
dc5812ec JF |
610 | } |
611 | ||
612 | @end | |
613 | /* }}} */ | |
dc5812ec | 614 | /* Confirmation View {{{ */ |
8fe19fc1 JF |
615 | void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) { |
616 | if ([packages count] == 0) | |
617 | return; | |
618 | ||
b4d89997 | 619 | UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 110, false); |
8fe19fc1 | 620 | [fields setObject:text forKey:key]; |
b4d89997 JF |
621 | |
622 | CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); | |
623 | CGColor blue(space, 0, 0, 0.4, 1); | |
624 | [text setTextColor:blue]; | |
625 | CGColorSpaceRelease(space); | |
8fe19fc1 JF |
626 | } |
627 | ||
3178d79b JF |
628 | @protocol ConfirmationViewDelegate |
629 | - (void) cancel; | |
630 | - (void) confirm; | |
631 | @end | |
632 | ||
dc5812ec | 633 | @interface ConfirmationView : UIView { |
3178d79b JF |
634 | Database *database_; |
635 | id delegate_; | |
636 | UITransitionView *transition_; | |
637 | UIView *overlay_; | |
638 | UINavigationBar *navbar_; | |
639 | UIPreferencesTable *table_; | |
8fe19fc1 JF |
640 | NSMutableDictionary *fields_; |
641 | UIAlertSheet *essential_; | |
dc5812ec JF |
642 | } |
643 | ||
3178d79b | 644 | - (void) dealloc; |
8fe19fc1 | 645 | - (void) cancel; |
3178d79b JF |
646 | |
647 | - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to; | |
648 | - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button; | |
8fe19fc1 JF |
649 | - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button; |
650 | ||
651 | - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table; | |
652 | - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group; | |
653 | - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed; | |
654 | - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group; | |
655 | - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group; | |
3178d79b JF |
656 | |
657 | - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate; | |
658 | ||
dc5812ec JF |
659 | @end |
660 | ||
661 | @implementation ConfirmationView | |
3178d79b JF |
662 | |
663 | - (void) dealloc { | |
664 | [transition_ release]; | |
665 | [overlay_ release]; | |
666 | [navbar_ release]; | |
667 | [table_ release]; | |
8fe19fc1 JF |
668 | [fields_ release]; |
669 | if (essential_ != nil) | |
670 | [essential_ release]; | |
3178d79b JF |
671 | [super dealloc]; |
672 | } | |
673 | ||
8fe19fc1 JF |
674 | - (void) cancel { |
675 | [transition_ transition:7 toView:nil]; | |
676 | [delegate_ cancel]; | |
677 | } | |
678 | ||
3178d79b JF |
679 | - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to { |
680 | if (from != nil && to == nil) | |
681 | [self removeFromSuperview]; | |
682 | } | |
683 | ||
684 | - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button { | |
685 | switch (button) { | |
686 | case 0: | |
8fe19fc1 JF |
687 | if (essential_ != nil) |
688 | [essential_ popupAlertAnimated:YES]; | |
689 | else | |
690 | [delegate_ confirm]; | |
3178d79b JF |
691 | break; |
692 | ||
693 | case 1: | |
8fe19fc1 | 694 | [self cancel]; |
3178d79b JF |
695 | break; |
696 | } | |
697 | } | |
698 | ||
8fe19fc1 JF |
699 | - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button { |
700 | [essential_ dismiss]; | |
701 | [self cancel]; | |
702 | } | |
703 | ||
704 | - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table { | |
705 | return 2; | |
706 | } | |
707 | ||
708 | - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group { | |
709 | switch (group) { | |
710 | case 0: return @"Statistics"; | |
711 | case 1: return @"Modifications"; | |
712 | ||
713 | default: _assert(false); | |
714 | } | |
715 | } | |
716 | ||
717 | - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group { | |
718 | switch (group) { | |
719 | case 0: return 3; | |
720 | case 1: return [fields_ count]; | |
721 | ||
722 | default: _assert(false); | |
723 | } | |
724 | } | |
725 | ||
726 | - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed { | |
727 | if (group != 1 || row == -1) | |
728 | return proposed; | |
729 | else { | |
730 | _assert(size_t(row) < [fields_ count]); | |
b4d89997 | 731 | return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_; |
8fe19fc1 JF |
732 | } |
733 | } | |
734 | ||
735 | - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group { | |
736 | UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease]; | |
737 | [cell setShowSelection:NO]; | |
738 | ||
739 | switch (group) { | |
740 | case 0: switch (row) { | |
741 | case 0: { | |
742 | [cell setTitle:@"Downloading"]; | |
743 | [cell setValue:SizeString([database_ fetcher].FetchNeeded())]; | |
744 | } break; | |
745 | ||
746 | case 1: { | |
747 | [cell setTitle:@"Resuming At"]; | |
748 | [cell setValue:SizeString([database_ fetcher].PartialPresent())]; | |
749 | } break; | |
750 | ||
751 | case 2: { | |
752 | double size([database_ cache]->UsrSize()); | |
753 | ||
754 | if (size < 0) { | |
755 | [cell setTitle:@"Disk Freeing"]; | |
756 | [cell setValue:SizeString(-size)]; | |
757 | } else { | |
758 | [cell setTitle:@"Disk Using"]; | |
759 | [cell setValue:SizeString(size)]; | |
760 | } | |
761 | } break; | |
762 | ||
763 | default: _assert(false); | |
764 | } break; | |
765 | ||
766 | case 1: | |
767 | _assert(size_t(row) < [fields_ count]); | |
768 | [cell setTitle:[[fields_ allKeys] objectAtIndex:row]]; | |
769 | [cell addSubview:[[fields_ allValues] objectAtIndex:row]]; | |
770 | break; | |
771 | ||
772 | default: _assert(false); | |
773 | } | |
774 | ||
775 | return cell; | |
776 | } | |
777 | ||
3178d79b JF |
778 | - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate { |
779 | if ((self = [super initWithFrame:[view bounds]]) != nil) { | |
780 | database_ = database; | |
781 | delegate_ = delegate; | |
782 | ||
783 | transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]]; | |
784 | [self addSubview:transition_]; | |
785 | ||
786 | overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]]; | |
787 | ||
788 | CGSize navsize = [UINavigationBar defaultSize]; | |
789 | CGRect navrect = {{0, 0}, navsize}; | |
790 | CGRect bounds = [overlay_ bounds]; | |
791 | ||
792 | navbar_ = [[UINavigationBar alloc] initWithFrame:navrect]; | |
793 | [navbar_ setBarStyle:1]; | |
794 | [navbar_ setDelegate:self]; | |
795 | ||
796 | UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease]; | |
797 | [navbar_ pushNavigationItem:navitem]; | |
798 | [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"]; | |
799 | ||
8fe19fc1 JF |
800 | fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain]; |
801 | ||
802 | NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16]; | |
803 | NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16]; | |
804 | NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16]; | |
805 | ||
806 | bool essential(false); | |
807 | ||
808 | pkgCacheFile &cache([database_ cache]); | |
809 | for (pkgCache::PkgIterator iterator = cache->PkgBegin(); !iterator.end(); ++iterator) { | |
810 | NSString *name([NSString stringWithCString:iterator.Name()]); | |
811 | if (cache[iterator].NewInstall()) | |
812 | [installing addObject:name]; | |
813 | else if (cache[iterator].Upgrade()) | |
814 | [upgrading addObject:name]; | |
815 | else if (cache[iterator].Delete()) { | |
816 | [removing addObject:name]; | |
817 | if ((iterator->Flags & pkgCache::Flag::Essential) != 0) | |
818 | essential = true; | |
819 | } | |
820 | } | |
821 | ||
822 | if (!essential) | |
823 | essential_ = nil; | |
824 | else { | |
825 | essential_ = [[UIAlertSheet alloc] | |
826 | initWithTitle:@"Unable to Comply" | |
827 | buttons:[NSArray arrayWithObjects:@"Okay", nil] | |
828 | defaultButtonIndex:0 | |
829 | delegate:self | |
830 | context:self | |
831 | ]; | |
832 | ||
833 | [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."]; | |
834 | } | |
835 | ||
836 | AddTextView(fields_, installing, @"Installing"); | |
837 | AddTextView(fields_, upgrading, @"Upgrading"); | |
838 | AddTextView(fields_, removing, @"Removing"); | |
839 | ||
3178d79b JF |
840 | table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake( |
841 | 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height | |
842 | )]; | |
843 | ||
b19871dd JF |
844 | [table_ setReusesTableCells:YES]; |
845 | [table_ setDataSource:self]; | |
846 | [table_ reloadData]; | |
847 | ||
848 | [overlay_ addSubview:navbar_]; | |
849 | [overlay_ addSubview:table_]; | |
850 | ||
851 | [view addSubview:self]; | |
852 | ||
853 | [transition_ setDelegate:self]; | |
854 | ||
855 | UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease]; | |
856 | [transition_ transition:0 toView:blank]; | |
857 | [transition_ transition:3 toView:overlay_]; | |
858 | } return self; | |
859 | } | |
860 | ||
861 | @end | |
862 | /* }}} */ | |
863 | ||
864 | /* Package Class {{{ */ | |
b4d89997 JF |
865 | NSString *Scour(const char *field, const char *begin, const char *end) { |
866 | size_t i(0), l(strlen(field)); | |
867 | ||
868 | for (;;) { | |
869 | const char *name = begin + i; | |
870 | const char *colon = name + l; | |
871 | const char *value = colon + 1; | |
872 | ||
873 | if ( | |
874 | value < end && | |
875 | *colon == ':' && | |
876 | memcmp(name, field, l) == 0 | |
877 | ) { | |
878 | while (value != end && value[0] == ' ') | |
879 | ++value; | |
880 | const char *line = std::find(value, end, '\n'); | |
881 | while (line != value && line[-1] == ' ') | |
882 | --line; | |
883 | return [NSString stringWithCString:value length:(line - value)]; | |
884 | } else { | |
885 | begin = std::find(begin, end, '\n'); | |
886 | if (begin == end) | |
887 | return nil; | |
888 | ++begin; | |
889 | } | |
890 | } | |
891 | } | |
892 | ||
b19871dd JF |
893 | @interface Package : NSObject { |
894 | pkgCache::PkgIterator iterator_; | |
895 | Database *database_; | |
b19871dd JF |
896 | pkgCache::VerIterator version_; |
897 | pkgCache::VerFileIterator file_; | |
b4d89997 JF |
898 | |
899 | NSString *latest_; | |
900 | NSString *installed_; | |
901 | ||
902 | NSString *id_; | |
903 | NSString *name_; | |
904 | NSString *tagline_; | |
905 | NSString *icon_; | |
906 | NSString *bundle_; | |
23672b39 | 907 | NSString *website_; |
b19871dd JF |
908 | } |
909 | ||
b4d89997 JF |
910 | - (void) dealloc; |
911 | ||
b19871dd JF |
912 | - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file; |
913 | + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database; | |
914 | ||
b19871dd | 915 | - (NSString *) section; |
b19871dd JF |
916 | - (Address *) maintainer; |
917 | - (size_t) size; | |
b19871dd | 918 | - (NSString *) description; |
b4d89997 JF |
919 | - (NSString *) index; |
920 | ||
921 | - (NSDate *) seen; | |
922 | ||
923 | - (NSString *) latest; | |
924 | - (NSString *) installed; | |
925 | - (BOOL) upgradable; | |
926 | ||
927 | - (NSString *) id; | |
928 | - (NSString *) name; | |
929 | - (NSString *) tagline; | |
930 | - (NSString *) icon; | |
931 | - (NSString *) bundle; | |
23672b39 | 932 | - (NSString *) website; |
b4d89997 JF |
933 | |
934 | - (BOOL) matches:(NSString *)text; | |
935 | ||
936 | - (NSComparisonResult) compareByName:(Package *)package; | |
b19871dd | 937 | - (NSComparisonResult) compareBySectionAndName:(Package *)package; |
b4d89997 | 938 | - (NSComparisonResult) compareForChanges:(Package *)package; |
b19871dd JF |
939 | |
940 | - (void) install; | |
941 | - (void) remove; | |
942 | @end | |
943 | ||
944 | @implementation Package | |
945 | ||
b4d89997 JF |
946 | - (void) dealloc { |
947 | [latest_ release]; | |
948 | if (installed_ != nil) | |
949 | [installed_ release]; | |
950 | ||
951 | [id_ release]; | |
952 | if (name_ != nil) | |
953 | [name_ release]; | |
954 | [tagline_ release]; | |
955 | if (icon_ != nil) | |
956 | [icon_ release]; | |
957 | if (bundle_ != nil) | |
958 | [bundle_ release]; | |
959 | [super dealloc]; | |
960 | } | |
961 | ||
b19871dd JF |
962 | - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file { |
963 | if ((self = [super init]) != nil) { | |
964 | iterator_ = iterator; | |
965 | database_ = database; | |
966 | ||
967 | version_ = version; | |
968 | file_ = file; | |
b4d89997 JF |
969 | |
970 | pkgRecords::Parser *parser = &[database_ records]->Lookup(file_); | |
971 | ||
972 | const char *begin, *end; | |
973 | parser->GetRec(begin, end); | |
974 | ||
975 | latest_ = [[NSString stringWithCString:version_.VerStr()] retain]; | |
976 | installed_ = iterator_.CurrentVer().end() ? nil : [[NSString stringWithCString:iterator_.CurrentVer().VerStr()] retain]; | |
977 | ||
978 | id_ = [[[NSString stringWithCString:iterator_.Name()] lowercaseString] retain]; | |
979 | name_ = Scour("Name", begin, end); | |
980 | if (name_ != nil) | |
981 | name_ = [name_ retain]; | |
982 | tagline_ = [[NSString stringWithCString:parser->ShortDesc().c_str()] retain]; | |
983 | icon_ = Scour("Icon", begin, end); | |
984 | if (icon_ != nil) | |
985 | icon_ = [icon_ retain]; | |
986 | bundle_ = Scour("Bundle", begin, end); | |
987 | if (bundle_ != nil) | |
988 | bundle_ = [bundle_ retain]; | |
23672b39 JF |
989 | website_ = Scour("Website", begin, end); |
990 | if (website_ != nil) | |
991 | website_ = [website_ retain]; | |
b4d89997 JF |
992 | |
993 | NSMutableDictionary *metadata = [Packages_ objectForKey:id_]; | |
994 | if (metadata == nil) { | |
995 | metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys: | |
996 | now_, @"FirstSeen", | |
997 | nil]; | |
998 | ||
999 | [Packages_ setObject:metadata forKey:id_]; | |
1000 | } | |
b19871dd JF |
1001 | } return self; |
1002 | } | |
1003 | ||
1004 | + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database { | |
1005 | for (pkgCache::VerIterator version = iterator.VersionList(); !version.end(); ++version) | |
1006 | for (pkgCache::VerFileIterator file = version.FileList(); !file.end(); ++file) | |
1007 | return [[[Package alloc] | |
1008 | initWithIterator:iterator | |
1009 | database:database | |
1010 | version:version | |
1011 | file:file] | |
1012 | autorelease]; | |
1013 | return nil; | |
1014 | } | |
1015 | ||
b4d89997 JF |
1016 | - (NSString *) section { |
1017 | return [[NSString stringWithCString:iterator_.Section()] stringByReplacingCharacter:'_' withCharacter:' ']; | |
b19871dd JF |
1018 | } |
1019 | ||
b4d89997 JF |
1020 | - (Address *) maintainer { |
1021 | pkgRecords::Parser *parser = &[database_ records]->Lookup(file_); | |
1022 | return [Address addressWithString:[NSString stringWithCString:parser->Maintainer().c_str()]]; | |
1023 | } | |
1024 | ||
1025 | - (size_t) size { | |
1026 | return version_->InstalledSize; | |
1027 | } | |
1028 | ||
1029 | - (NSString *) description { | |
1030 | pkgRecords::Parser *parser = &[database_ records]->Lookup(file_); | |
1031 | NSString *description([NSString stringWithCString:parser->LongDesc().c_str()]); | |
1032 | ||
1033 | NSArray *lines = [description componentsSeparatedByString:@"\n"]; | |
1034 | NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)]; | |
1035 | if ([lines count] < 2) | |
1036 | return nil; | |
1037 | ||
1038 | NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet]; | |
1039 | for (size_t i(1); i != [lines count]; ++i) { | |
1040 | NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace]; | |
1041 | [trimmed addObject:trim]; | |
1042 | } | |
1043 | ||
1044 | return [trimmed componentsJoinedByString:@"\n"]; | |
1045 | } | |
1046 | ||
1047 | - (NSString *) index { | |
1048 | return [[[self name] substringToIndex:1] uppercaseString]; | |
1049 | } | |
1050 | ||
1051 | - (NSDate *) seen { | |
1052 | return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"]; | |
b19871dd JF |
1053 | } |
1054 | ||
1055 | - (NSString *) latest { | |
b4d89997 | 1056 | return latest_; |
b19871dd JF |
1057 | } |
1058 | ||
1059 | - (NSString *) installed { | |
b4d89997 | 1060 | return installed_; |
b19871dd JF |
1061 | } |
1062 | ||
b4d89997 JF |
1063 | - (BOOL) upgradable { |
1064 | NSString *installed = [self installed]; | |
1065 | return installed != nil && [[self latest] compare:installed] != NSOrderedSame ? YES : NO; | |
b19871dd JF |
1066 | } |
1067 | ||
b4d89997 JF |
1068 | - (NSString *) id { |
1069 | return id_; | |
1070 | } | |
1071 | ||
1072 | - (NSString *) name { | |
1073 | return name_ == nil ? id_ : name_; | |
b19871dd JF |
1074 | } |
1075 | ||
1076 | - (NSString *) tagline { | |
b4d89997 | 1077 | return tagline_; |
b19871dd JF |
1078 | } |
1079 | ||
b4d89997 JF |
1080 | - (NSString *) icon { |
1081 | return icon_; | |
1082 | } | |
1083 | ||
1084 | - (NSString *) bundle { | |
1085 | return bundle_; | |
1086 | } | |
1087 | ||
23672b39 JF |
1088 | - (NSString *) website { |
1089 | return website_; | |
1090 | } | |
1091 | ||
b4d89997 JF |
1092 | - (BOOL) matches:(NSString *)text { |
1093 | if (text == nil) | |
1094 | return NO; | |
1095 | ||
1096 | NSRange range; | |
1097 | ||
1098 | range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch]; | |
1099 | if (range.location != NSNotFound) | |
1100 | return YES; | |
1101 | ||
1102 | range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch]; | |
1103 | if (range.location != NSNotFound) | |
1104 | return YES; | |
1105 | ||
1106 | return NO; | |
1107 | } | |
1108 | ||
1109 | - (NSComparisonResult) compareByName:(Package *)package { | |
1110 | return [[self name] caseInsensitiveCompare:[package name]]; | |
b19871dd JF |
1111 | } |
1112 | ||
1113 | - (NSComparisonResult) compareBySectionAndName:(Package *)package { | |
b4d89997 | 1114 | NSComparisonResult result = [[self section] caseInsensitiveCompare:[package section]]; |
b19871dd JF |
1115 | if (result != NSOrderedSame) |
1116 | return result; | |
b4d89997 JF |
1117 | return [self compareByName:package]; |
1118 | } | |
1119 | ||
1120 | - (NSComparisonResult) compareForChanges:(Package *)package { | |
1121 | BOOL lhs = [self upgradable]; | |
1122 | BOOL rhs = [package upgradable]; | |
1123 | ||
1124 | if (lhs != rhs) | |
1125 | return lhs ? NSOrderedAscending : NSOrderedDescending; | |
1126 | else if (!lhs) { | |
1127 | switch ([[self seen] compare:[package seen]]) { | |
1128 | case NSOrderedAscending: | |
1129 | return NSOrderedDescending; | |
1130 | case NSOrderedSame: | |
1131 | break; | |
1132 | case NSOrderedDescending: | |
1133 | return NSOrderedAscending; | |
1134 | default: | |
1135 | _assert(false); | |
1136 | } | |
1137 | } | |
1138 | ||
1139 | return [self compareByName:package]; | |
b19871dd JF |
1140 | } |
1141 | ||
1142 | - (void) install { | |
1143 | pkgProblemResolver *resolver = [database_ resolver]; | |
1144 | resolver->Clear(iterator_); | |
1145 | resolver->Protect(iterator_); | |
1146 | [database_ cache]->MarkInstall(iterator_, false); | |
1147 | } | |
1148 | ||
1149 | - (void) remove { | |
1150 | pkgProblemResolver *resolver = [database_ resolver]; | |
1151 | resolver->Clear(iterator_); | |
1152 | resolver->Protect(iterator_); | |
1153 | resolver->Remove(iterator_); | |
1154 | [database_ cache]->MarkDelete(iterator_, true); | |
1155 | } | |
1156 | ||
1157 | @end | |
1158 | /* }}} */ | |
1159 | /* Section Class {{{ */ | |
1160 | @interface Section : NSObject { | |
1161 | NSString *name_; | |
1162 | size_t row_; | |
1163 | NSMutableArray *packages_; | |
1164 | } | |
1165 | ||
1166 | - (void) dealloc; | |
1167 | ||
1168 | - (Section *) initWithName:(NSString *)name row:(size_t)row; | |
1169 | - (NSString *) name; | |
1170 | - (size_t) row; | |
b4d89997 JF |
1171 | - (NSArray *) packages; |
1172 | - (size_t) count; | |
b19871dd JF |
1173 | - (void) addPackage:(Package *)package; |
1174 | @end | |
1175 | ||
1176 | @implementation Section | |
1177 | ||
1178 | - (void) dealloc { | |
1179 | [name_ release]; | |
1180 | [packages_ release]; | |
1181 | [super dealloc]; | |
1182 | } | |
3178d79b | 1183 | |
b19871dd JF |
1184 | - (Section *) initWithName:(NSString *)name row:(size_t)row { |
1185 | if ((self = [super init]) != nil) { | |
1186 | name_ = [name retain]; | |
1187 | row_ = row; | |
1188 | packages_ = [[NSMutableArray arrayWithCapacity:16] retain]; | |
1189 | } return self; | |
1190 | } | |
3178d79b | 1191 | |
b19871dd JF |
1192 | - (NSString *) name { |
1193 | return name_; | |
1194 | } | |
3178d79b | 1195 | |
b19871dd JF |
1196 | - (size_t) row { |
1197 | return row_; | |
1198 | } | |
3178d79b | 1199 | |
b4d89997 JF |
1200 | - (NSArray *) packages { |
1201 | return packages_; | |
1202 | } | |
1203 | ||
1204 | - (size_t) count { | |
1205 | return [packages_ count]; | |
1206 | } | |
1207 | ||
b19871dd JF |
1208 | - (void) addPackage:(Package *)package { |
1209 | [packages_ addObject:package]; | |
3178d79b JF |
1210 | } |
1211 | ||
dc5812ec JF |
1212 | @end |
1213 | /* }}} */ | |
b19871dd | 1214 | |
dc5812ec | 1215 | /* Package View {{{ */ |
b4d89997 JF |
1216 | @protocol PackageViewDelegate |
1217 | - (void) performPackage:(Package *)package; | |
1218 | @end | |
1219 | ||
8da60fb7 JF |
1220 | @interface PackageView : UIView { |
1221 | UIPreferencesTable *table_; | |
dc5812ec | 1222 | Package *package_; |
b4d89997 | 1223 | UITextView *description_; |
8da60fb7 | 1224 | id delegate_; |
dc5812ec JF |
1225 | } |
1226 | ||
2367a917 JF |
1227 | - (void) dealloc; |
1228 | ||
dc5812ec | 1229 | - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table; |
8fe19fc1 | 1230 | - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group; |
b4d89997 | 1231 | - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed; |
dc5812ec JF |
1232 | - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group; |
1233 | - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group; | |
1234 | ||
8da60fb7 JF |
1235 | - (BOOL) canSelectRow:(int)row; |
1236 | - (void) tableRowSelected:(NSNotification *)notification; | |
1237 | ||
b4d89997 JF |
1238 | - (Package *) package; |
1239 | ||
1240 | - (id) initWithFrame:(struct CGRect)frame; | |
dc5812ec | 1241 | - (void) setPackage:(Package *)package; |
8da60fb7 | 1242 | - (void) setDelegate:(id)delegate; |
dc5812ec JF |
1243 | @end |
1244 | ||
1245 | @implementation PackageView | |
1246 | ||
2367a917 JF |
1247 | - (void) dealloc { |
1248 | if (package_ != nil) | |
1249 | [package_ release]; | |
b4d89997 JF |
1250 | if (description_ != nil) |
1251 | [description_ release]; | |
8da60fb7 | 1252 | [table_ release]; |
2367a917 JF |
1253 | [super dealloc]; |
1254 | } | |
1255 | ||
dc5812ec JF |
1256 | - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table { |
1257 | return 2; | |
1258 | } | |
1259 | ||
1260 | - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group { | |
1261 | switch (group) { | |
b4d89997 JF |
1262 | case 0: return nil; |
1263 | case 1: return @"Details"; | |
1264 | case 2: return @"Source"; | |
dc5812ec JF |
1265 | |
1266 | default: _assert(false); | |
1267 | } | |
1268 | } | |
1269 | ||
b4d89997 JF |
1270 | - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed { |
1271 | if (group != 0 || row != 1) | |
1272 | return proposed; | |
1273 | else | |
1274 | return [description_ visibleTextRect].size.height + TextViewOffset_; | |
1275 | } | |
1276 | ||
dc5812ec JF |
1277 | - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group { |
1278 | switch (group) { | |
b4d89997 JF |
1279 | case 0: return 2; |
1280 | case 1: return 5; | |
1281 | case 2: return 0; | |
dc5812ec JF |
1282 | |
1283 | default: _assert(false); | |
1284 | } | |
1285 | } | |
1286 | ||
1287 | - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group { | |
b4d89997 JF |
1288 | UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease]; |
1289 | [cell setShowSelection:NO]; | |
dc5812ec JF |
1290 | |
1291 | switch (group) { | |
1292 | case 0: switch (row) { | |
1293 | case 0: | |
b4d89997 JF |
1294 | [cell setTitle:[package_ name]]; |
1295 | [cell setValue:[package_ latest]]; | |
1296 | break; | |
1297 | ||
1298 | case 1: | |
1299 | [cell addSubview:description_]; | |
1300 | break; | |
1301 | ||
1302 | default: _assert(false); | |
1303 | } break; | |
1304 | ||
1305 | case 1: switch (row) { | |
1306 | case 0: | |
1307 | [cell setTitle:@"Identifier"]; | |
1308 | [cell setValue:[package_ id]]; | |
dc5812ec JF |
1309 | break; |
1310 | ||
3178d79b | 1311 | case 1: { |
b4d89997 | 1312 | [cell setTitle:@"Installed Version"]; |
3178d79b JF |
1313 | NSString *installed([package_ installed]); |
1314 | [cell setValue:(installed == nil ? @"n/a" : installed)]; | |
1315 | } break; | |
dc5812ec JF |
1316 | |
1317 | case 2: | |
dc5812ec JF |
1318 | [cell setTitle:@"Section"]; |
1319 | [cell setValue:[package_ section]]; | |
1320 | break; | |
1321 | ||
b4d89997 JF |
1322 | case 3: |
1323 | [cell setTitle:@"Expanded Size"]; | |
8fe19fc1 JF |
1324 | [cell setValue:SizeString([package_ size])]; |
1325 | break; | |
dc5812ec | 1326 | |
b4d89997 | 1327 | case 4: |
dc5812ec JF |
1328 | [cell setTitle:@"Maintainer"]; |
1329 | [cell setValue:[[package_ maintainer] name]]; | |
1330 | [cell setShowDisclosure:YES]; | |
1331 | [cell setShowSelection:YES]; | |
1332 | break; | |
1333 | ||
1334 | default: _assert(false); | |
1335 | } break; | |
1336 | ||
b4d89997 | 1337 | case 2: switch (row) { |
dc5812ec JF |
1338 | } break; |
1339 | ||
1340 | default: _assert(false); | |
1341 | } | |
1342 | ||
1343 | return cell; | |
1344 | } | |
1345 | ||
8da60fb7 JF |
1346 | - (BOOL) canSelectRow:(int)row { |
1347 | return YES; | |
1348 | } | |
1349 | ||
1350 | - (void) tableRowSelected:(NSNotification *)notification { | |
b4d89997 | 1351 | printf("%d\n", [table_ selectedRow]); |
8da60fb7 | 1352 | switch ([table_ selectedRow]) { |
b4d89997 | 1353 | case 8: |
8da60fb7 JF |
1354 | [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@", |
1355 | [[package_ maintainer] email], | |
1356 | [[NSString stringWithFormat:@"regarding apt package \"%@\"", [package_ name]] stringByAddingPercentEscapes] | |
1357 | ]]]; | |
1358 | break; | |
1359 | } | |
1360 | } | |
1361 | ||
b4d89997 JF |
1362 | - (Package *) package { |
1363 | return package_; | |
1364 | } | |
8da60fb7 | 1365 | |
b4d89997 JF |
1366 | - (id) initWithFrame:(struct CGRect)frame { |
1367 | if ((self = [super initWithFrame:frame]) != nil) { | |
8da60fb7 JF |
1368 | table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]]; |
1369 | [self addSubview:table_]; | |
1370 | ||
1371 | [table_ setDataSource:self]; | |
1372 | [table_ setDelegate:self]; | |
dc5812ec JF |
1373 | } return self; |
1374 | } | |
1375 | ||
1376 | - (void) setPackage:(Package *)package { | |
b4d89997 JF |
1377 | if (package_ != nil) { |
1378 | [package_ autorelease]; | |
1379 | package_ = nil; | |
1380 | } | |
1381 | ||
1382 | if (description_ != nil) { | |
1383 | [description_ release]; | |
1384 | description_ = nil; | |
1385 | } | |
1386 | ||
1387 | if (package != nil) { | |
1388 | package_ = [package retain]; | |
1389 | ||
1390 | NSString *description([package description]); | |
1391 | if (description == nil) | |
1392 | description = [package tagline]; | |
1393 | description_ = [GetTextView(description, 12, true) retain]; | |
1394 | ||
1395 | CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); | |
1396 | CGColor black(space, 0, 0, 0, 1); | |
1397 | [description_ setTextColor:black]; | |
1398 | CGColorSpaceRelease(space); | |
1399 | ||
1400 | [table_ reloadData]; | |
1401 | } | |
8da60fb7 JF |
1402 | } |
1403 | ||
1404 | - (void) setDelegate:(id)delegate { | |
1405 | delegate_ = delegate; | |
dc5812ec JF |
1406 | } |
1407 | ||
2367a917 JF |
1408 | @end |
1409 | /* }}} */ | |
1410 | /* Package Cell {{{ */ | |
1411 | @interface PackageCell : UITableCell { | |
1412 | UITextLabel *name_; | |
b4d89997 | 1413 | UITextLabel *version_; |
2367a917 | 1414 | UITextLabel *description_; |
b4d89997 | 1415 | SEL versioner_; |
2367a917 JF |
1416 | } |
1417 | ||
1418 | - (void) dealloc; | |
1419 | ||
b4d89997 | 1420 | - (PackageCell *) initWithVersioner:(SEL)versioner; |
1d80f6b9 | 1421 | - (void) setPackage:(Package *)package; |
2367a917 JF |
1422 | |
1423 | - (void) _setSelected:(float)fraction; | |
1424 | - (void) setSelected:(BOOL)selected; | |
1425 | - (void) setSelected:(BOOL)selected withFade:(BOOL)fade; | |
1426 | - (void) _setSelectionFadeFraction:(float)fraction; | |
1427 | ||
1428 | @end | |
1429 | ||
1430 | @implementation PackageCell | |
1431 | ||
1432 | - (void) dealloc { | |
1433 | [name_ release]; | |
1434 | [version_ release]; | |
1435 | [description_ release]; | |
1436 | [super dealloc]; | |
1437 | } | |
1438 | ||
b4d89997 | 1439 | - (PackageCell *) initWithVersioner:(SEL)versioner { |
2367a917 | 1440 | if ((self = [super init]) != nil) { |
b4d89997 | 1441 | versioner_ = versioner; |
1d80f6b9 | 1442 | |
2367a917 JF |
1443 | GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22); |
1444 | GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16); | |
1445 | GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14); | |
1446 | ||
1447 | CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); | |
b4d89997 JF |
1448 | |
1449 | CGColor clear(space, 0, 0, 0, 0); | |
2367a917 JF |
1450 | |
1451 | name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 7, 250, 25)]; | |
b4d89997 | 1452 | [name_ setBackgroundColor:clear]; |
2367a917 JF |
1453 | [name_ setFont:bold]; |
1454 | ||
b4d89997 JF |
1455 | version_ = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(286, 7, 70, 25)]; |
1456 | [version_ setBackgroundColor:clear]; | |
2367a917 JF |
1457 | [version_ setFont:large]; |
1458 | ||
1459 | description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(13, 35, 315, 20)]; | |
b4d89997 | 1460 | [description_ setBackgroundColor:clear]; |
2367a917 JF |
1461 | [description_ setFont:small]; |
1462 | ||
1463 | [self addSubview:name_]; | |
1464 | [self addSubview:version_]; | |
1465 | [self addSubview:description_]; | |
1466 | ||
b4d89997 JF |
1467 | CGColorSpaceRelease(space); |
1468 | ||
2367a917 JF |
1469 | CFRelease(small); |
1470 | CFRelease(large); | |
1471 | CFRelease(bold); | |
1472 | } return self; | |
1473 | } | |
1474 | ||
1d80f6b9 JF |
1475 | - (void) setPackage:(Package *)package { |
1476 | [name_ setText:[package name]]; | |
b4d89997 | 1477 | [version_ setText:[package latest]]; |
1d80f6b9 JF |
1478 | [description_ setText:[package tagline]]; |
1479 | } | |
1480 | ||
2367a917 JF |
1481 | - (void) _setSelected:(float)fraction { |
1482 | CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); | |
1483 | ||
b4d89997 | 1484 | CGColor black(space, |
2367a917 JF |
1485 | interpolate(0.0, 1.0, fraction), |
1486 | interpolate(0.0, 1.0, fraction), | |
1487 | interpolate(0.0, 1.0, fraction), | |
b4d89997 | 1488 | 1.0); |
2367a917 | 1489 | |
b4d89997 | 1490 | CGColor blue(space, |
2367a917 JF |
1491 | interpolate(0.2, 1.0, fraction), |
1492 | interpolate(0.2, 1.0, fraction), | |
1493 | interpolate(1.0, 1.0, fraction), | |
b4d89997 | 1494 | 1.0); |
2367a917 | 1495 | |
b4d89997 | 1496 | CGColor gray(space, |
2367a917 JF |
1497 | interpolate(0.4, 1.0, fraction), |
1498 | interpolate(0.4, 1.0, fraction), | |
1499 | interpolate(0.4, 1.0, fraction), | |
b4d89997 JF |
1500 | 1.0); |
1501 | ||
1502 | [name_ setColor:black]; | |
1503 | [version_ setColor:blue]; | |
1504 | [description_ setColor:gray]; | |
2367a917 | 1505 | |
b4d89997 | 1506 | CGColorSpaceRelease(space); |
2367a917 JF |
1507 | } |
1508 | ||
1509 | - (void) setSelected:(BOOL)selected { | |
1510 | [self _setSelected:(selected ? 1.0 : 0.0)]; | |
1511 | [super setSelected:selected]; | |
1512 | } | |
1513 | ||
1514 | - (void) setSelected:(BOOL)selected withFade:(BOOL)fade { | |
1515 | if (!fade) | |
1516 | [self _setSelected:(selected ? 1.0 : 0.0)]; | |
1517 | [super setSelected:selected withFade:fade]; | |
1518 | } | |
1519 | ||
1520 | - (void) _setSelectionFadeFraction:(float)fraction { | |
1521 | [self _setSelected:fraction]; | |
1522 | [super _setSelectionFadeFraction:fraction]; | |
1523 | } | |
1524 | ||
b19871dd JF |
1525 | @end |
1526 | /* }}} */ | |
1527 | ||
b4d89997 JF |
1528 | /* Database Implementation {{{ */ |
1529 | @implementation Database | |
b19871dd | 1530 | |
b4d89997 JF |
1531 | - (void) dealloc { |
1532 | _assert(false); | |
1533 | [super dealloc]; | |
b19871dd JF |
1534 | } |
1535 | ||
b4d89997 JF |
1536 | - (void) _readStatus:(NSNumber *)fd { |
1537 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
1538 | ||
1539 | __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in); | |
1540 | std::istream is(&ib); | |
1541 | std::string line; | |
b19871dd | 1542 | |
b4d89997 JF |
1543 | const char *error; |
1544 | int offset; | |
1545 | pcre *code = pcre_compile("^([^:]*):([^:]*):([^:]*):(.*)$", 0, &error, &offset, NULL); | |
b19871dd | 1546 | |
b4d89997 JF |
1547 | pcre_extra *study = NULL; |
1548 | int capture; | |
1549 | pcre_fullinfo(code, study, PCRE_INFO_CAPTURECOUNT, &capture); | |
1550 | int matches[(capture + 1) * 3]; | |
b19871dd | 1551 | |
b4d89997 JF |
1552 | while (std::getline(is, line)) { |
1553 | const char *data(line.c_str()); | |
b19871dd | 1554 | |
b4d89997 | 1555 | _assert(pcre_exec(code, study, data, line.size(), 0, 0, matches, sizeof(matches) / sizeof(matches[0])) >= 0); |
b19871dd | 1556 | |
b4d89997 JF |
1557 | std::istringstream buffer(line.substr(matches[6], matches[7] - matches[6])); |
1558 | float percent; | |
1559 | buffer >> percent; | |
1560 | [delegate_ setPercent:(percent / 100)]; | |
b19871dd | 1561 | |
b4d89997 JF |
1562 | NSString *string = [NSString stringWithCString:(data + matches[8]) length:(matches[9] - matches[8])]; |
1563 | std::string type(line.substr(matches[2], matches[3] - matches[2])); | |
b19871dd | 1564 | |
b4d89997 JF |
1565 | if (type == "pmerror") |
1566 | [delegate_ setError:string]; | |
1567 | else if (type == "pmstatus") | |
1568 | [delegate_ setTitle:string]; | |
1569 | else if (type == "pmconffile") | |
1570 | ; | |
1571 | else _assert(false); | |
1572 | } | |
b19871dd | 1573 | |
b4d89997 JF |
1574 | [pool release]; |
1575 | _assert(false); | |
b19871dd JF |
1576 | } |
1577 | ||
b4d89997 JF |
1578 | - (void) _readOutput:(NSNumber *)fd { |
1579 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
1580 | ||
1581 | __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in); | |
1582 | std::istream is(&ib); | |
1583 | std::string line; | |
b19871dd | 1584 | |
b4d89997 JF |
1585 | while (std::getline(is, line)) |
1586 | [delegate_ addOutput:[NSString stringWithCString:line.c_str()]]; | |
b19871dd | 1587 | |
b4d89997 JF |
1588 | [pool release]; |
1589 | _assert(false); | |
b19871dd JF |
1590 | } |
1591 | ||
b4d89997 JF |
1592 | - (Package *) packageWithName:(NSString *)name { |
1593 | pkgCache::PkgIterator iterator(cache_->FindPkg([name cString])); | |
1594 | return iterator.end() ? nil : [Package packageWithIterator:iterator database:self]; | |
b19871dd JF |
1595 | } |
1596 | ||
b4d89997 JF |
1597 | - (Database *) init { |
1598 | if ((self = [super init]) != nil) { | |
1599 | records_ = NULL; | |
1600 | resolver_ = NULL; | |
1601 | fetcher_ = NULL; | |
1602 | lock_ = NULL; | |
b19871dd | 1603 | |
b4d89997 | 1604 | int fds[2]; |
b19871dd | 1605 | |
b4d89997 JF |
1606 | _assert(pipe(fds) != -1); |
1607 | statusfd_ = fds[1]; | |
b19871dd | 1608 | |
b4d89997 JF |
1609 | [NSThread |
1610 | detachNewThreadSelector:@selector(_readStatus:) | |
1611 | toTarget:self | |
1612 | withObject:[[NSNumber numberWithInt:fds[0]] retain] | |
1613 | ]; | |
1614 | ||
1615 | _assert(pipe(fds) != -1); | |
1616 | _assert(dup2(fds[1], 1) != -1); | |
1617 | _assert(close(fds[1]) != -1); | |
1618 | ||
1619 | [NSThread | |
1620 | detachNewThreadSelector:@selector(_readOutput:) | |
1621 | toTarget:self | |
1622 | withObject:[[NSNumber numberWithInt:fds[0]] retain] | |
1623 | ]; | |
1624 | } return self; | |
b19871dd JF |
1625 | } |
1626 | ||
b4d89997 JF |
1627 | - (pkgCacheFile &) cache { |
1628 | return cache_; | |
b19871dd JF |
1629 | } |
1630 | ||
b4d89997 JF |
1631 | - (pkgRecords *) records { |
1632 | return records_; | |
b19871dd JF |
1633 | } |
1634 | ||
b4d89997 JF |
1635 | - (pkgProblemResolver *) resolver { |
1636 | return resolver_; | |
b19871dd JF |
1637 | } |
1638 | ||
b4d89997 JF |
1639 | - (pkgAcquire &) fetcher { |
1640 | return *fetcher_; | |
1641 | } | |
b19871dd | 1642 | |
b4d89997 JF |
1643 | - (void) reloadData { |
1644 | _error->Discard(); | |
1645 | manager_ = NULL; | |
1646 | delete lock_; | |
1647 | delete fetcher_; | |
1648 | delete resolver_; | |
1649 | delete records_; | |
1650 | cache_.Close(); | |
1651 | _assert(cache_.Open(progress_, true)); | |
1652 | records_ = new pkgRecords(cache_); | |
1653 | resolver_ = new pkgProblemResolver(cache_); | |
1654 | fetcher_ = new pkgAcquire(&status_); | |
1655 | lock_ = NULL; | |
1656 | } | |
b19871dd | 1657 | |
b4d89997 JF |
1658 | - (void) prepare { |
1659 | pkgRecords records(cache_); | |
b19871dd | 1660 | |
b4d89997 JF |
1661 | lock_ = new FileFd(); |
1662 | lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock")); | |
1663 | _assert(!_error->PendingError()); | |
b19871dd | 1664 | |
b4d89997 JF |
1665 | pkgSourceList list; |
1666 | _assert(list.ReadMainList()); | |
b19871dd | 1667 | |
b4d89997 JF |
1668 | manager_ = (_system->CreatePM(cache_)); |
1669 | _assert(manager_->GetArchives(fetcher_, &list, &records)); | |
1670 | _assert(!_error->PendingError()); | |
b19871dd JF |
1671 | } |
1672 | ||
b4d89997 JF |
1673 | - (void) perform { |
1674 | if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue) | |
1675 | return; | |
b19871dd | 1676 | |
b4d89997 JF |
1677 | _system->UnLock(); |
1678 | pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_); | |
b19871dd | 1679 | |
b4d89997 JF |
1680 | if (result == pkgPackageManager::Failed) |
1681 | return; | |
1682 | if (_error->PendingError()) | |
1683 | return; | |
1684 | if (result != pkgPackageManager::Completed) | |
1685 | return; | |
1686 | } | |
b19871dd | 1687 | |
b4d89997 JF |
1688 | - (void) update { |
1689 | pkgSourceList list; | |
1690 | _assert(list.ReadMainList()); | |
b19871dd | 1691 | |
b4d89997 JF |
1692 | FileFd lock; |
1693 | lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock")); | |
1694 | _assert(!_error->PendingError()); | |
b19871dd | 1695 | |
b4d89997 JF |
1696 | pkgAcquire fetcher(&status_); |
1697 | _assert(list.GetIndexes(&fetcher)); | |
1698 | _assert(fetcher.Run(PulseInterval_) != pkgAcquire::Failed); | |
b19871dd | 1699 | |
b4d89997 JF |
1700 | bool failed = false; |
1701 | for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++) | |
1702 | if ((*item)->Status != pkgAcquire::Item::StatDone) { | |
1703 | (*item)->Finished(); | |
1704 | failed = true; | |
1705 | } | |
b19871dd | 1706 | |
b4d89997 JF |
1707 | if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) { |
1708 | _assert(fetcher.Clean(_config->FindDir("Dir::State::lists"))); | |
1709 | _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/")); | |
1710 | } | |
b19871dd | 1711 | |
b4d89997 | 1712 | [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"]; |
b19871dd JF |
1713 | } |
1714 | ||
b4d89997 JF |
1715 | - (void) upgrade { |
1716 | _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0); | |
1717 | _assert(pkgApplyStatus(cache_)); | |
b19871dd | 1718 | |
b4d89997 JF |
1719 | if (cache_->BrokenCount() != 0) { |
1720 | _assert(pkgFixBroken(cache_)); | |
1721 | _assert(cache_->BrokenCount() == 0); | |
1722 | _assert(pkgMinimizeUpgrade(cache_)); | |
1723 | } | |
b19871dd | 1724 | |
b4d89997 | 1725 | _assert(pkgDistUpgrade(cache_)); |
b19871dd JF |
1726 | } |
1727 | ||
b4d89997 JF |
1728 | - (void) setDelegate:(id)delegate { |
1729 | delegate_ = delegate; | |
1730 | status_.setDelegate(delegate); | |
1731 | progress_.setDelegate(delegate); | |
b19871dd JF |
1732 | } |
1733 | ||
8da60fb7 JF |
1734 | @end |
1735 | /* }}} */ | |
b19871dd | 1736 | |
b4d89997 JF |
1737 | /* Progress Data {{{ */ |
1738 | @interface ProgressData : NSObject { | |
1739 | SEL selector_; | |
1740 | id target_; | |
1741 | id object_; | |
1742 | } | |
b19871dd | 1743 | |
b4d89997 | 1744 | - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object; |
b19871dd | 1745 | |
b4d89997 JF |
1746 | - (SEL) selector; |
1747 | - (id) target; | |
1748 | - (id) object; | |
8da60fb7 JF |
1749 | @end |
1750 | ||
b4d89997 | 1751 | @implementation ProgressData |
8da60fb7 | 1752 | |
b4d89997 JF |
1753 | - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object { |
1754 | if ((self = [super init]) != nil) { | |
1755 | selector_ = selector; | |
1756 | target_ = target; | |
1757 | object_ = object; | |
1758 | } return self; | |
b19871dd JF |
1759 | } |
1760 | ||
b4d89997 JF |
1761 | - (SEL) selector { |
1762 | return selector_; | |
b19871dd JF |
1763 | } |
1764 | ||
b4d89997 JF |
1765 | - (id) target { |
1766 | return target_; | |
b19871dd JF |
1767 | } |
1768 | ||
b4d89997 JF |
1769 | - (id) object { |
1770 | return object_; | |
b19871dd JF |
1771 | } |
1772 | ||
b4d89997 JF |
1773 | @end |
1774 | /* }}} */ | |
1775 | /* Progress View {{{ */ | |
1776 | @interface ProgressView : UIView < | |
1777 | ProgressDelegate | |
1778 | > { | |
1779 | UIView *view_; | |
1780 | UIView *background_; | |
1781 | UITransitionView *transition_; | |
1782 | UIView *overlay_; | |
1783 | UINavigationBar *navbar_; | |
1784 | UIProgressBar *progress_; | |
1785 | UITextView *output_; | |
1786 | UITextLabel *status_; | |
1787 | id delegate_; | |
b19871dd JF |
1788 | } |
1789 | ||
b4d89997 | 1790 | - (void) dealloc; |
b19871dd | 1791 | |
b31b87cc JF |
1792 | - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to; |
1793 | ||
b4d89997 JF |
1794 | - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate; |
1795 | - (void) setContentView:(UIView *)view; | |
1796 | - (void) resetView; | |
b19871dd | 1797 | |
b4d89997 | 1798 | - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button; |
b19871dd | 1799 | |
b4d89997 JF |
1800 | - (void) _retachThread; |
1801 | - (void) _detachNewThreadData:(ProgressData *)data; | |
1802 | - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title; | |
b19871dd | 1803 | |
b4d89997 JF |
1804 | - (void) setError:(NSString *)error; |
1805 | - (void) _setError:(NSString *)error; | |
b19871dd | 1806 | |
b4d89997 JF |
1807 | - (void) setTitle:(NSString *)title; |
1808 | - (void) _setTitle:(NSString *)title; | |
b19871dd | 1809 | |
b4d89997 JF |
1810 | - (void) setPercent:(float)percent; |
1811 | - (void) _setPercent:(NSNumber *)percent; | |
8da60fb7 | 1812 | |
b4d89997 JF |
1813 | - (void) addOutput:(NSString *)output; |
1814 | - (void) _addOutput:(NSString *)output; | |
1815 | @end | |
1816 | ||
1817 | @protocol ProgressViewDelegate | |
1818 | - (void) progressViewIsComplete:(ProgressView *)sender; | |
1819 | @end | |
1820 | ||
1821 | @implementation ProgressView | |
8da60fb7 JF |
1822 | |
1823 | - (void) dealloc { | |
b4d89997 | 1824 | [view_ release]; |
b31b87cc JF |
1825 | if (background_ != nil) |
1826 | [background_ release]; | |
b4d89997 JF |
1827 | [transition_ release]; |
1828 | [overlay_ release]; | |
1829 | [navbar_ release]; | |
1830 | [progress_ release]; | |
1831 | [output_ release]; | |
1832 | [status_ release]; | |
8da60fb7 JF |
1833 | [super dealloc]; |
1834 | } | |
1835 | ||
b31b87cc JF |
1836 | - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to { |
1837 | if (bootstrap_ && from == overlay_ && to == view_) | |
1838 | exit(0); | |
1839 | } | |
1840 | ||
b4d89997 | 1841 | - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate { |
8da60fb7 | 1842 | if ((self = [super initWithFrame:frame]) != nil) { |
b4d89997 JF |
1843 | delegate_ = delegate; |
1844 | ||
1845 | CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); | |
1846 | ||
1847 | CGColor black(space, 0.0, 0.0, 0.0, 1.0); | |
1848 | CGColor white(space, 1.0, 1.0, 1.0, 1.0); | |
1849 | CGColor clear(space, 0.0, 0.0, 0.0, 0.0); | |
1850 | ||
b4d89997 | 1851 | transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]]; |
b31b87cc | 1852 | [transition_ setDelegate:self]; |
b4d89997 JF |
1853 | |
1854 | overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]]; | |
8da60fb7 | 1855 | |
b31b87cc JF |
1856 | if (bootstrap_) |
1857 | [overlay_ setBackgroundColor:black]; | |
1858 | else { | |
1859 | background_ = [[UIView alloc] initWithFrame:[self bounds]]; | |
1860 | [background_ setBackgroundColor:black]; | |
1861 | [self addSubview:background_]; | |
1862 | } | |
1863 | ||
1864 | [self addSubview:transition_]; | |
1865 | ||
8da60fb7 JF |
1866 | CGSize navsize = [UINavigationBar defaultSize]; |
1867 | CGRect navrect = {{0, 0}, navsize}; | |
8da60fb7 JF |
1868 | |
1869 | navbar_ = [[UINavigationBar alloc] initWithFrame:navrect]; | |
b4d89997 | 1870 | [overlay_ addSubview:navbar_]; |
8da60fb7 JF |
1871 | |
1872 | [navbar_ setBarStyle:1]; | |
1873 | [navbar_ setDelegate:self]; | |
1874 | ||
b4d89997 | 1875 | UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease]; |
8da60fb7 JF |
1876 | [navbar_ pushNavigationItem:navitem]; |
1877 | ||
b4d89997 JF |
1878 | CGRect bounds = [overlay_ bounds]; |
1879 | CGSize prgsize = [UIProgressBar defaultSize]; | |
1880 | ||
1881 | CGRect prgrect = {{ | |
1882 | (bounds.size.width - prgsize.width) / 2, | |
1883 | bounds.size.height - prgsize.height - 20 | |
1884 | }, prgsize}; | |
1885 | ||
1886 | progress_ = [[UIProgressBar alloc] initWithFrame:prgrect]; | |
1887 | [overlay_ addSubview:progress_]; | |
1888 | ||
1889 | status_ = [[UITextLabel alloc] initWithFrame:CGRectMake( | |
1890 | 10, | |
1891 | bounds.size.height - prgsize.height - 50, | |
1892 | bounds.size.width - 20, | |
1893 | 24 | |
8da60fb7 JF |
1894 | )]; |
1895 | ||
b4d89997 JF |
1896 | [status_ setColor:white]; |
1897 | [status_ setBackgroundColor:clear]; | |
b19871dd | 1898 | |
b4d89997 JF |
1899 | [status_ setCentersHorizontally:YES]; |
1900 | //[status_ setFont:font]; | |
b19871dd | 1901 | |
b4d89997 JF |
1902 | output_ = [[UITextView alloc] initWithFrame:CGRectMake( |
1903 | 10, | |
1904 | navrect.size.height + 20, | |
1905 | bounds.size.width - 20, | |
1906 | bounds.size.height - navsize.height - 62 - navrect.size.height | |
1907 | )]; | |
b19871dd | 1908 | |
b4d89997 JF |
1909 | //[output_ setTextFont:@"Courier New"]; |
1910 | [output_ setTextSize:12]; | |
8da60fb7 | 1911 | |
b4d89997 JF |
1912 | [output_ setTextColor:white]; |
1913 | [output_ setBackgroundColor:clear]; | |
8da60fb7 | 1914 | |
b4d89997 JF |
1915 | [output_ setMarginTop:0]; |
1916 | [output_ setAllowsRubberBanding:YES]; | |
8da60fb7 | 1917 | |
b4d89997 JF |
1918 | [overlay_ addSubview:output_]; |
1919 | [overlay_ addSubview:status_]; | |
3178d79b | 1920 | |
b4d89997 | 1921 | [progress_ setStyle:0]; |
3178d79b | 1922 | |
b4d89997 JF |
1923 | CGColorSpaceRelease(space); |
1924 | } return self; | |
3178d79b JF |
1925 | } |
1926 | ||
b4d89997 JF |
1927 | - (void) setContentView:(UIView *)view { |
1928 | view_ = [view retain]; | |
3178d79b JF |
1929 | } |
1930 | ||
b4d89997 JF |
1931 | - (void) resetView { |
1932 | [transition_ transition:6 toView:view_]; | |
8da60fb7 JF |
1933 | } |
1934 | ||
b4d89997 JF |
1935 | - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button { |
1936 | [sheet dismiss]; | |
1937 | } | |
dc5812ec | 1938 | |
b4d89997 JF |
1939 | - (void) _retachThread { |
1940 | [delegate_ progressViewIsComplete:self]; | |
1941 | [self resetView]; | |
1942 | } | |
dc5812ec | 1943 | |
b4d89997 | 1944 | - (void) _detachNewThreadData:(ProgressData *)data { |
2367a917 JF |
1945 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
1946 | ||
b4d89997 JF |
1947 | [[data target] performSelector:[data selector] withObject:[data object]]; |
1948 | [data release]; | |
2367a917 | 1949 | |
b4d89997 | 1950 | [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES]; |
2367a917 JF |
1951 | |
1952 | [pool release]; | |
1953 | } | |
1954 | ||
b4d89997 JF |
1955 | - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title { |
1956 | [navbar_ popNavigationItem]; | |
1957 | UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:title] autorelease]; | |
1958 | [navbar_ pushNavigationItem:navitem]; | |
2367a917 | 1959 | |
b4d89997 JF |
1960 | [status_ setText:nil]; |
1961 | [output_ setText:@""]; | |
1962 | [progress_ setProgress:0]; | |
2367a917 | 1963 | |
b4d89997 | 1964 | [transition_ transition:6 toView:overlay_]; |
2367a917 | 1965 | |
b4d89997 JF |
1966 | [NSThread |
1967 | detachNewThreadSelector:@selector(_detachNewThreadData:) | |
1968 | toTarget:self | |
1969 | withObject:[[ProgressData alloc] | |
1970 | initWithSelector:selector | |
1971 | target:target | |
1972 | object:object | |
1973 | ] | |
1974 | ]; | |
3178d79b JF |
1975 | } |
1976 | ||
b4d89997 JF |
1977 | - (void) setError:(NSString *)error { |
1978 | [self | |
1979 | performSelectorOnMainThread:@selector(_setError:) | |
1980 | withObject:error | |
1981 | waitUntilDone:YES | |
1982 | ]; | |
1983 | } | |
2367a917 | 1984 | |
b4d89997 JF |
1985 | - (void) _setError:(NSString *)error { |
1986 | UIAlertSheet *sheet = [[[UIAlertSheet alloc] | |
1987 | initWithTitle:@"Package Error" | |
1988 | buttons:[NSArray arrayWithObjects:@"Okay", nil] | |
1989 | defaultButtonIndex:0 | |
1990 | delegate:self | |
1991 | context:self | |
1992 | ] autorelease]; | |
2367a917 | 1993 | |
b4d89997 JF |
1994 | [sheet setBodyText:error]; |
1995 | [sheet popupAlertAnimated:YES]; | |
1996 | } | |
2367a917 | 1997 | |
b4d89997 JF |
1998 | - (void) setTitle:(NSString *)title { |
1999 | [self | |
2000 | performSelectorOnMainThread:@selector(_setTitle:) | |
2001 | withObject:title | |
2002 | waitUntilDone:YES | |
2003 | ]; | |
2004 | } | |
2367a917 | 2005 | |
b4d89997 JF |
2006 | - (void) _setTitle:(NSString *)title { |
2007 | [status_ setText:[title stringByAppendingString:@"..."]]; | |
dc5812ec JF |
2008 | } |
2009 | ||
b4d89997 JF |
2010 | - (void) setPercent:(float)percent { |
2011 | [self | |
2012 | performSelectorOnMainThread:@selector(_setPercent:) | |
2013 | withObject:[NSNumber numberWithFloat:percent] | |
2014 | waitUntilDone:YES | |
2015 | ]; | |
dc5812ec JF |
2016 | } |
2017 | ||
b4d89997 JF |
2018 | - (void) _setPercent:(NSNumber *)percent { |
2019 | [progress_ setProgress:[percent floatValue]]; | |
dc5812ec JF |
2020 | } |
2021 | ||
b4d89997 JF |
2022 | - (void) addOutput:(NSString *)output { |
2023 | [self | |
2024 | performSelectorOnMainThread:@selector(_addOutput:) | |
2025 | withObject:output | |
2026 | waitUntilDone:YES | |
2027 | ]; | |
dc5812ec JF |
2028 | } |
2029 | ||
b4d89997 JF |
2030 | - (void) _addOutput:(NSString *)output { |
2031 | [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]]; | |
2032 | CGSize size = [output_ contentSize]; | |
2033 | CGRect rect = {{0, size.height}, {size.width, 0}}; | |
2034 | [output_ scrollRectToVisible:rect animated:YES]; | |
8fe19fc1 JF |
2035 | } |
2036 | ||
b4d89997 JF |
2037 | @end |
2038 | /* }}} */ | |
2039 | ||
2040 | /* Package Table {{{ */ | |
2041 | @protocol PackageTableDelegate | |
2042 | - (void) packageTable:(id)table packageSelected:(Package *)package; | |
2043 | @end | |
2044 | ||
2045 | @interface PackageTable : UIView { | |
2046 | SEL versioner_; | |
2047 | UISectionList *list_; | |
2048 | ||
2049 | id delegate_; | |
2050 | NSArray *packages_; | |
2051 | NSMutableArray *sections_; | |
dc5812ec JF |
2052 | } |
2053 | ||
b4d89997 | 2054 | - (void) dealloc; |
2367a917 | 2055 | |
b4d89997 JF |
2056 | - (int) numberOfSectionsInSectionList:(UISectionList *)list; |
2057 | - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section; | |
2058 | - (int) sectionList:(UISectionList *)list rowForSection:(int)section; | |
2367a917 | 2059 | |
b4d89997 JF |
2060 | - (int) numberOfRowsInTable:(UITable *)table; |
2061 | - (float) table:(UITable *)table heightForRow:(int)row; | |
2062 | - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing; | |
2063 | - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row; | |
2064 | - (void) tableRowSelected:(NSNotification *)notification; | |
2367a917 | 2065 | |
b4d89997 JF |
2066 | - (id) initWithFrame:(CGRect)frame versioner:(SEL)versioner; |
2067 | ||
2068 | - (void) setDelegate:(id)delegate; | |
2069 | - (void) setPackages:(NSArray *)packages; | |
2070 | ||
2071 | - (void) resetViewAnimated:(BOOL)animated; | |
2072 | - (UITable *) table; | |
2073 | @end | |
2074 | ||
2075 | @implementation PackageTable | |
2076 | ||
2077 | - (void) dealloc { | |
2078 | [list_ release]; | |
2079 | [sections_ release]; | |
2080 | if (packages_ != nil) | |
2081 | [packages_ release]; | |
2082 | [super dealloc]; | |
8fe19fc1 JF |
2083 | } |
2084 | ||
b4d89997 JF |
2085 | - (int) numberOfSectionsInSectionList:(UISectionList *)list { |
2086 | return [sections_ count]; | |
2087 | } | |
2367a917 | 2088 | |
b4d89997 JF |
2089 | - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section { |
2090 | return [[sections_ objectAtIndex:section] name]; | |
2091 | } | |
dc5812ec | 2092 | |
b4d89997 JF |
2093 | - (int) sectionList:(UISectionList *)list rowForSection:(int)section { |
2094 | return [[sections_ objectAtIndex:section] row]; | |
2367a917 JF |
2095 | } |
2096 | ||
b4d89997 JF |
2097 | - (int) numberOfRowsInTable:(UITable *)table { |
2098 | return [packages_ count]; | |
2099 | } | |
dc5812ec | 2100 | |
b4d89997 JF |
2101 | - (float) table:(UITable *)table heightForRow:(int)row { |
2102 | return 64; | |
2103 | } | |
dc5812ec | 2104 | |
b4d89997 JF |
2105 | - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing { |
2106 | if (reusing == nil) | |
2107 | reusing = [[[PackageCell alloc] initWithVersioner:versioner_] autorelease]; | |
2108 | [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]]; | |
2109 | return reusing; | |
2110 | } | |
dc5812ec | 2111 | |
b4d89997 JF |
2112 | - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row { |
2113 | return NO; | |
2114 | } | |
dc5812ec | 2115 | |
b4d89997 JF |
2116 | - (void) tableRowSelected:(NSNotification *)notification { |
2117 | int row = [[notification object] selectedRow]; | |
2118 | [delegate_ packageTable:self packageSelected:(row == INT_MAX ? nil : [packages_ objectAtIndex:row])]; | |
dc5812ec JF |
2119 | } |
2120 | ||
b4d89997 JF |
2121 | - (id) initWithFrame:(CGRect)frame versioner:(SEL)versioner { |
2122 | if ((self = [super initWithFrame:frame]) != nil) { | |
2123 | versioner_ = versioner; | |
2124 | sections_ = [[NSMutableArray arrayWithCapacity:16] retain]; | |
dc5812ec | 2125 | |
b4d89997 JF |
2126 | list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES]; |
2127 | [list_ setDataSource:self]; | |
dc5812ec | 2128 | |
b4d89997 JF |
2129 | UITableColumn *column = [[[UITableColumn alloc] |
2130 | initWithTitle:@"Name" | |
2131 | identifier:@"name" | |
2132 | width:frame.size.width | |
2133 | ] autorelease]; | |
2134 | ||
2135 | UITable *table = [list_ table]; | |
2136 | [table setSeparatorStyle:1]; | |
2137 | [table addTableColumn:column]; | |
2138 | [table setDelegate:self]; | |
2139 | [table setReusesTableCells:YES]; | |
2140 | ||
2141 | [self addSubview:list_]; | |
2142 | } return self; | |
dc5812ec JF |
2143 | } |
2144 | ||
2145 | - (void) setDelegate:(id)delegate { | |
2367a917 | 2146 | delegate_ = delegate; |
b4d89997 JF |
2147 | } |
2148 | ||
2149 | - (void) setPackages:(NSArray *)packages { | |
2150 | if (packages_ != nil) | |
2151 | [packages_ autorelease]; | |
2152 | _assert(packages != nil); | |
2153 | packages_ = [packages retain]; | |
2154 | ||
2155 | [sections_ removeAllObjects]; | |
2156 | ||
2157 | Section *section = nil; | |
2158 | ||
2159 | for (size_t offset(0); offset != [packages_ count]; ++offset) { | |
2160 | Package *package = [packages_ objectAtIndex:offset]; | |
2161 | NSString *name = [package index]; | |
2162 | ||
2163 | if (section == nil || ![[section name] isEqual:name]) { | |
2164 | section = [[[Section alloc] initWithName:name row:offset] autorelease]; | |
2165 | [sections_ addObject:section]; | |
2166 | } | |
2167 | ||
2168 | [section addPackage:package]; | |
2169 | } | |
2170 | ||
2171 | [list_ reloadData]; | |
2172 | } | |
2173 | ||
2174 | - (void) resetViewAnimated:(BOOL)animated { | |
2175 | [[list_ table] selectRow:-1 byExtendingSelection:NO withFade:animated]; | |
2176 | } | |
2177 | ||
2178 | - (UITable *) table { | |
2179 | return [list_ table]; | |
dc5812ec JF |
2180 | } |
2181 | ||
2182 | @end | |
b4d89997 | 2183 | /* }}} */ |
dc5812ec | 2184 | |
b4d89997 JF |
2185 | /* Section Cell {{{ */ |
2186 | @interface SectionCell : UITableCell { | |
2187 | UITextLabel *name_; | |
2188 | UITextLabel *count_; | |
dc5812ec JF |
2189 | } |
2190 | ||
b4d89997 JF |
2191 | - (void) dealloc; |
2192 | ||
2193 | - (id) init; | |
2194 | - (void) setSection:(Section *)section; | |
2195 | ||
2196 | - (void) _setSelected:(float)fraction; | |
2197 | - (void) setSelected:(BOOL)selected; | |
2198 | - (void) setSelected:(BOOL)selected withFade:(BOOL)fade; | |
2199 | - (void) _setSelectionFadeFraction:(float)fraction; | |
dc5812ec | 2200 | |
dc5812ec JF |
2201 | @end |
2202 | ||
b4d89997 | 2203 | @implementation SectionCell |
dc5812ec | 2204 | |
b4d89997 JF |
2205 | - (void) dealloc { |
2206 | [name_ release]; | |
2207 | [count_ release]; | |
2208 | [super dealloc]; | |
2209 | } | |
2210 | ||
2211 | - (id) init { | |
dc5812ec | 2212 | if ((self = [super init]) != nil) { |
b4d89997 JF |
2213 | GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22); |
2214 | GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 12); | |
2215 | ||
2216 | CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); | |
2217 | CGColor clear(space, 0, 0, 0, 0); | |
2218 | CGColor white(space, 1, 1, 1, 1); | |
2219 | ||
2220 | name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(47, 9, 250, 25)]; | |
2221 | [name_ setBackgroundColor:clear]; | |
2222 | [name_ setFont:bold]; | |
2223 | ||
2224 | count_ = [[UITextLabel alloc] initWithFrame:CGRectMake(11, 7, 29, 32)]; | |
2225 | [count_ setCentersHorizontally:YES]; | |
2226 | [count_ setBackgroundColor:clear]; | |
2227 | [count_ setFont:small]; | |
2228 | [count_ setColor:white]; | |
2229 | ||
2230 | UIImageView *folder = [[[UIImageView alloc] initWithFrame:CGRectMake(8, 7, 32, 32)] autorelease]; | |
2231 | [folder setImage:[UIImage applicationImageNamed:@"folder.png"]]; | |
2232 | ||
2233 | [self addSubview:folder]; | |
2234 | [self addSubview:name_]; | |
2235 | [self addSubview:count_]; | |
2236 | ||
2237 | [self _setSelected:0]; | |
2238 | ||
2239 | CGColorSpaceRelease(space); | |
2240 | ||
2241 | CFRelease(small); | |
2242 | CFRelease(bold); | |
dc5812ec JF |
2243 | } return self; |
2244 | } | |
2245 | ||
b4d89997 JF |
2246 | - (void) setSection:(Section *)section { |
2247 | if (section == nil) { | |
2248 | [name_ setText:@"All Packages"]; | |
2249 | [count_ setText:nil]; | |
2250 | } else { | |
2251 | [name_ setText:[section name]]; | |
2252 | [count_ setText:[NSString stringWithFormat:@"%d", [section count]]]; | |
2253 | } | |
dc5812ec JF |
2254 | } |
2255 | ||
b4d89997 JF |
2256 | - (void) _setSelected:(float)fraction { |
2257 | CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); | |
2258 | ||
2259 | CGColor black(space, | |
2260 | interpolate(0.0, 1.0, fraction), | |
2261 | interpolate(0.0, 1.0, fraction), | |
2262 | interpolate(0.0, 1.0, fraction), | |
2263 | 1.0); | |
2264 | ||
2265 | [name_ setColor:black]; | |
2266 | ||
2267 | CGColorSpaceRelease(space); | |
dc5812ec JF |
2268 | } |
2269 | ||
b4d89997 JF |
2270 | - (void) setSelected:(BOOL)selected { |
2271 | [self _setSelected:(selected ? 1.0 : 0.0)]; | |
2272 | [super setSelected:selected]; | |
dc5812ec JF |
2273 | } |
2274 | ||
b4d89997 JF |
2275 | - (void) setSelected:(BOOL)selected withFade:(BOOL)fade { |
2276 | if (!fade) | |
2277 | [self _setSelected:(selected ? 1.0 : 0.0)]; | |
2278 | [super setSelected:selected withFade:fade]; | |
dc5812ec JF |
2279 | } |
2280 | ||
b4d89997 JF |
2281 | - (void) _setSelectionFadeFraction:(float)fraction { |
2282 | [self _setSelected:fraction]; | |
2283 | [super _setSelectionFadeFraction:fraction]; | |
2284 | } | |
2367a917 | 2285 | |
b4d89997 JF |
2286 | @end |
2287 | /* }}} */ | |
2288 | /* Install View {{{ */ | |
2289 | @interface InstallView : ResetView < | |
2290 | PackageTableDelegate | |
2291 | > { | |
2292 | NSArray *sections_; | |
2293 | UITable *list_; | |
2294 | PackageTable *table_; | |
2295 | PackageView *view_; | |
2296 | NSString *section_; | |
2297 | NSString *package_; | |
2298 | NSMutableArray *packages_; | |
2299 | } | |
dc5812ec | 2300 | |
b4d89997 | 2301 | - (void) dealloc; |
2367a917 | 2302 | |
b4d89997 | 2303 | - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button; |
2367a917 | 2304 | |
b4d89997 JF |
2305 | - (int) numberOfRowsInTable:(UITable *)table; |
2306 | - (float) table:(UITable *)table heightForRow:(int)row; | |
2307 | - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing; | |
2308 | - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row; | |
2309 | - (void) tableRowSelected:(NSNotification *)notification; | |
2367a917 | 2310 | |
b4d89997 | 2311 | - (void) packageTable:(id)table packageSelected:(Package *)package; |
dc5812ec | 2312 | |
b4d89997 JF |
2313 | - (id) initWithFrame:(CGRect)frame; |
2314 | - (void) setPackages:(NSArray *)packages; | |
2315 | - (void) setDelegate:(id)delegate; | |
2367a917 JF |
2316 | @end |
2317 | ||
b4d89997 | 2318 | @implementation InstallView |
dc5812ec | 2319 | |
2367a917 | 2320 | - (void) dealloc { |
b4d89997 JF |
2321 | [packages_ release]; |
2322 | if (sections_ != nil) | |
2323 | [sections_ release]; | |
2324 | if (list_ != nil) | |
2325 | [list_ release]; | |
2326 | if (table_ != nil) | |
2327 | [table_ release]; | |
2328 | if (view_ != nil) | |
2329 | [view_ release]; | |
2330 | if (section_ != nil) | |
2331 | [section_ release]; | |
2332 | if (package_ != nil) | |
2333 | [package_ release]; | |
2367a917 JF |
2334 | [super dealloc]; |
2335 | } | |
2336 | ||
b4d89997 JF |
2337 | - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button { |
2338 | if (button == 0) { | |
2339 | [[view_ package] install]; | |
2340 | [delegate_ resolve]; | |
2341 | [delegate_ perform]; | |
2342 | } | |
2343 | } | |
2367a917 | 2344 | |
b4d89997 JF |
2345 | - (int) numberOfRowsInTable:(UITable *)table { |
2346 | return [sections_ count] + 1; | |
2347 | } | |
8da60fb7 | 2348 | |
b4d89997 JF |
2349 | - (float) table:(UITable *)table heightForRow:(int)row { |
2350 | return 45; | |
2351 | } | |
8da60fb7 | 2352 | |
b4d89997 JF |
2353 | - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing { |
2354 | if (reusing == nil) | |
2355 | reusing = [[[SectionCell alloc] init] autorelease]; | |
2356 | if (row == 0) | |
2357 | [(SectionCell *)reusing setSection:nil]; | |
2358 | else | |
2359 | [(SectionCell *)reusing setSection:[sections_ objectAtIndex:(row - 1)]]; | |
2360 | return reusing; | |
2361 | } | |
dc5812ec | 2362 | |
b4d89997 JF |
2363 | - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row { |
2364 | return YES; | |
2365 | } | |
dc5812ec | 2366 | |
b4d89997 JF |
2367 | - (void) tableRowSelected:(NSNotification *)notification { |
2368 | int row = [[notification object] selectedRow]; | |
dc5812ec | 2369 | |
b4d89997 JF |
2370 | if (row == INT_MAX) { |
2371 | [section_ release]; | |
2372 | section_ = nil; | |
dc5812ec | 2373 | |
b4d89997 JF |
2374 | [table_ release]; |
2375 | table_ = nil; | |
2376 | } else { | |
2377 | _assert(section_ == nil); | |
2378 | _assert(table_ == nil); | |
2367a917 | 2379 | |
b4d89997 JF |
2380 | Section *section; |
2381 | NSString *name; | |
2367a917 | 2382 | |
b4d89997 JF |
2383 | if (row == 0) { |
2384 | section = nil; | |
2385 | section_ = nil; | |
2386 | name = @"All Packages"; | |
2387 | } else { | |
2388 | section = [sections_ objectAtIndex:(row - 1)]; | |
2389 | name = [section name]; | |
2390 | section_ = [name retain]; | |
2391 | } | |
2367a917 | 2392 | |
b4d89997 JF |
2393 | table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)]; |
2394 | [table_ setDelegate:self]; | |
2395 | [table_ setPackages:(section == nil ? packages_ : [section packages])]; | |
2367a917 | 2396 | |
b4d89997 JF |
2397 | [self pushView:table_ withTitle:name backButtonTitle:@"Packages" rightButton:nil]; |
2398 | } | |
2399 | } | |
2367a917 | 2400 | |
b4d89997 JF |
2401 | - (void) packageTable:(id)table packageSelected:(Package *)package { |
2402 | if (package == nil) { | |
2403 | [package_ release]; | |
2404 | package_ = nil; | |
2367a917 | 2405 | |
b4d89997 JF |
2406 | [view_ release]; |
2407 | view_ = nil; | |
2408 | } else { | |
2409 | _assert(package_ == nil); | |
2410 | _assert(view_ == nil); | |
2367a917 | 2411 | |
b4d89997 | 2412 | package_ = [[package name] retain]; |
2367a917 | 2413 | |
b4d89997 JF |
2414 | view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]]; |
2415 | [view_ setDelegate:delegate_]; | |
2367a917 | 2416 | |
b4d89997 | 2417 | [view_ setPackage:package]; |
2367a917 | 2418 | |
b4d89997 JF |
2419 | [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:@"Install"]; |
2420 | } | |
2421 | } | |
2367a917 | 2422 | |
b4d89997 JF |
2423 | - (id) initWithFrame:(CGRect)frame { |
2424 | if ((self = [super initWithFrame:frame]) != nil) { | |
2425 | packages_ = [[NSMutableArray arrayWithCapacity:16] retain]; | |
2367a917 | 2426 | |
b4d89997 JF |
2427 | list_ = [[UITable alloc] initWithFrame:[transition_ bounds]]; |
2428 | [self pushView:list_ withTitle:@"Install" backButtonTitle:@"Sections" rightButton:nil]; | |
dc5812ec | 2429 | |
b4d89997 JF |
2430 | UITableColumn *column = [[[UITableColumn alloc] |
2431 | initWithTitle:@"Name" | |
2432 | identifier:@"name" | |
2433 | width:frame.size.width | |
2434 | ] autorelease]; | |
dc5812ec | 2435 | |
b4d89997 JF |
2436 | [list_ setDataSource:self]; |
2437 | [list_ setSeparatorStyle:1]; | |
2438 | [list_ addTableColumn:column]; | |
2439 | [list_ setDelegate:self]; | |
2440 | [list_ setReusesTableCells:YES]; | |
2367a917 | 2441 | |
b4d89997 JF |
2442 | [transition_ transition:0 toView:list_]; |
2443 | } return self; | |
2367a917 JF |
2444 | } |
2445 | ||
b4d89997 JF |
2446 | - (void) setPackages:(NSArray *)packages { |
2447 | [packages_ removeAllObjects]; | |
dc5812ec | 2448 | |
b4d89997 JF |
2449 | for (size_t i(0); i != [packages count]; ++i) { |
2450 | Package *package([packages objectAtIndex:i]); | |
2451 | if ([package installed] == nil) | |
2452 | [packages_ addObject:package]; | |
2453 | } | |
dc5812ec | 2454 | |
b4d89997 JF |
2455 | [packages_ sortUsingSelector:@selector(compareBySectionAndName:)]; |
2456 | NSMutableArray *sections = [NSMutableArray arrayWithCapacity:16]; | |
dc5812ec | 2457 | |
b4d89997 JF |
2458 | Section *nsection = nil; |
2459 | Package *npackage = nil; | |
dc5812ec | 2460 | |
b4d89997 JF |
2461 | Section *section = nil; |
2462 | for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) { | |
2463 | Package *package = [packages_ objectAtIndex:offset]; | |
2464 | NSString *name = [package section]; | |
2367a917 | 2465 | |
b4d89997 JF |
2466 | if (section == nil || ![[section name] isEqual:name]) { |
2467 | section = [[[Section alloc] initWithName:name row:offset] autorelease]; | |
dc5812ec | 2468 | |
b4d89997 JF |
2469 | if ([name isEqualToString:section_]) |
2470 | nsection = section; | |
2471 | [sections addObject:section]; | |
2472 | } | |
dc5812ec | 2473 | |
b4d89997 JF |
2474 | if ([[package name] isEqualToString:package_]) |
2475 | npackage = package; | |
2476 | [section addPackage:package]; | |
2477 | } | |
2367a917 | 2478 | |
b4d89997 JF |
2479 | if (sections_ != nil) |
2480 | [sections_ release]; | |
2481 | sections_ = [sections retain]; | |
2367a917 | 2482 | |
b4d89997 | 2483 | [packages_ sortUsingSelector:@selector(compareByName:)]; |
2367a917 | 2484 | |
b4d89997 | 2485 | [list_ reloadData]; |
2367a917 | 2486 | |
b4d89997 | 2487 | unsigned views(0); |
2367a917 | 2488 | |
b4d89997 JF |
2489 | if (npackage != nil) |
2490 | [view_ setPackage:npackage]; | |
2491 | else if (package_ != nil) | |
2492 | ++views; | |
2367a917 | 2493 | |
b4d89997 JF |
2494 | if (nsection != nil) |
2495 | [table_ setPackages:[nsection packages]]; | |
2496 | else if (section_ != nil) | |
2497 | ++views; | |
2367a917 | 2498 | |
b4d89997 JF |
2499 | [self popViews:views]; |
2500 | [self setPrompt]; | |
2367a917 JF |
2501 | } |
2502 | ||
b4d89997 JF |
2503 | - (void) setDelegate:(id)delegate { |
2504 | if (view_ != nil) | |
2505 | [view_ setDelegate:delegate]; | |
2506 | [super setDelegate:delegate]; | |
dc5812ec JF |
2507 | } |
2508 | ||
2509 | @end | |
2367a917 | 2510 | /* }}} */ |
b4d89997 JF |
2511 | /* Changes View {{{ */ |
2512 | @interface ChangesView : ResetView < | |
2513 | PackageTableDelegate | |
8fe19fc1 | 2514 | > { |
b4d89997 | 2515 | UISectionList *list_; |
dc5812ec JF |
2516 | NSMutableArray *packages_; |
2517 | NSMutableArray *sections_; | |
b4d89997 JF |
2518 | PackageView *view_; |
2519 | NSString *package_; | |
2520 | size_t count_; | |
dc5812ec JF |
2521 | } |
2522 | ||
b4d89997 JF |
2523 | - (void) dealloc; |
2524 | ||
2525 | - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button; | |
2526 | ||
dc5812ec JF |
2527 | - (int) numberOfSectionsInSectionList:(UISectionList *)list; |
2528 | - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section; | |
2529 | - (int) sectionList:(UISectionList *)list rowForSection:(int)section; | |
2530 | ||
2531 | - (int) numberOfRowsInTable:(UITable *)table; | |
2532 | - (float) table:(UITable *)table heightForRow:(int)row; | |
1d80f6b9 | 2533 | - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing; |
dc5812ec | 2534 | - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row; |
b4d89997 | 2535 | - (void) tableRowSelected:(NSNotification *)notification; |
dc5812ec | 2536 | |
b4d89997 JF |
2537 | - (id) initWithFrame:(CGRect)frame; |
2538 | - (void) setPackages:(NSArray *)packages; | |
2539 | - (void) _resetView; | |
2540 | - (size_t) count; | |
dc5812ec | 2541 | |
dc5812ec | 2542 | - (void) setDelegate:(id)delegate; |
dc5812ec JF |
2543 | @end |
2544 | ||
b4d89997 JF |
2545 | @implementation ChangesView |
2546 | ||
2547 | - (void) dealloc { | |
2548 | [list_ release]; | |
2549 | [packages_ release]; | |
2550 | [sections_ release]; | |
2551 | if (view_ != nil) | |
2552 | [view_ release]; | |
2553 | if (package_ != nil) | |
2554 | [package_ release]; | |
2555 | [super dealloc]; | |
2556 | } | |
dc5812ec JF |
2557 | |
2558 | - (int) numberOfSectionsInSectionList:(UISectionList *)list { | |
2559 | return [sections_ count]; | |
2560 | } | |
2561 | ||
2562 | - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section { | |
2563 | return [[sections_ objectAtIndex:section] name]; | |
2564 | } | |
2565 | ||
2566 | - (int) sectionList:(UISectionList *)list rowForSection:(int)section { | |
2567 | return [[sections_ objectAtIndex:section] row]; | |
2568 | } | |
2569 | ||
2570 | - (int) numberOfRowsInTable:(UITable *)table { | |
2571 | return [packages_ count]; | |
2572 | } | |
2573 | ||
2574 | - (float) table:(UITable *)table heightForRow:(int)row { | |
2575 | return 64; | |
2576 | } | |
2577 | ||
1d80f6b9 JF |
2578 | - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing { |
2579 | if (reusing == nil) | |
b4d89997 | 2580 | reusing = [[[PackageCell alloc] initWithVersioner:NULL] autorelease]; |
1d80f6b9 JF |
2581 | [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]]; |
2582 | return reusing; | |
dc5812ec JF |
2583 | } |
2584 | ||
2585 | - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row { | |
b4d89997 | 2586 | return NO; |
dc5812ec JF |
2587 | } |
2588 | ||
b4d89997 JF |
2589 | - (void) tableRowSelected:(NSNotification *)notification { |
2590 | int row = [[notification object] selectedRow]; | |
2591 | [self packageTable:self packageSelected:(row == INT_MAX ? nil : [packages_ objectAtIndex:row])]; | |
dc5812ec JF |
2592 | } |
2593 | ||
2594 | - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button { | |
912a99dd JF |
2595 | switch (button) { |
2596 | case 0: | |
2597 | [[view_ package] install]; | |
2598 | [delegate_ resolve]; | |
2599 | [delegate_ perform]; | |
2600 | break; | |
2601 | ||
2602 | case 1: | |
2603 | [delegate_ upgrade]; | |
2604 | break; | |
2605 | } | |
dc5812ec JF |
2606 | } |
2607 | ||
b4d89997 JF |
2608 | - (void) packageTable:(id)table packageSelected:(Package *)package { |
2609 | if (package == nil) { | |
2610 | [package_ release]; | |
2611 | package_ = nil; | |
dc5812ec | 2612 | |
b4d89997 JF |
2613 | [view_ release]; |
2614 | view_ = nil; | |
2615 | } else { | |
2616 | _assert(package_ == nil); | |
2617 | _assert(view_ == nil); | |
dc5812ec | 2618 | |
b4d89997 | 2619 | package_ = [[package name] retain]; |
dc5812ec | 2620 | |
b4d89997 JF |
2621 | view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]]; |
2622 | [view_ setDelegate:delegate_]; | |
dc5812ec | 2623 | |
b4d89997 | 2624 | [view_ setPackage:package]; |
dc5812ec | 2625 | |
b4d89997 JF |
2626 | [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:( |
2627 | [package upgradable] ? @"Upgrade" : @"Install" | |
dc5812ec | 2628 | )]; |
b4d89997 JF |
2629 | } |
2630 | } | |
dc5812ec | 2631 | |
b4d89997 JF |
2632 | - (id) initWithFrame:(CGRect)frame { |
2633 | if ((self = [super initWithFrame:frame]) != nil) { | |
2634 | packages_ = [[NSMutableArray arrayWithCapacity:16] retain]; | |
2635 | sections_ = [[NSMutableArray arrayWithCapacity:16] retain]; | |
dc5812ec JF |
2636 | |
2637 | list_ = [[UISectionList alloc] initWithFrame:[transition_ bounds] showSectionIndex:NO]; | |
3178d79b | 2638 | [list_ setShouldHideHeaderInShortLists:NO]; |
b4d89997 JF |
2639 | [list_ setDataSource:self]; |
2640 | //[list_ setSectionListStyle:1]; | |
dc5812ec | 2641 | |
b4d89997 | 2642 | UITableColumn *column = [[[UITableColumn alloc] |
dc5812ec JF |
2643 | initWithTitle:@"Name" |
2644 | identifier:@"name" | |
2645 | width:frame.size.width | |
b4d89997 | 2646 | ] autorelease]; |
dc5812ec JF |
2647 | |
2648 | UITable *table = [list_ table]; | |
2649 | [table setSeparatorStyle:1]; | |
2650 | [table addTableColumn:column]; | |
2651 | [table setDelegate:self]; | |
1d80f6b9 | 2652 | [table setReusesTableCells:YES]; |
dc5812ec | 2653 | |
b4d89997 | 2654 | [self pushView:list_ withTitle:@"Changes" backButtonTitle:nil rightButton:nil]; |
dc5812ec JF |
2655 | } return self; |
2656 | } | |
2657 | ||
b4d89997 JF |
2658 | - (void) setPackages:(NSArray *)packages { |
2659 | [packages_ removeAllObjects]; | |
2660 | for (size_t i(0); i != [packages count]; ++i) { | |
2661 | Package *package([packages objectAtIndex:i]); | |
2662 | if ([package installed] == nil || [package upgradable]) | |
2663 | [packages_ addObject:package]; | |
2664 | } | |
2367a917 | 2665 | |
b4d89997 | 2666 | [packages_ sortUsingSelector:@selector(compareForChanges:)]; |
dc5812ec | 2667 | |
b4d89997 | 2668 | [sections_ removeAllObjects]; |
dc5812ec | 2669 | |
b4d89997 | 2670 | Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades" row:0] autorelease]; |
dc5812ec | 2671 | Section *section = nil; |
b4d89997 JF |
2672 | |
2673 | count_ = 0; | |
2674 | Package *npackage = nil; | |
dc5812ec JF |
2675 | for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) { |
2676 | Package *package = [packages_ objectAtIndex:offset]; | |
b4d89997 JF |
2677 | if ([[package name] isEqualToString:package_]) |
2678 | npackage = package; | |
dc5812ec | 2679 | |
b4d89997 JF |
2680 | if ([package upgradable]) |
2681 | [upgradable addPackage:package]; | |
2682 | else { | |
2683 | NSDate *seen = [package seen]; | |
dc5812ec | 2684 | |
b4d89997 JF |
2685 | CFLocaleRef locale = CFLocaleCopyCurrent(); |
2686 | CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle); | |
2687 | CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen); | |
2688 | ||
2689 | NSString *name = (NSString *) formatted; | |
2690 | ||
2691 | if (section == nil || ![[section name] isEqual:name]) { | |
2692 | section = [[[Section alloc] initWithName:name row:offset] autorelease]; | |
2693 | [sections_ addObject:section]; | |
2694 | } | |
2695 | ||
2696 | [section addPackage:package]; | |
2697 | ||
2698 | CFRelease(formatter); | |
2699 | CFRelease(formatted); | |
2700 | CFRelease(locale); | |
2701 | } | |
dc5812ec JF |
2702 | } |
2703 | ||
b4d89997 JF |
2704 | count_ = [[upgradable packages] count]; |
2705 | if (count_ != 0) | |
2706 | [sections_ insertObject:upgradable atIndex:0]; | |
2707 | ||
dc5812ec | 2708 | [list_ reloadData]; |
dc5812ec | 2709 | |
b4d89997 JF |
2710 | if (npackage != nil) |
2711 | [view_ setPackage:npackage]; | |
2712 | else if (package_ != nil) | |
2713 | [self popViews:1]; | |
2714 | if ([views_ count] == 1) | |
2715 | [self _resetView]; | |
c25a610d | 2716 | |
b4d89997 | 2717 | [self setPrompt]; |
3178d79b JF |
2718 | } |
2719 | ||
b4d89997 JF |
2720 | - (void) _resetView { |
2721 | [navbar_ showButtonsWithLeftTitle:(count_ == 0 ? nil : @"Upgrade All") rightTitle:nil]; | |
3178d79b JF |
2722 | } |
2723 | ||
b4d89997 JF |
2724 | - (size_t) count { |
2725 | return count_; | |
3178d79b JF |
2726 | } |
2727 | ||
b4d89997 JF |
2728 | - (void) setDelegate:(id)delegate { |
2729 | if (view_ != nil) | |
2730 | [view_ setDelegate:delegate]; | |
2731 | [super setDelegate:delegate]; | |
8fe19fc1 JF |
2732 | } |
2733 | ||
3178d79b JF |
2734 | @end |
2735 | /* }}} */ | |
b4d89997 JF |
2736 | /* Manage View {{{ */ |
2737 | @interface ManageView : ResetView < | |
2738 | PackageTableDelegate | |
2739 | > { | |
2740 | PackageTable *table_; | |
2741 | PackageView *view_; | |
2742 | NSString *package_; | |
3178d79b JF |
2743 | } |
2744 | ||
b4d89997 JF |
2745 | - (void) dealloc; |
2746 | ||
2747 | - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button; | |
2748 | ||
2749 | - (void) packageTable:(id)table packageSelected:(Package *)package; | |
2750 | ||
2751 | - (id) initWithFrame:(CGRect)frame; | |
2752 | - (void) setPackages:(NSArray *)packages; | |
2753 | ||
2754 | - (void) setDelegate:(id)delegate; | |
3178d79b JF |
2755 | @end |
2756 | ||
b4d89997 | 2757 | @implementation ManageView |
3178d79b | 2758 | |
b4d89997 JF |
2759 | - (void) dealloc { |
2760 | [table_ release]; | |
2761 | if (view_ != nil) | |
2762 | [view_ release]; | |
2763 | if (package_ != nil) | |
2764 | [package_ release]; | |
2765 | [super dealloc]; | |
3178d79b JF |
2766 | } |
2767 | ||
b4d89997 JF |
2768 | - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button { |
2769 | if (button == 0) { | |
2770 | [[view_ package] remove]; | |
2771 | [delegate_ resolve]; | |
2772 | [delegate_ perform]; | |
2773 | } | |
2774 | } | |
2775 | ||
2776 | - (void) packageTable:(id)table packageSelected:(Package *)package { | |
2777 | if (package == nil) { | |
2778 | [package_ release]; | |
2779 | package_ = nil; | |
2780 | ||
2781 | [view_ release]; | |
2782 | view_ = nil; | |
2783 | } else { | |
2784 | _assert(package_ == nil); | |
2785 | _assert(view_ == nil); | |
2786 | ||
2787 | package_ = [[package name] retain]; | |
2788 | ||
2789 | view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]]; | |
2790 | [view_ setDelegate:delegate_]; | |
2791 | ||
2792 | [view_ setPackage:package]; | |
2793 | ||
2794 | [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:@"Uninstall"]; | |
2795 | } | |
2796 | } | |
2797 | ||
2798 | - (id) initWithFrame:(CGRect)frame { | |
2799 | if ((self = [super initWithFrame:frame]) != nil) { | |
2800 | table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)]; | |
2801 | [table_ setDelegate:self]; | |
2802 | ||
2803 | [self pushView:table_ withTitle:@"Uninstall" backButtonTitle:@"Packages" rightButton:nil]; | |
2804 | } return self; | |
3178d79b JF |
2805 | } |
2806 | ||
b4d89997 JF |
2807 | - (void) setPackages:(NSArray *)packages { |
2808 | NSMutableArray *local = [NSMutableArray arrayWithCapacity:16]; | |
2809 | for (size_t i(0); i != [packages count]; ++i) { | |
2810 | Package *package([packages objectAtIndex:i]); | |
2811 | if ([package installed] != nil) | |
2812 | [local addObject:package]; | |
2813 | } | |
2814 | ||
2815 | [local sortUsingSelector:@selector(compareByName:)]; | |
2816 | ||
2817 | Package *npackage = nil; | |
2818 | for (size_t offset = 0, count = [local count]; offset != count; ++offset) { | |
2819 | Package *package = [local objectAtIndex:offset]; | |
2820 | if ([[package name] isEqualToString:package_]) | |
2821 | npackage = package; | |
2822 | } | |
2823 | ||
2824 | [table_ setPackages:local]; | |
2825 | ||
2826 | if (npackage != nil) | |
2827 | [view_ setPackage:npackage]; | |
2828 | else if (package_ != nil) | |
2829 | [self popViews:1]; | |
2830 | ||
2831 | [self setPrompt]; | |
3178d79b JF |
2832 | } |
2833 | ||
b4d89997 JF |
2834 | - (void) setDelegate:(id)delegate { |
2835 | if (view_ != nil) | |
2836 | [view_ setDelegate:delegate]; | |
2837 | [super setDelegate:delegate]; | |
8fe19fc1 JF |
2838 | } |
2839 | ||
3178d79b JF |
2840 | @end |
2841 | /* }}} */ | |
b4d89997 JF |
2842 | /* Search View {{{ */ |
2843 | @protocol SearchViewDelegate | |
2844 | - (void) showKeyboard:(BOOL)show; | |
2845 | @end | |
2846 | ||
2847 | @interface SearchView : ResetView < | |
2848 | PackageTableDelegate | |
2849 | > { | |
2850 | NSMutableArray *packages_; | |
2851 | UIView *accessory_; | |
2852 | UISearchField *field_; | |
2853 | PackageTable *table_; | |
2854 | PackageView *view_; | |
2855 | NSString *package_; | |
3178d79b JF |
2856 | } |
2857 | ||
b4d89997 JF |
2858 | - (void) dealloc; |
2859 | ||
74127566 | 2860 | - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button; |
b4d89997 JF |
2861 | - (void) packageTable:(id)table packageSelected:(Package *)package; |
2862 | ||
2863 | - (void) textFieldDidBecomeFirstResponder:(UITextField *)field; | |
2864 | - (void) textFieldDidResignFirstResponder:(UITextField *)field; | |
2865 | ||
2866 | - (void) keyboardInputChanged:(UIFieldEditor *)editor; | |
2867 | - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked; | |
2868 | ||
2869 | - (id) initWithFrame:(CGRect)frame; | |
2870 | - (void) setPackages:(NSArray *)packages; | |
2871 | ||
2872 | - (void) setDelegate:(id)delegate; | |
2873 | - (void) resetPackage:(Package *)package; | |
2874 | - (void) searchPackages; | |
74127566 | 2875 | |
3178d79b JF |
2876 | @end |
2877 | ||
b4d89997 JF |
2878 | @implementation SearchView |
2879 | ||
2880 | - (void) dealloc { | |
2881 | [packages_ release]; | |
2882 | [accessory_ release]; | |
2883 | [field_ release]; | |
2884 | [table_ release]; | |
2885 | if (view_ != nil) | |
2886 | [view_ release]; | |
2887 | if (package_ != nil) | |
2888 | [package_ release]; | |
2889 | [super dealloc]; | |
2890 | } | |
3178d79b | 2891 | |
74127566 | 2892 | - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button { |
b4d89997 JF |
2893 | if (button == 0) { |
2894 | Package *package = [view_ package]; | |
2895 | if ([package installed] == nil) | |
2896 | [package install]; | |
2897 | else | |
2898 | [package remove]; | |
2899 | [delegate_ resolve]; | |
74127566 JF |
2900 | [delegate_ perform]; |
2901 | } | |
2902 | } | |
2903 | ||
b4d89997 JF |
2904 | - (void) packageTable:(id)table packageSelected:(Package *)package { |
2905 | if (package == nil) { | |
2906 | [navbar_ setAccessoryView:accessory_ animate:(resetting_ ? NO : YES) goingBack:YES]; | |
2907 | ||
2908 | [package_ release]; | |
2909 | package_ = nil; | |
2910 | ||
2911 | [view_ release]; | |
2912 | view_ = nil; | |
2913 | } else { | |
2914 | [navbar_ setAccessoryView:nil animate:YES goingBack:NO]; | |
2915 | ||
2916 | _assert(package_ == nil); | |
2917 | _assert(view_ == nil); | |
2918 | ||
2919 | package_ = [[package name] retain]; | |
2920 | ||
2921 | view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]]; | |
2922 | [view_ setDelegate:delegate_]; | |
2923 | ||
2924 | [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:nil]; | |
2925 | [self resetPackage:package]; | |
2926 | } | |
3178d79b JF |
2927 | } |
2928 | ||
b4d89997 JF |
2929 | - (void) textFieldDidBecomeFirstResponder:(UITextField *)field { |
2930 | [delegate_ showKeyboard:YES]; | |
2931 | [table_ setEnabled:NO]; | |
2932 | ||
2933 | /*CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); | |
2934 | CGColor dimmed(alpha, 0, 0, 0, 0.5); | |
2935 | [editor_ setBackgroundColor:dimmed]; | |
2936 | CGColorSpaceRelease(space);*/ | |
3178d79b JF |
2937 | } |
2938 | ||
b4d89997 JF |
2939 | - (void) textFieldDidResignFirstResponder:(UITextField *)field { |
2940 | [table_ setEnabled:YES]; | |
2941 | [delegate_ showKeyboard:NO]; | |
3178d79b JF |
2942 | } |
2943 | ||
b4d89997 JF |
2944 | - (void) keyboardInputChanged:(UIFieldEditor *)editor { |
2945 | NSString *text([field_ text]); | |
2946 | [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)]; | |
3178d79b JF |
2947 | } |
2948 | ||
b4d89997 JF |
2949 | - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked { |
2950 | if ([text length] != 1 || [text characterAtIndex:0] != '\n') | |
2951 | return YES; | |
2952 | ||
2953 | [self searchPackages]; | |
2954 | [field_ resignFirstResponder]; | |
2955 | return NO; | |
8fe19fc1 JF |
2956 | } |
2957 | ||
b4d89997 JF |
2958 | - (id) initWithFrame:(CGRect)frame { |
2959 | if ((self = [super initWithFrame:frame]) != nil) { | |
2960 | packages_ = [[NSMutableArray arrayWithCapacity:16] retain]; | |
2961 | ||
2962 | table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)]; | |
2963 | [table_ setDelegate:self]; | |
2964 | ||
2965 | CGRect area = [self bounds]; | |
2966 | area.origin.y = 30; | |
2967 | area.origin.x = 0; | |
2968 | area.size.width -= 12; | |
2969 | area.size.height = [UISearchField defaultHeight]; | |
2970 | ||
2971 | field_ = [[UISearchField alloc] initWithFrame:area]; | |
2972 | ||
2973 | GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16); | |
2974 | [field_ setFont:font]; | |
2975 | CFRelease(font); | |
2976 | ||
2977 | [field_ setPlaceholder:@"Package Names & Descriptions"]; | |
2978 | [field_ setPaddingTop:5]; | |
2979 | [field_ setDelegate:self]; | |
2980 | ||
2981 | UITextTraits *traits = [field_ textTraits]; | |
2982 | [traits setEditingDelegate:self]; | |
2983 | [traits setReturnKeyType:6]; | |
2984 | ||
2985 | accessory_ = [[UIView alloc] initWithFrame:CGRectMake(6, 6, area.size.width, area.size.height + 30)]; | |
2986 | [accessory_ addSubview:field_]; | |
2987 | ||
2988 | [navbar_ setAccessoryView:accessory_]; | |
2989 | [self pushView:table_ withTitle:nil backButtonTitle:@"Search" rightButton:nil]; | |
2990 | ||
2991 | /* XXX: for the love of god just fix this */ | |
2992 | [navbar_ removeFromSuperview]; | |
2993 | [self addSubview:navbar_]; | |
2994 | } return self; | |
3178d79b JF |
2995 | } |
2996 | ||
b4d89997 JF |
2997 | - (void) setPackages:(NSArray *)packages { |
2998 | [packages_ removeAllObjects]; | |
2999 | [packages_ addObjectsFromArray:packages]; | |
3000 | [packages_ sortUsingSelector:@selector(compareByName:)]; | |
dc5812ec | 3001 | |
b4d89997 JF |
3002 | Package *npackage = nil; |
3003 | for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) { | |
3004 | Package *package = [packages_ objectAtIndex:offset]; | |
3005 | if ([[package name] isEqualToString:package_]) | |
3006 | npackage = package; | |
3007 | } | |
3008 | ||
3009 | [self searchPackages]; | |
3178d79b | 3010 | |
b4d89997 JF |
3011 | if (npackage != nil) |
3012 | [self resetPackage:npackage]; | |
3013 | else if (package_ != nil) | |
3014 | [self popViews:1]; | |
3015 | ||
3016 | [self setPrompt]; | |
dc5812ec JF |
3017 | } |
3018 | ||
b4d89997 JF |
3019 | - (void) setDelegate:(id)delegate { |
3020 | if (view_ != nil) | |
3021 | [view_ setDelegate:delegate]; | |
3022 | [super setDelegate:delegate]; | |
dc5812ec JF |
3023 | } |
3024 | ||
b4d89997 JF |
3025 | - (void) resetPackage:(Package *)package { |
3026 | [view_ setPackage:package]; | |
3027 | NSString *right = [package installed] == nil ? @"Install" : @"Uninstall"; | |
3028 | [navbar_ showButtonsWithLeftTitle:nil rightTitle:right]; | |
3178d79b JF |
3029 | } |
3030 | ||
b4d89997 JF |
3031 | - (void) searchPackages { |
3032 | NSString *text([field_ text]); | |
3033 | ||
3034 | NSMutableArray *packages([NSMutableArray arrayWithCapacity:16]); | |
3035 | ||
3036 | for (size_t offset(0), count([packages_ count]); offset != count; ++offset) { | |
3037 | Package *package = [packages_ objectAtIndex:offset]; | |
3038 | if ([package matches:text]) | |
3039 | [packages addObject:package]; | |
3040 | } | |
3041 | ||
3042 | [table_ setPackages:packages]; | |
3043 | [[table_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO]; | |
8fe19fc1 JF |
3044 | } |
3045 | ||
3178d79b JF |
3046 | @end |
3047 | /* }}} */ | |
3048 | ||
2367a917 | 3049 | @interface Cydia : UIApplication < |
3178d79b | 3050 | ConfirmationViewDelegate, |
b4d89997 JF |
3051 | ProgressViewDelegate, |
3052 | SearchViewDelegate | |
2367a917 | 3053 | > { |
dc5812ec | 3054 | UIWindow *window_; |
3178d79b JF |
3055 | UIView *underlay_; |
3056 | UIView *overlay_; | |
dc5812ec | 3057 | UITransitionView *transition_; |
2367a917 | 3058 | UIButtonBar *buttonbar_; |
3178d79b | 3059 | |
3178d79b | 3060 | ConfirmationView *confirm_; |
dc5812ec JF |
3061 | |
3062 | Database *database_; | |
3063 | ProgressView *progress_; | |
3064 | ||
3065 | UIView *featured_; | |
3066 | UINavigationBar *navbar_; | |
3067 | UIScroller *scroller_; | |
3068 | UIWebView *webview_; | |
3069 | NSURL *url_; | |
b19871dd | 3070 | UIProgressIndicator *indicator_; |
dc5812ec | 3071 | |
3178d79b | 3072 | InstallView *install_; |
b4d89997 JF |
3073 | ChangesView *changes_; |
3074 | ManageView *manage_; | |
3075 | SearchView *search_; | |
3076 | ||
3077 | bool restart_; | |
3078 | ||
3079 | UIKeyboard *keyboard_; | |
dc5812ec JF |
3080 | } |
3081 | ||
3082 | - (void) loadNews; | |
8fe19fc1 | 3083 | - (void) reloadData:(BOOL)reset; |
b4d89997 JF |
3084 | - (void) setPrompt; |
3085 | ||
3086 | - (void) resolve; | |
2367a917 | 3087 | - (void) perform; |
b4d89997 JF |
3088 | - (void) upgrade; |
3089 | - (void) update; | |
3090 | ||
3178d79b JF |
3091 | - (void) cancel; |
3092 | - (void) confirm; | |
2367a917 JF |
3093 | |
3094 | - (void) progressViewIsComplete:(ProgressView *)progress; | |
dc5812ec JF |
3095 | |
3096 | - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button; | |
2367a917 | 3097 | - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button; |
dc5812ec JF |
3098 | - (void) buttonBarItemTapped:(id)sender; |
3099 | ||
e8a3d6d7 | 3100 | - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old; |
dc5812ec | 3101 | |
b4d89997 | 3102 | - (void) applicationWillSuspend; |
dc5812ec JF |
3103 | - (void) applicationDidFinishLaunching:(id)unused; |
3104 | @end | |
3105 | ||
3106 | @implementation Cydia | |
3107 | ||
3108 | - (void) loadNews { | |
3178d79b | 3109 | NSMutableURLRequest *request = [NSMutableURLRequest |
dc5812ec JF |
3110 | requestWithURL:url_ |
3111 | cachePolicy:NSURLRequestReloadIgnoringCacheData | |
3112 | timeoutInterval:30.0 | |
3178d79b JF |
3113 | ]; |
3114 | ||
3115 | [request addValue:[NSString stringWithCString:Machine_] forHTTPHeaderField:@"X-Machine"]; | |
3116 | [request addValue:[NSString stringWithCString:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"]; | |
3117 | ||
3118 | [webview_ loadRequest:request]; | |
b19871dd | 3119 | [indicator_ startAnimation]; |
dc5812ec JF |
3120 | } |
3121 | ||
8fe19fc1 | 3122 | - (void) reloadData:(BOOL)reset { |
dc5812ec | 3123 | [database_ reloadData]; |
c25a610d | 3124 | |
b4d89997 JF |
3125 | size_t count = 16; |
3126 | ||
3127 | if (Packages_ == nil) { | |
3128 | Packages_ = [[NSMutableDictionary alloc] initWithCapacity:count]; | |
3129 | [Metadata_ setObject:Packages_ forKey:@"Packages"]; | |
3130 | } | |
3131 | ||
3132 | now_ = [NSDate date]; | |
3133 | ||
3134 | NSMutableArray *packages = [NSMutableArray arrayWithCapacity:count]; | |
3135 | for (pkgCache::PkgIterator iterator = [database_ cache]->PkgBegin(); !iterator.end(); ++iterator) | |
3136 | if (Package *package = [Package packageWithIterator:iterator database:database_]) | |
3137 | [packages addObject:package]; | |
3138 | ||
3139 | [install_ setPackages:packages]; | |
3140 | [changes_ setPackages:packages]; | |
3141 | [manage_ setPackages:packages]; | |
3142 | [search_ setPackages:packages]; | |
3143 | //[self setPrompt]; | |
3144 | ||
3145 | if (size_t count = [changes_ count]) { | |
c25a610d JF |
3146 | NSString *badge([[NSNumber numberWithInt:count] stringValue]); |
3147 | [buttonbar_ setBadgeValue:badge forButton:3]; | |
3148 | [buttonbar_ setBadgeAnimated:YES forButton:3]; | |
3149 | [self setApplicationBadge:badge]; | |
3150 | } else { | |
3151 | [buttonbar_ setBadgeValue:nil forButton:3]; | |
3152 | [buttonbar_ setBadgeAnimated:NO forButton:3]; | |
3153 | [self removeApplicationBadge]; | |
3154 | } | |
b4d89997 JF |
3155 | |
3156 | _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES); | |
3157 | } | |
3158 | ||
3159 | - (void) setPrompt { | |
23672b39 | 3160 | [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]]; |
b4d89997 JF |
3161 | } |
3162 | ||
3163 | - (void) resolve { | |
3164 | pkgProblemResolver *resolver = [database_ resolver]; | |
3165 | ||
3166 | resolver->InstallProtect(); | |
3167 | if (!resolver->Resolve(true)) | |
3168 | _error->Discard(); | |
2367a917 JF |
3169 | } |
3170 | ||
3171 | - (void) perform { | |
8fe19fc1 | 3172 | [database_ prepare]; |
3178d79b JF |
3173 | confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self]; |
3174 | } | |
3175 | ||
b4d89997 JF |
3176 | - (void) upgrade { |
3177 | [database_ upgrade]; | |
3178 | [self perform]; | |
3179 | } | |
3180 | ||
3178d79b | 3181 | - (void) cancel { |
8fe19fc1 | 3182 | [self reloadData:NO]; |
3178d79b JF |
3183 | [confirm_ release]; |
3184 | confirm_ = nil; | |
3185 | } | |
3186 | ||
3187 | - (void) confirm { | |
3188 | [overlay_ removeFromSuperview]; | |
b4d89997 | 3189 | restart_ = true; |
3178d79b | 3190 | |
2367a917 JF |
3191 | [progress_ |
3192 | detachNewThreadSelector:@selector(perform) | |
3193 | toTarget:database_ | |
3194 | withObject:nil | |
b4d89997 | 3195 | title:@"Running..." |
2367a917 JF |
3196 | ]; |
3197 | } | |
3198 | ||
b31b87cc JF |
3199 | - (void) bootstrap_ { |
3200 | [database_ update]; | |
3201 | [database_ upgrade]; | |
3202 | [database_ prepare]; | |
3203 | [database_ perform]; | |
3204 | } | |
3205 | ||
3206 | - (void) bootstrap { | |
3207 | [progress_ | |
3208 | detachNewThreadSelector:@selector(bootstrap_) | |
3209 | toTarget:self | |
3210 | withObject:nil | |
3211 | title:@"Bootstrap Install..." | |
3212 | ]; | |
3213 | } | |
3214 | ||
8da60fb7 JF |
3215 | - (void) update { |
3216 | [progress_ | |
3217 | detachNewThreadSelector:@selector(update) | |
3218 | toTarget:database_ | |
3219 | withObject:nil | |
b4d89997 | 3220 | title:@"Refreshing Sources..." |
8da60fb7 JF |
3221 | ]; |
3222 | } | |
3223 | ||
2367a917 | 3224 | - (void) progressViewIsComplete:(ProgressView *)progress { |
8fe19fc1 | 3225 | [self reloadData:YES]; |
3178d79b JF |
3226 | |
3227 | if (confirm_ != nil) { | |
3228 | [underlay_ addSubview:overlay_]; | |
3229 | [confirm_ removeFromSuperview]; | |
3230 | [confirm_ release]; | |
3231 | confirm_ = nil; | |
3232 | } | |
dc5812ec JF |
3233 | } |
3234 | ||
3235 | - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button { | |
3236 | switch (button) { | |
3237 | case 0: | |
3238 | [self loadNews]; | |
3239 | break; | |
3240 | ||
3241 | case 1: | |
1d80f6b9 | 3242 | UIAlertSheet *sheet = [[[UIAlertSheet alloc] |
2367a917 JF |
3243 | initWithTitle:@"About Cydia Packager" |
3244 | buttons:[NSArray arrayWithObjects:@"Close", nil] | |
3245 | defaultButtonIndex:0 | |
3246 | delegate:self | |
3247 | context:self | |
1d80f6b9 | 3248 | ] autorelease]; |
2367a917 | 3249 | |
1d80f6b9 | 3250 | [sheet setBodyText: |
b4d89997 | 3251 | @"Copyright (C) 2008\n" |
2367a917 JF |
3252 | "Jay Freeman (saurik)\n" |
3253 | "saurik@saurik.com\n" | |
3254 | "http://www.saurik.com/\n" | |
3255 | "\n" | |
3256 | "The Okori Group\n" | |
3257 | "http://www.theokorigroup.com/\n" | |
3258 | "\n" | |
3259 | "College of Creative Studies,\n" | |
3260 | "University of California,\n" | |
3261 | "Santa Barbara\n" | |
3262 | "http://www.ccs.ucsb.edu/\n" | |
3263 | "\n" | |
3264 | "Special Thanks:\n" | |
b4d89997 JF |
3265 | "bad_, BHSPitMonkey, cash, Cobra,\n" |
3266 | "core, Corona, crashx, cromas,\n" | |
3267 | "Darken, dtzWill, Erica, francis,\n" | |
3268 | "Godores, jerry, Kingstone, lounger,\n" | |
3269 | "mbranes, rockabilly, tman, Wbiggs" | |
2367a917 JF |
3270 | ]; |
3271 | ||
1d80f6b9 | 3272 | [sheet presentSheetFromButtonBar:buttonbar_]; |
dc5812ec JF |
3273 | break; |
3274 | } | |
3275 | } | |
3276 | ||
2367a917 | 3277 | - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button { |
1d80f6b9 | 3278 | [sheet dismiss]; |
2367a917 JF |
3279 | } |
3280 | ||
dc5812ec JF |
3281 | - (void) buttonBarItemTapped:(id)sender { |
3282 | UIView *view; | |
3283 | ||
3284 | switch ([sender tag]) { | |
3285 | case 1: view = featured_; break; | |
3286 | case 2: view = install_; break; | |
b4d89997 JF |
3287 | case 3: view = changes_; break; |
3288 | case 4: view = manage_; break; | |
3289 | case 5: view = search_; break; | |
dc5812ec JF |
3290 | |
3291 | default: | |
3292 | _assert(false); | |
3293 | } | |
3294 | ||
8da60fb7 JF |
3295 | if ([view respondsToSelector:@selector(resetView)]) |
3296 | [(id) view resetView]; | |
dc5812ec JF |
3297 | [transition_ transition:0 toView:view]; |
3298 | } | |
3299 | ||
e8a3d6d7 | 3300 | - (void) view:(UIView *)view didSetFrame:(CGRect)frame oldFrame:(CGRect)old { |
dc5812ec | 3301 | [scroller_ setContentSize:frame.size]; |
b19871dd | 3302 | [indicator_ stopAnimation]; |
dc5812ec JF |
3303 | } |
3304 | ||
b4d89997 JF |
3305 | - (void) applicationWillSuspend { |
3306 | if (restart_) | |
3307 | system("launchctl stop com.apple.SpringBoard"); | |
3308 | } | |
3309 | ||
dc5812ec JF |
3310 | - (void) applicationDidFinishLaunching:(id)unused { |
3311 | _assert(pkgInitConfig(*_config)); | |
3312 | _assert(pkgInitSystem(*_config, _system)); | |
3313 | ||
3178d79b | 3314 | confirm_ = nil; |
b4d89997 | 3315 | restart_ = false; |
3178d79b | 3316 | |
dc5812ec JF |
3317 | CGRect screenrect = [UIHardware fullScreenApplicationContentRect]; |
3318 | window_ = [[UIWindow alloc] initWithContentRect:screenrect]; | |
3319 | ||
3320 | [window_ orderFront: self]; | |
3321 | [window_ makeKey: self]; | |
3322 | [window_ _setHidden: NO]; | |
3323 | ||
2367a917 | 3324 | progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] delegate:self]; |
dc5812ec JF |
3325 | [window_ setContentView:progress_]; |
3326 | ||
3178d79b JF |
3327 | underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]]; |
3328 | [progress_ setContentView:underlay_]; | |
3329 | ||
3330 | overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]]; | |
b31b87cc JF |
3331 | |
3332 | if (!bootstrap_) | |
3333 | [underlay_ addSubview:overlay_]; | |
dc5812ec JF |
3334 | |
3335 | transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake( | |
3336 | 0, 0, screenrect.size.width, screenrect.size.height - 48 | |
3337 | )]; | |
3338 | ||
3178d79b | 3339 | [overlay_ addSubview:transition_]; |
dc5812ec JF |
3340 | |
3341 | featured_ = [[UIView alloc] initWithFrame:[transition_ bounds]]; | |
3342 | ||
b4d89997 | 3343 | CGSize navsize = [UINavigationBar defaultSizeWithPrompt]; |
dc5812ec JF |
3344 | CGRect navrect = {{0, 0}, navsize}; |
3345 | ||
3346 | navbar_ = [[UINavigationBar alloc] initWithFrame:navrect]; | |
3347 | [featured_ addSubview:navbar_]; | |
3348 | ||
3349 | [navbar_ setBarStyle:1]; | |
3350 | [navbar_ setDelegate:self]; | |
b4d89997 | 3351 | [navbar_ setPrompt:@"Welcome to Cydia Packager"]; |
dc5812ec JF |
3352 | |
3353 | [navbar_ showButtonsWithLeftTitle:@"About" rightTitle:@"Reload"]; | |
3354 | ||
b4d89997 | 3355 | UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Featured"] autorelease]; |
dc5812ec JF |
3356 | [navbar_ pushNavigationItem:navitem]; |
3357 | ||
3358 | struct CGRect subbounds = [featured_ bounds]; | |
3359 | subbounds.origin.y += navsize.height; | |
3360 | subbounds.size.height -= navsize.height; | |
3361 | ||
b4d89997 | 3362 | UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:subbounds] autorelease]; |
dc5812ec JF |
3363 | [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]]; |
3364 | [featured_ addSubview:pinstripe]; | |
3365 | ||
3366 | scroller_ = [[UIScroller alloc] initWithFrame:subbounds]; | |
3367 | [featured_ addSubview:scroller_]; | |
3368 | ||
3369 | [scroller_ setScrollingEnabled:YES]; | |
3370 | [scroller_ setAdjustForContentSizeChange:YES]; | |
3371 | [scroller_ setClipsSubviews:YES]; | |
3372 | [scroller_ setAllowsRubberBanding:YES]; | |
3373 | [scroller_ setScrollDecelerationFactor:0.99]; | |
3374 | [scroller_ setDelegate:self]; | |
3375 | ||
3376 | webview_ = [[UIWebView alloc] initWithFrame:[scroller_ bounds]]; | |
3377 | [scroller_ addSubview:webview_]; | |
3378 | ||
3379 | [webview_ setTilingEnabled:YES]; | |
3380 | [webview_ setTileSize:CGSizeMake(screenrect.size.width, 500)]; | |
3381 | [webview_ setAutoresizes:YES]; | |
3382 | [webview_ setDelegate:self]; | |
3383 | ||
b19871dd | 3384 | CGSize indsize = [UIProgressIndicator defaultSizeForStyle:2]; |
b4d89997 | 3385 | indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(87, 45, indsize.width, indsize.height)]; |
b19871dd JF |
3386 | [indicator_ setStyle:2]; |
3387 | [featured_ addSubview:indicator_]; | |
3388 | ||
dc5812ec JF |
3389 | NSArray *buttonitems = [NSArray arrayWithObjects: |
3390 | [NSDictionary dictionaryWithObjectsAndKeys: | |
3391 | @"buttonBarItemTapped:", kUIButtonBarButtonAction, | |
3392 | @"featured-up.png", kUIButtonBarButtonInfo, | |
3393 | @"featured-dn.png", kUIButtonBarButtonSelectedInfo, | |
3394 | [NSNumber numberWithInt:1], kUIButtonBarButtonTag, | |
3395 | self, kUIButtonBarButtonTarget, | |
3396 | @"Featured", kUIButtonBarButtonTitle, | |
3397 | @"0", kUIButtonBarButtonType, | |
3398 | nil], | |
3399 | ||
3400 | [NSDictionary dictionaryWithObjectsAndKeys: | |
3401 | @"buttonBarItemTapped:", kUIButtonBarButtonAction, | |
3402 | @"install-up.png", kUIButtonBarButtonInfo, | |
3403 | @"install-dn.png", kUIButtonBarButtonSelectedInfo, | |
3404 | [NSNumber numberWithInt:2], kUIButtonBarButtonTag, | |
3405 | self, kUIButtonBarButtonTarget, | |
3406 | @"Install", kUIButtonBarButtonTitle, | |
3407 | @"0", kUIButtonBarButtonType, | |
3408 | nil], | |
3409 | ||
3410 | [NSDictionary dictionaryWithObjectsAndKeys: | |
3411 | @"buttonBarItemTapped:", kUIButtonBarButtonAction, | |
b4d89997 JF |
3412 | @"changes-up.png", kUIButtonBarButtonInfo, |
3413 | @"changes-dn.png", kUIButtonBarButtonSelectedInfo, | |
dc5812ec JF |
3414 | [NSNumber numberWithInt:3], kUIButtonBarButtonTag, |
3415 | self, kUIButtonBarButtonTarget, | |
b4d89997 | 3416 | @"Changes", kUIButtonBarButtonTitle, |
dc5812ec JF |
3417 | @"0", kUIButtonBarButtonType, |
3418 | nil], | |
3419 | ||
3420 | [NSDictionary dictionaryWithObjectsAndKeys: | |
3421 | @"buttonBarItemTapped:", kUIButtonBarButtonAction, | |
b4d89997 JF |
3422 | @"manage-up.png", kUIButtonBarButtonInfo, |
3423 | @"manage-dn.png", kUIButtonBarButtonSelectedInfo, | |
dc5812ec JF |
3424 | [NSNumber numberWithInt:4], kUIButtonBarButtonTag, |
3425 | self, kUIButtonBarButtonTarget, | |
3426 | @"Uninstall", kUIButtonBarButtonTitle, | |
3427 | @"0", kUIButtonBarButtonType, | |
3428 | nil], | |
3429 | ||
3430 | [NSDictionary dictionaryWithObjectsAndKeys: | |
3431 | @"buttonBarItemTapped:", kUIButtonBarButtonAction, | |
b4d89997 JF |
3432 | @"search-up.png", kUIButtonBarButtonInfo, |
3433 | @"search-dn.png", kUIButtonBarButtonSelectedInfo, | |
dc5812ec JF |
3434 | [NSNumber numberWithInt:5], kUIButtonBarButtonTag, |
3435 | self, kUIButtonBarButtonTarget, | |
b4d89997 | 3436 | @"Search", kUIButtonBarButtonTitle, |
dc5812ec JF |
3437 | @"0", kUIButtonBarButtonType, |
3438 | nil], | |
3439 | nil]; | |
3440 | ||
2367a917 | 3441 | buttonbar_ = [[UIButtonBar alloc] |
3178d79b | 3442 | initInView:overlay_ |
dc5812ec JF |
3443 | withFrame:CGRectMake( |
3444 | 0, screenrect.size.height - 48, | |
3445 | screenrect.size.width, 48 | |
3446 | ) | |
3447 | withItemList:buttonitems | |
3448 | ]; | |
3449 | ||
2367a917 JF |
3450 | [buttonbar_ setDelegate:self]; |
3451 | [buttonbar_ setBarStyle:1]; | |
3452 | [buttonbar_ setButtonBarTrackingMode:2]; | |
dc5812ec JF |
3453 | |
3454 | int buttons[5] = {1, 2, 3, 4, 5}; | |
2367a917 JF |
3455 | [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5]; |
3456 | [buttonbar_ showButtonGroup:0 withDuration:0]; | |
dc5812ec JF |
3457 | |
3458 | for (int i = 0; i != 5; ++i) | |
2367a917 | 3459 | [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake( |
dc5812ec JF |
3460 | i * 64 + 2, 1, 60, 48 |
3461 | )]; | |
3462 | ||
2367a917 | 3463 | [buttonbar_ showSelectionForButton:1]; |
dc5812ec JF |
3464 | [transition_ transition:0 toView:featured_]; |
3465 | ||
3178d79b | 3466 | [overlay_ addSubview:buttonbar_]; |
dc5812ec | 3467 | |
b4d89997 JF |
3468 | [UIKeyboard initImplementationNow]; |
3469 | ||
b4d89997 JF |
3470 | CGRect edtrect = [overlay_ bounds]; |
3471 | edtrect.origin.y += navsize.height; | |
3472 | edtrect.size.height -= navsize.height; | |
3473 | ||
b4d89997 JF |
3474 | CGSize keysize = [UIKeyboard defaultSize]; |
3475 | CGRect keyrect = {{0, [overlay_ bounds].size.height - keysize.height}, keysize}; | |
3476 | keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect]; | |
3477 | ||
dc5812ec | 3478 | database_ = [[Database alloc] init]; |
2367a917 | 3479 | [database_ setDelegate:progress_]; |
dc5812ec | 3480 | |
b4d89997 | 3481 | install_ = [[InstallView alloc] initWithFrame:[transition_ bounds]]; |
dc5812ec JF |
3482 | [install_ setDelegate:self]; |
3483 | ||
b4d89997 JF |
3484 | changes_ = [[ChangesView alloc] initWithFrame:[transition_ bounds]]; |
3485 | [changes_ setDelegate:self]; | |
3178d79b | 3486 | |
b4d89997 JF |
3487 | manage_ = [[ManageView alloc] initWithFrame:[transition_ bounds]]; |
3488 | [manage_ setDelegate:self]; | |
dc5812ec | 3489 | |
b4d89997 JF |
3490 | search_ = [[SearchView alloc] initWithFrame:[transition_ bounds]]; |
3491 | [search_ setDelegate:self]; | |
8da60fb7 | 3492 | |
8fe19fc1 | 3493 | [self reloadData:NO]; |
3178d79b JF |
3494 | |
3495 | Package *package([database_ packageWithName:@"cydia"]); | |
3496 | NSString *application = package == nil ? @"Cydia" : [NSString stringWithFormat:@"Cydia/%@", [package installed]]; | |
3497 | WebView *webview = [webview_ webView]; | |
3498 | [webview setApplicationNameForUserAgent:application]; | |
3499 | ||
3500 | url_ = [NSURL URLWithString:@"http://cydia.saurik.com/"]; | |
3501 | [self loadNews]; | |
b31b87cc JF |
3502 | |
3503 | [progress_ resetView]; | |
3504 | ||
3505 | if (bootstrap_) | |
3506 | [self bootstrap]; | |
b4d89997 JF |
3507 | } |
3508 | ||
3509 | - (void) showKeyboard:(BOOL)show { | |
3510 | if (show) | |
3511 | [overlay_ addSubview:keyboard_]; | |
3512 | else | |
3513 | [keyboard_ removeFromSuperview]; | |
dc5812ec JF |
3514 | } |
3515 | ||
3516 | @end | |
3517 | ||
b4d89997 JF |
3518 | void AddPreferences(NSString *plist) { |
3519 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
3520 | ||
3521 | NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease]; | |
3522 | _assert(settings != NULL); | |
3523 | NSMutableArray *items = [settings objectForKey:@"items"]; | |
3524 | ||
3525 | bool cydia(false); | |
3526 | ||
3527 | for (size_t i(0); i != [items count]; ++i) { | |
3528 | NSMutableDictionary *item([items objectAtIndex:i]); | |
3529 | NSString *label = [item objectForKey:@"label"]; | |
3530 | if (label != nil && [label isEqualToString:@"Cydia"]) { | |
3531 | cydia = true; | |
3532 | break; | |
3533 | } | |
3534 | } | |
3535 | ||
3536 | if (!cydia) { | |
3537 | for (size_t i(0); i != [items count]; ++i) { | |
3538 | NSDictionary *item([items objectAtIndex:i]); | |
3539 | NSString *label = [item objectForKey:@"label"]; | |
3540 | if (label != nil && [label isEqualToString:@"General"]) { | |
3541 | [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys: | |
3542 | @"CydiaSettings", @"bundle", | |
3543 | @"PSLinkCell", @"cell", | |
3544 | [NSNumber numberWithBool:YES], @"hasIcon", | |
3545 | [NSNumber numberWithBool:YES], @"isController", | |
3546 | @"Cydia", @"label", | |
3547 | nil] atIndex:(i + 1)]; | |
3548 | ||
3549 | break; | |
3550 | } | |
3551 | } | |
3552 | ||
3553 | _assert([settings writeToFile:plist atomically:YES] == YES); | |
3554 | } | |
3555 | ||
3556 | [pool release]; | |
3557 | } | |
3558 | ||
3559 | /*IMP alloc_; | |
3560 | id Alloc_(id self, SEL selector) { | |
3561 | id object = alloc_(self, selector); | |
3562 | fprintf(stderr, "[%s]A-%p\n", self->isa->name, object); | |
3563 | return object; | |
3564 | }*/ | |
3565 | ||
dc5812ec | 3566 | int main(int argc, char *argv[]) { |
b4d89997 JF |
3567 | struct nlist nl[2]; |
3568 | memset(nl, 0, sizeof(nl)); | |
3569 | nl[0].n_un.n_name = "_useMDNSResponder"; | |
3570 | nlist("/usr/lib/libc.dylib", nl); | |
3571 | if (nl[0].n_type != N_UNDF) | |
3572 | *(int *) nl[0].n_value = 0; | |
3573 | ||
b31b87cc JF |
3574 | bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0; |
3575 | ||
b4d89997 JF |
3576 | setuid(0); |
3577 | setgid(0); | |
3578 | ||
3579 | /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc)); | |
3580 | alloc_ = alloc->method_imp; | |
3581 | alloc->method_imp = (IMP) &Alloc_;*/ | |
3582 | ||
dc5812ec | 3583 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
3178d79b JF |
3584 | |
3585 | size_t size; | |
3586 | sysctlbyname("hw.machine", NULL, &size, NULL, 0); | |
3587 | char *machine = new char[size]; | |
3588 | sysctlbyname("hw.machine", machine, &size, NULL, 0); | |
3589 | Machine_ = machine; | |
3590 | ||
3591 | if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice")) | |
3592 | if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) { | |
3593 | if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) { | |
3594 | SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding())); | |
3595 | CFRelease(serial); | |
3596 | } | |
3597 | ||
3598 | IOObjectRelease(service); | |
3599 | } | |
3600 | ||
b4d89997 JF |
3601 | AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist"); |
3602 | AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist"); | |
3603 | ||
3604 | if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL) | |
3605 | Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2]; | |
3606 | else | |
3607 | Packages_ = [Metadata_ objectForKey:@"Packages"]; | |
3608 | ||
dc5812ec JF |
3609 | UIApplicationMain(argc, argv, [Cydia class]); |
3610 | [pool release]; | |
b4d89997 | 3611 | return 0; |
dc5812ec | 3612 | } |