]> git.saurik.com Git - cydia.git/blame - Cydia.mm
Memory management this deterministic _should_ be automated.
[cydia.git] / Cydia.mm
CommitLineData
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
23extern "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 } \
41while (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 {{{ */
96class 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 {{{ */
140class 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
159class GSFont {
160 private:
161 GSFontRef font_;
162
163 public:
164 ~GSFont() {
165 /* XXX: no GSFontRelease()? */
166 CFRelease(font_);
167 }
168};
169/* }}} */
170
3178d79b
JF
171static const int PulseInterval_ = 50000;
172const char *Machine_ = NULL;
173const char *SerialNumber_ = NULL;
174
b31b87cc
JF
175bool bootstrap_ = false;
176
b4d89997
JF
177static NSMutableDictionary *Metadata_;
178static NSMutableDictionary *Packages_;
179static NSDate *now_;
8da60fb7 180
23672b39
JF
181NSString *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
204NSString *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
216static const float TextViewOffset_ = 22;
217
218UITextView *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 {{{ */
243class 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 {{{ */
303class 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 {{{ */
332extern NSString *kUIButtonBarButtonAction;
333extern NSString *kUIButtonBarButtonInfo;
334extern NSString *kUIButtonBarButtonInfoOffset;
335extern NSString *kUIButtonBarButtonSelectedInfo;
336extern NSString *kUIButtonBarButtonStyle;
337extern NSString *kUIButtonBarButtonTag;
338extern NSString *kUIButtonBarButtonTarget;
339extern NSString *kUIButtonBarButtonTitle;
340extern NSString *kUIButtonBarButtonTitleVerticalHeight;
341extern NSString *kUIButtonBarButtonTitleWidth;
342extern NSString *kUIButtonBarButtonType;
343/* }}} */
344/* Mime Addresses {{{ */
b4d89997
JF
345Pcre 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 {{{ */
443inline 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
615void 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
865NSString *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
3518void 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_;
3560id 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 3566int 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}