1 /* #include Directives {{{ */
2 #include <Foundation/NSURL.h>
3 #include <UIKit/UIKit.h>
4 #import <GraphicsServices/GraphicsServices.h>
7 #include <ext/stdio_filebuf.h>
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>
14 #include <apt-pkg/debmetaindex.h>
15 #include <apt-pkg/error.h>
16 #include <apt-pkg/init.h>
17 #include <apt-pkg/pkgrecords.h>
18 #include <apt-pkg/sourcelist.h>
19 #include <apt-pkg/sptr.h>
21 #include <sys/sysctl.h>
24 #include <mach-o/nlist.h>
27 #include <objc/objc-class.h>
33 /* Extension Keywords {{{ */
34 #define _trace() fprintf(stderr, "_trace()@%s:%u[%s]\n", __FILE__, __LINE__, __FUNCTION__)
36 #define _assert(test) do \
38 fprintf(stderr, "_assert(%d:%s)@%s:%u[%s]\n", errno, #test, __FILE__, __LINE__, __FUNCTION__); \
43 /* Miscellaneous Messages {{{ */
45 - (void) setApplicationNameForUserAgent:(NSString *)applicationName;
48 @interface NSString (Cydia)
49 - (NSString *) stringByAddingPercentEscapes;
50 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
54 /* Reset View (UIView) {{{ */
55 @interface UIView (CYResetView)
56 - (void) resetViewAnimated:(BOOL)animated;
59 @implementation UIView (CYResetView)
61 - (void) resetViewAnimated:(BOOL)animated {
62 fprintf(stderr, "%s\n", self->isa->name);
68 /* Reset View (UITable) {{{ */
69 @interface UITable (CYResetView)
70 - (void) resetViewAnimated:(BOOL)animated;
73 @implementation UITable (CYResetView)
75 - (void) resetViewAnimated:(BOOL)animated {
76 [self selectRow:-1 byExtendingSelection:NO withFade:animated];
81 /* Reset View (UISectionList) {{{ */
82 @interface UISectionList (CYResetView)
83 - (void) resetViewAnimated:(BOOL)animated;
86 @implementation UISectionList (CYResetView)
88 - (void) resetViewAnimated:(BOOL)animated {
89 [[self table] resetViewAnimated:animated];
95 /* Perl-Compatible RegEx {{{ */
105 Pcre(const char *regex) :
110 code_ = pcre_compile(regex, 0, &error, &offset, NULL);
113 fprintf(stderr, "%d:%s\n", offset, error);
117 pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_);
118 matches_ = new int[(capture_ + 1) * 3];
126 NSString *operator [](size_t match) {
128 stringWithCString:(data_ + matches_[match * 2])
129 length:(matches_[match * 2 + 1] - matches_[match * 2])
133 bool operator ()(const char *data, size_t size) {
135 return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0;
139 /* CoreGraphicsServices Primitives {{{ */
145 CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
146 float color[] = {red, green, blue, alpha};
147 color_ = CGColorCreate(space, color);
151 CGColorRelease(color_);
154 operator CGColorRef() {
165 /* XXX: no GSFontRelease()? */
171 static const int PulseInterval_ = 50000;
172 const char *Machine_ = NULL;
173 const char *SerialNumber_ = NULL;
175 bool bootstrap_ = false;
177 static NSMutableDictionary *Metadata_;
178 static NSMutableDictionary *Packages_;
181 NSString *GetLastUpdate() {
182 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
185 return @"Never or Unknown";
187 CFLocaleRef locale = CFLocaleCopyCurrent();
188 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
189 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
191 CFRelease(formatter);
194 return [(NSString *) formatted autorelease];
197 @protocol ProgressDelegate
198 - (void) setError:(NSString *)error;
199 - (void) setTitle:(NSString *)title;
200 - (void) setPercent:(float)percent;
201 - (void) addOutput:(NSString *)output;
204 NSString *SizeString(double size) {
206 while (size > 1024) {
211 static const char *powers_[] = {"B", "kB", "MB", "GB"};
213 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
216 static const float TextViewOffset_ = 22;
218 UITextView *GetTextView(NSString *value, float left, bool html) {
219 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
220 [text setEditable:NO];
221 [text setTextSize:16];
223 [text setHTML:value];
225 [text setText:value];
226 [text setEnabled:NO];
228 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
229 CGColor clear(space, 0, 0, 0, 0);
230 [text setBackgroundColor:clear];
231 CGColorSpaceRelease(space);
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];
242 /* Status Delegation {{{ */
244 public pkgAcquireStatus
255 void setDelegate(id delegate) {
256 delegate_ = delegate;
259 virtual bool MediaChange(std::string media, std::string drive) {
263 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
266 virtual void Fetch(pkgAcquire::ItemDesc &item) {
267 [delegate_ setTitle:[NSString stringWithCString:("Downloading " + item.ShortDesc).c_str()]];
270 virtual void Done(pkgAcquire::ItemDesc &item) {
273 virtual void Fail(pkgAcquire::ItemDesc &item) {
275 item.Owner->Status == pkgAcquire::Item::StatIdle ||
276 item.Owner->Status == pkgAcquire::Item::StatDone
280 [delegate_ setError:[NSString stringWithCString:item.Owner->ErrorText.c_str()]];
283 virtual bool Pulse(pkgAcquire *Owner) {
284 bool value = pkgAcquireStatus::Pulse(Owner);
287 double(CurrentBytes + CurrentItems) /
288 double(TotalBytes + TotalItems)
291 [delegate_ setPercent:percent];
295 virtual void Start() {
298 virtual void Stop() {
302 /* Progress Delegation {{{ */
310 virtual void Update() {
311 [delegate_ setTitle:[NSString stringWithCString:Op.c_str()]];
312 [delegate_ setPercent:(Percent / 100)];
321 void setDelegate(id delegate) {
322 delegate_ = delegate;
325 virtual void Done() {
326 [delegate_ setPercent:1];
331 /* External Constants {{{ */
332 extern NSString *kUIButtonBarButtonAction;
333 extern NSString *kUIButtonBarButtonInfo;
334 extern NSString *kUIButtonBarButtonInfoOffset;
335 extern NSString *kUIButtonBarButtonSelectedInfo;
336 extern NSString *kUIButtonBarButtonStyle;
337 extern NSString *kUIButtonBarButtonTag;
338 extern NSString *kUIButtonBarButtonTarget;
339 extern NSString *kUIButtonBarButtonTitle;
340 extern NSString *kUIButtonBarButtonTitleVerticalHeight;
341 extern NSString *kUIButtonBarButtonTitleWidth;
342 extern NSString *kUIButtonBarButtonType;
344 /* Mime Addresses {{{ */
345 Pcre email_r("^\"?(.*)\"? <([^>]*)>$");
347 @interface Address : NSObject {
355 - (NSString *) email;
357 + (Address *) addressWithString:(NSString *)string;
358 - (Address *) initWithString:(NSString *)string;
361 @implementation Address
370 - (NSString *) name {
374 - (NSString *) email {
378 + (Address *) addressWithString:(NSString *)string {
379 return [[[Address alloc] initWithString:string] autorelease];
382 - (Address *) initWithString:(NSString *)string {
383 if ((self = [super init]) != nil) {
384 const char *data = [string UTF8String];
385 size_t size = [string length];
387 if (email_r(data, size)) {
388 name_ = [email_r[1] retain];
389 email_ = [email_r[2] retain];
391 name_ = [[NSString stringWithCString:data length:size] retain];
400 /* Right Alignment {{{ */
401 @interface UIRightTextLabel : UITextLabel {
402 float _savedRightEdgeX;
403 BOOL _sizedtofit_flag;
406 - (void) setFrame:(CGRect)frame;
407 - (void) setText:(NSString *)text;
408 - (void) realignText;
411 @implementation UIRightTextLabel
413 - (void) setFrame:(CGRect)frame {
414 [super setFrame:frame];
415 if (_sizedtofit_flag == NO) {
416 _savedRightEdgeX = frame.origin.x;
421 - (void) setText:(NSString *)text {
422 [super setText:text];
426 - (void) realignText {
427 CGRect oldFrame = [self frame];
429 _sizedtofit_flag = YES;
430 [self sizeToFit]; // shrink down size so I can right align it
432 CGRect newFrame = [self frame];
434 oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width;
435 oldFrame.size.width = newFrame.size.width;
436 [super setFrame:oldFrame];
437 _sizedtofit_flag = NO;
442 /* Linear Algebra {{{ */
443 inline float interpolate(float begin, float end, float fraction) {
444 return (end - begin) * fraction + begin;
450 /* Database Interface {{{ */
451 @interface Database : NSObject {
453 pkgRecords *records_;
454 pkgProblemResolver *resolver_;
455 pkgAcquire *fetcher_;
457 SPtr<pkgPackageManager> manager_;
467 - (void) _readStatus:(NSNumber *)fd;
468 - (void) _readOutput:(NSNumber *)fd;
470 - (Package *) packageWithName:(NSString *)name;
473 - (pkgCacheFile &) cache;
474 - (pkgRecords *) records;
475 - (pkgProblemResolver *) resolver;
476 - (pkgAcquire &) fetcher;
484 - (void) setDelegate:(id)delegate;
489 @interface ResetView : UIView {
490 UIPushButton *reload_;
491 NSMutableArray *views_;
492 UINavigationBar *navbar_;
493 UITransitionView *transition_;
500 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item;
502 - (id) initWithFrame:(CGRect)frame;
503 - (void) setDelegate:(id)delegate;
504 - (void) reloadPushed;
506 - (void) pushView:(UIView *)view withTitle:(NSString *)title backButtonTitle:(NSString *)back rightButton:(NSString *)right;
507 - (void) popViews:(unsigned)views;
513 @implementation ResetView
517 [transition_ release];
523 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item {
524 [views_ removeLastObject];
525 UIView *view([views_ lastObject]);
526 [view resetViewAnimated:!resetting_];
528 [transition_ transition:2 toView:view];
530 if ([views_ count] == 1)
534 - (id) initWithFrame:(CGRect)frame {
535 if ((self = [super initWithFrame:frame]) != nil) {
536 views_ = [[NSMutableArray arrayWithCapacity:4] retain];
538 struct CGRect bounds = [self bounds];
539 CGSize navsize = [UINavigationBar defaultSizeWithPrompt];
540 CGRect navrect = {{0, 0}, navsize};
542 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
543 [self addSubview:navbar_];
545 [navbar_ setBarStyle:1];
546 [navbar_ setDelegate:self];
548 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
549 bounds.origin.x, bounds.origin.y + navsize.height, bounds.size.width, bounds.size.height - navsize.height
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];
558 [navbar_ addSubview:reload_];
560 [self addSubview:transition_];
564 - (void) setDelegate:(id)delegate {
565 delegate_ = delegate;
568 - (void) reloadPushed {
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];
577 [navbar_ showButtonsWithLeftTitle:nil rightTitle:right];
579 [transition_ transition:([views_ count] == 0 ? 0 : 1) toView:view];
580 [views_ addObject:view];
583 - (void) popViews:(unsigned)views {
585 for (unsigned i(0); i != views; ++i)
586 [navbar_ popNavigationItem];
589 [transition_ transition:2 toView:[views_ lastObject]];
594 if ([[navbar_ navigationItems] count] == 1)
597 [navbar_ popNavigationItem];
598 while ([[navbar_ navigationItems] count] != 1);
601 [transition_ transition:0 toView:[views_ lastObject]];
604 - (void) _resetView {
605 [navbar_ showButtonsWithLeftTitle:nil rightTitle:nil];
609 [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
614 /* Confirmation View {{{ */
615 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
616 if ([packages count] == 0)
619 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 110, false);
620 [fields setObject:text forKey:key];
622 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
623 CGColor blue(space, 0, 0, 0.4, 1);
624 [text setTextColor:blue];
625 CGColorSpaceRelease(space);
628 @protocol ConfirmationViewDelegate
633 @interface ConfirmationView : UIView {
636 UITransitionView *transition_;
638 UINavigationBar *navbar_;
639 UIPreferencesTable *table_;
640 NSMutableDictionary *fields_;
641 UIAlertSheet *essential_;
647 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
648 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
649 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
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;
657 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
661 @implementation ConfirmationView
664 [transition_ release];
669 if (essential_ != nil)
670 [essential_ release];
675 [transition_ transition:7 toView:nil];
679 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
680 if (from != nil && to == nil)
681 [self removeFromSuperview];
684 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
687 if (essential_ != nil)
688 [essential_ popupAlertAnimated:YES];
699 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
700 [essential_ dismiss];
704 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
708 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
710 case 0: return @"Statistics";
711 case 1: return @"Modifications";
713 default: _assert(false);
717 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
720 case 1: return [fields_ count];
722 default: _assert(false);
726 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
727 if (group != 1 || row == -1)
730 _assert(size_t(row) < [fields_ count]);
731 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
735 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
736 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
737 [cell setShowSelection:NO];
740 case 0: switch (row) {
742 [cell setTitle:@"Downloading"];
743 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
747 [cell setTitle:@"Resuming At"];
748 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
752 double size([database_ cache]->UsrSize());
755 [cell setTitle:@"Disk Freeing"];
756 [cell setValue:SizeString(-size)];
758 [cell setTitle:@"Disk Using"];
759 [cell setValue:SizeString(size)];
763 default: _assert(false);
767 _assert(size_t(row) < [fields_ count]);
768 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
769 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
772 default: _assert(false);
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;
783 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
784 [self addSubview:transition_];
786 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
788 CGSize navsize = [UINavigationBar defaultSize];
789 CGRect navrect = {{0, 0}, navsize};
790 CGRect bounds = [overlay_ bounds];
792 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
793 [navbar_ setBarStyle:1];
794 [navbar_ setDelegate:self];
796 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
797 [navbar_ pushNavigationItem:navitem];
798 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
800 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
802 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
803 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
804 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
806 bool essential(false);
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)
825 essential_ = [[UIAlertSheet alloc]
826 initWithTitle:@"Unable to Comply"
827 buttons:[NSArray arrayWithObjects:@"Okay", nil]
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."];
836 AddTextView(fields_, installing, @"Installing");
837 AddTextView(fields_, upgrading, @"Upgrading");
838 AddTextView(fields_, removing, @"Removing");
840 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
841 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
844 [table_ setReusesTableCells:YES];
845 [table_ setDataSource:self];
848 [overlay_ addSubview:navbar_];
849 [overlay_ addSubview:table_];
851 [view addSubview:self];
853 [transition_ setDelegate:self];
855 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
856 [transition_ transition:0 toView:blank];
857 [transition_ transition:3 toView:overlay_];
864 /* Package Class {{{ */
865 NSString *Scour(const char *field, const char *begin, const char *end) {
866 size_t i(0), l(strlen(field));
869 const char *name = begin + i;
870 const char *colon = name + l;
871 const char *value = colon + 1;
876 memcmp(name, field, l) == 0
878 while (value != end && value[0] == ' ')
880 const char *line = std::find(value, end, '\n');
881 while (line != value && line[-1] == ' ')
883 return [NSString stringWithCString:value length:(line - value)];
885 begin = std::find(begin, end, '\n');
893 @interface Package : NSObject {
894 pkgCache::PkgIterator iterator_;
896 pkgCache::VerIterator version_;
897 pkgCache::VerFileIterator file_;
900 NSString *installed_;
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;
915 - (NSString *) section;
916 - (Address *) maintainer;
918 - (NSString *) description;
919 - (NSString *) index;
923 - (NSString *) latest;
924 - (NSString *) installed;
929 - (NSString *) tagline;
931 - (NSString *) bundle;
932 - (NSString *) website;
934 - (BOOL) matches:(NSString *)text;
936 - (NSComparisonResult) compareByName:(Package *)package;
937 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
938 - (NSComparisonResult) compareForChanges:(Package *)package;
944 @implementation Package
948 if (installed_ != nil)
949 [installed_ release];
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;
970 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
972 const char *begin, *end;
973 parser->GetRec(begin, end);
975 latest_ = [[NSString stringWithCString:version_.VerStr()] retain];
976 installed_ = iterator_.CurrentVer().end() ? nil : [[NSString stringWithCString:iterator_.CurrentVer().VerStr()] retain];
978 id_ = [[[NSString stringWithCString:iterator_.Name()] lowercaseString] retain];
979 name_ = Scour("Name", begin, end);
981 name_ = [name_ retain];
982 tagline_ = [[NSString stringWithCString:parser->ShortDesc().c_str()] retain];
983 icon_ = Scour("Icon", begin, end);
985 icon_ = [icon_ retain];
986 bundle_ = Scour("Bundle", begin, end);
988 bundle_ = [bundle_ retain];
989 website_ = Scour("Website", begin, end);
991 website_ = [website_ retain];
993 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
994 if (metadata == nil) {
995 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
999 [Packages_ setObject:metadata forKey:id_];
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
1016 - (NSString *) section {
1017 return [[NSString stringWithCString:iterator_.Section()] stringByReplacingCharacter:'_' withCharacter:' '];
1020 - (Address *) maintainer {
1021 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1022 return [Address addressWithString:[NSString stringWithCString:parser->Maintainer().c_str()]];
1026 return version_->InstalledSize;
1029 - (NSString *) description {
1030 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1031 NSString *description([NSString stringWithCString:parser->LongDesc().c_str()]);
1033 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1034 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1035 if ([lines count] < 2)
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];
1044 return [trimmed componentsJoinedByString:@"\n"];
1047 - (NSString *) index {
1048 return [[[self name] substringToIndex:1] uppercaseString];
1052 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1055 - (NSString *) latest {
1059 - (NSString *) installed {
1063 - (BOOL) upgradable {
1064 NSString *installed = [self installed];
1065 return installed != nil && [[self latest] compare:installed] != NSOrderedSame ? YES : NO;
1072 - (NSString *) name {
1073 return name_ == nil ? id_ : name_;
1076 - (NSString *) tagline {
1080 - (NSString *) icon {
1084 - (NSString *) bundle {
1088 - (NSString *) website {
1092 - (BOOL) matches:(NSString *)text {
1098 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1099 if (range.location != NSNotFound)
1102 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1103 if (range.location != NSNotFound)
1109 - (NSComparisonResult) compareByName:(Package *)package {
1110 return [[self name] caseInsensitiveCompare:[package name]];
1113 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1114 NSComparisonResult result = [[self section] caseInsensitiveCompare:[package section]];
1115 if (result != NSOrderedSame)
1117 return [self compareByName:package];
1120 - (NSComparisonResult) compareForChanges:(Package *)package {
1121 BOOL lhs = [self upgradable];
1122 BOOL rhs = [package upgradable];
1125 return lhs ? NSOrderedAscending : NSOrderedDescending;
1127 switch ([[self seen] compare:[package seen]]) {
1128 case NSOrderedAscending:
1129 return NSOrderedDescending;
1132 case NSOrderedDescending:
1133 return NSOrderedAscending;
1139 return [self compareByName:package];
1143 pkgProblemResolver *resolver = [database_ resolver];
1144 resolver->Clear(iterator_);
1145 resolver->Protect(iterator_);
1146 [database_ cache]->MarkInstall(iterator_, false);
1150 pkgProblemResolver *resolver = [database_ resolver];
1151 resolver->Clear(iterator_);
1152 resolver->Protect(iterator_);
1153 resolver->Remove(iterator_);
1154 [database_ cache]->MarkDelete(iterator_, true);
1159 /* Section Class {{{ */
1160 @interface Section : NSObject {
1163 NSMutableArray *packages_;
1168 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1169 - (NSString *) name;
1171 - (NSArray *) packages;
1173 - (void) addPackage:(Package *)package;
1176 @implementation Section
1180 [packages_ release];
1184 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1185 if ((self = [super init]) != nil) {
1186 name_ = [name retain];
1188 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1192 - (NSString *) name {
1200 - (NSArray *) packages {
1205 return [packages_ count];
1208 - (void) addPackage:(Package *)package {
1209 [packages_ addObject:package];
1215 /* Package View {{{ */
1216 @protocol PackageViewDelegate
1217 - (void) performPackage:(Package *)package;
1220 @interface PackageView : UIView {
1221 UIPreferencesTable *table_;
1223 UITextView *description_;
1229 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
1230 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group;
1231 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed;
1232 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
1233 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
1235 - (BOOL) canSelectRow:(int)row;
1236 - (void) tableRowSelected:(NSNotification *)notification;
1238 - (Package *) package;
1240 - (id) initWithFrame:(struct CGRect)frame;
1241 - (void) setPackage:(Package *)package;
1242 - (void) setDelegate:(id)delegate;
1245 @implementation PackageView
1248 if (package_ != nil)
1250 if (description_ != nil)
1251 [description_ release];
1256 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
1260 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
1263 case 1: return @"Details";
1264 case 2: return @"Source";
1266 default: _assert(false);
1270 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
1271 if (group != 0 || row != 1)
1274 return [description_ visibleTextRect].size.height + TextViewOffset_;
1277 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
1283 default: _assert(false);
1287 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
1288 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
1289 [cell setShowSelection:NO];
1292 case 0: switch (row) {
1294 [cell setTitle:[package_ name]];
1295 [cell setValue:[package_ latest]];
1299 [cell addSubview:description_];
1302 default: _assert(false);
1305 case 1: switch (row) {
1307 [cell setTitle:@"Identifier"];
1308 [cell setValue:[package_ id]];
1312 [cell setTitle:@"Installed Version"];
1313 NSString *installed([package_ installed]);
1314 [cell setValue:(installed == nil ? @"n/a" : installed)];
1318 [cell setTitle:@"Section"];
1319 [cell setValue:[package_ section]];
1323 [cell setTitle:@"Expanded Size"];
1324 [cell setValue:SizeString([package_ size])];
1328 [cell setTitle:@"Maintainer"];
1329 [cell setValue:[[package_ maintainer] name]];
1330 [cell setShowDisclosure:YES];
1331 [cell setShowSelection:YES];
1334 default: _assert(false);
1337 case 2: switch (row) {
1340 default: _assert(false);
1346 - (BOOL) canSelectRow:(int)row {
1350 - (void) tableRowSelected:(NSNotification *)notification {
1351 printf("%d\n", [table_ selectedRow]);
1352 switch ([table_ selectedRow]) {
1354 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
1355 [[package_ maintainer] email],
1356 [[NSString stringWithFormat:@"regarding apt package \"%@\"", [package_ name]] stringByAddingPercentEscapes]
1362 - (Package *) package {
1366 - (id) initWithFrame:(struct CGRect)frame {
1367 if ((self = [super initWithFrame:frame]) != nil) {
1368 table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]];
1369 [self addSubview:table_];
1371 [table_ setDataSource:self];
1372 [table_ setDelegate:self];
1376 - (void) setPackage:(Package *)package {
1377 if (package_ != nil) {
1378 [package_ autorelease];
1382 if (description_ != nil) {
1383 [description_ release];
1387 if (package != nil) {
1388 package_ = [package retain];
1390 NSString *description([package description]);
1391 if (description == nil)
1392 description = [package tagline];
1393 description_ = [GetTextView(description, 12, true) retain];
1395 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1396 CGColor black(space, 0, 0, 0, 1);
1397 [description_ setTextColor:black];
1398 CGColorSpaceRelease(space);
1400 [table_ reloadData];
1404 - (void) setDelegate:(id)delegate {
1405 delegate_ = delegate;
1410 /* Package Cell {{{ */
1411 @interface PackageCell : UITableCell {
1413 UITextLabel *version_;
1414 UITextLabel *description_;
1420 - (PackageCell *) initWithVersioner:(SEL)versioner;
1421 - (void) setPackage:(Package *)package;
1423 - (void) _setSelected:(float)fraction;
1424 - (void) setSelected:(BOOL)selected;
1425 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
1426 - (void) _setSelectionFadeFraction:(float)fraction;
1430 @implementation PackageCell
1435 [description_ release];
1439 - (PackageCell *) initWithVersioner:(SEL)versioner {
1440 if ((self = [super init]) != nil) {
1441 versioner_ = versioner;
1443 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
1444 GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
1445 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
1447 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1449 CGColor clear(space, 0, 0, 0, 0);
1451 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 7, 250, 25)];
1452 [name_ setBackgroundColor:clear];
1453 [name_ setFont:bold];
1455 version_ = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(286, 7, 70, 25)];
1456 [version_ setBackgroundColor:clear];
1457 [version_ setFont:large];
1459 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(13, 35, 315, 20)];
1460 [description_ setBackgroundColor:clear];
1461 [description_ setFont:small];
1463 [self addSubview:name_];
1464 [self addSubview:version_];
1465 [self addSubview:description_];
1467 CGColorSpaceRelease(space);
1475 - (void) setPackage:(Package *)package {
1476 [name_ setText:[package name]];
1477 [version_ setText:[package latest]];
1478 [description_ setText:[package tagline]];
1481 - (void) _setSelected:(float)fraction {
1482 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1484 CGColor black(space,
1485 interpolate(0.0, 1.0, fraction),
1486 interpolate(0.0, 1.0, fraction),
1487 interpolate(0.0, 1.0, fraction),
1491 interpolate(0.2, 1.0, fraction),
1492 interpolate(0.2, 1.0, fraction),
1493 interpolate(1.0, 1.0, fraction),
1497 interpolate(0.4, 1.0, fraction),
1498 interpolate(0.4, 1.0, fraction),
1499 interpolate(0.4, 1.0, fraction),
1502 [name_ setColor:black];
1503 [version_ setColor:blue];
1504 [description_ setColor:gray];
1506 CGColorSpaceRelease(space);
1509 - (void) setSelected:(BOOL)selected {
1510 [self _setSelected:(selected ? 1.0 : 0.0)];
1511 [super setSelected:selected];
1514 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
1516 [self _setSelected:(selected ? 1.0 : 0.0)];
1517 [super setSelected:selected withFade:fade];
1520 - (void) _setSelectionFadeFraction:(float)fraction {
1521 [self _setSelected:fraction];
1522 [super _setSelectionFadeFraction:fraction];
1528 /* Database Implementation {{{ */
1529 @implementation Database
1536 - (void) _readStatus:(NSNumber *)fd {
1537 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1539 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1540 std::istream is(&ib);
1545 pcre *code = pcre_compile("^([^:]*):([^:]*):([^:]*):(.*)$", 0, &error, &offset, NULL);
1547 pcre_extra *study = NULL;
1549 pcre_fullinfo(code, study, PCRE_INFO_CAPTURECOUNT, &capture);
1550 int matches[(capture + 1) * 3];
1552 while (std::getline(is, line)) {
1553 const char *data(line.c_str());
1555 _assert(pcre_exec(code, study, data, line.size(), 0, 0, matches, sizeof(matches) / sizeof(matches[0])) >= 0);
1557 std::istringstream buffer(line.substr(matches[6], matches[7] - matches[6]));
1560 [delegate_ setPercent:(percent / 100)];
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]));
1565 if (type == "pmerror")
1566 [delegate_ setError:string];
1567 else if (type == "pmstatus")
1568 [delegate_ setTitle:string];
1569 else if (type == "pmconffile")
1571 else _assert(false);
1578 - (void) _readOutput:(NSNumber *)fd {
1579 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1581 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1582 std::istream is(&ib);
1585 while (std::getline(is, line))
1586 [delegate_ addOutput:[NSString stringWithCString:line.c_str()]];
1592 - (Package *) packageWithName:(NSString *)name {
1593 pkgCache::PkgIterator iterator(cache_->FindPkg([name cString]));
1594 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1597 - (Database *) init {
1598 if ((self = [super init]) != nil) {
1606 _assert(pipe(fds) != -1);
1610 detachNewThreadSelector:@selector(_readStatus:)
1612 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1615 _assert(pipe(fds) != -1);
1616 _assert(dup2(fds[1], 1) != -1);
1617 _assert(close(fds[1]) != -1);
1620 detachNewThreadSelector:@selector(_readOutput:)
1622 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1627 - (pkgCacheFile &) cache {
1631 - (pkgRecords *) records {
1635 - (pkgProblemResolver *) resolver {
1639 - (pkgAcquire &) fetcher {
1643 - (void) reloadData {
1651 _assert(cache_.Open(progress_, true));
1652 records_ = new pkgRecords(cache_);
1653 resolver_ = new pkgProblemResolver(cache_);
1654 fetcher_ = new pkgAcquire(&status_);
1659 pkgRecords records(cache_);
1661 lock_ = new FileFd();
1662 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1663 _assert(!_error->PendingError());
1666 _assert(list.ReadMainList());
1668 manager_ = (_system->CreatePM(cache_));
1669 _assert(manager_->GetArchives(fetcher_, &list, &records));
1670 _assert(!_error->PendingError());
1674 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue)
1678 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
1680 if (result == pkgPackageManager::Failed)
1682 if (_error->PendingError())
1684 if (result != pkgPackageManager::Completed)
1690 _assert(list.ReadMainList());
1693 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
1694 _assert(!_error->PendingError());
1696 pkgAcquire fetcher(&status_);
1697 _assert(list.GetIndexes(&fetcher));
1698 _assert(fetcher.Run(PulseInterval_) != pkgAcquire::Failed);
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();
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/"));
1712 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
1716 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1717 _assert(pkgApplyStatus(cache_));
1719 if (cache_->BrokenCount() != 0) {
1720 _assert(pkgFixBroken(cache_));
1721 _assert(cache_->BrokenCount() == 0);
1722 _assert(pkgMinimizeUpgrade(cache_));
1725 _assert(pkgDistUpgrade(cache_));
1728 - (void) setDelegate:(id)delegate {
1729 delegate_ = delegate;
1730 status_.setDelegate(delegate);
1731 progress_.setDelegate(delegate);
1737 /* Progress Data {{{ */
1738 @interface ProgressData : NSObject {
1744 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
1751 @implementation ProgressData
1753 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
1754 if ((self = [super init]) != nil) {
1755 selector_ = selector;
1775 /* Progress View {{{ */
1776 @interface ProgressView : UIView <
1780 UIView *background_;
1781 UITransitionView *transition_;
1783 UINavigationBar *navbar_;
1784 UIProgressBar *progress_;
1785 UITextView *output_;
1786 UITextLabel *status_;
1792 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
1794 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate;
1795 - (void) setContentView:(UIView *)view;
1798 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
1800 - (void) _retachThread;
1801 - (void) _detachNewThreadData:(ProgressData *)data;
1802 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
1804 - (void) setError:(NSString *)error;
1805 - (void) _setError:(NSString *)error;
1807 - (void) setTitle:(NSString *)title;
1808 - (void) _setTitle:(NSString *)title;
1810 - (void) setPercent:(float)percent;
1811 - (void) _setPercent:(NSNumber *)percent;
1813 - (void) addOutput:(NSString *)output;
1814 - (void) _addOutput:(NSString *)output;
1817 @protocol ProgressViewDelegate
1818 - (void) progressViewIsComplete:(ProgressView *)sender;
1821 @implementation ProgressView
1825 if (background_ != nil)
1826 [background_ release];
1827 [transition_ release];
1830 [progress_ release];
1836 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
1837 if (bootstrap_ && from == overlay_ && to == view_)
1841 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate {
1842 if ((self = [super initWithFrame:frame]) != nil) {
1843 delegate_ = delegate;
1845 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
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);
1851 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
1852 [transition_ setDelegate:self];
1854 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
1857 [overlay_ setBackgroundColor:black];
1859 background_ = [[UIView alloc] initWithFrame:[self bounds]];
1860 [background_ setBackgroundColor:black];
1861 [self addSubview:background_];
1864 [self addSubview:transition_];
1866 CGSize navsize = [UINavigationBar defaultSize];
1867 CGRect navrect = {{0, 0}, navsize};
1869 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
1870 [overlay_ addSubview:navbar_];
1872 [navbar_ setBarStyle:1];
1873 [navbar_ setDelegate:self];
1875 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
1876 [navbar_ pushNavigationItem:navitem];
1878 CGRect bounds = [overlay_ bounds];
1879 CGSize prgsize = [UIProgressBar defaultSize];
1882 (bounds.size.width - prgsize.width) / 2,
1883 bounds.size.height - prgsize.height - 20
1886 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
1887 [overlay_ addSubview:progress_];
1889 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
1891 bounds.size.height - prgsize.height - 50,
1892 bounds.size.width - 20,
1896 [status_ setColor:white];
1897 [status_ setBackgroundColor:clear];
1899 [status_ setCentersHorizontally:YES];
1900 //[status_ setFont:font];
1902 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
1904 navrect.size.height + 20,
1905 bounds.size.width - 20,
1906 bounds.size.height - navsize.height - 62 - navrect.size.height
1909 //[output_ setTextFont:@"Courier New"];
1910 [output_ setTextSize:12];
1912 [output_ setTextColor:white];
1913 [output_ setBackgroundColor:clear];
1915 [output_ setMarginTop:0];
1916 [output_ setAllowsRubberBanding:YES];
1918 [overlay_ addSubview:output_];
1919 [overlay_ addSubview:status_];
1921 [progress_ setStyle:0];
1923 CGColorSpaceRelease(space);
1927 - (void) setContentView:(UIView *)view {
1928 view_ = [view retain];
1931 - (void) resetView {
1932 [transition_ transition:6 toView:view_];
1935 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
1939 - (void) _retachThread {
1940 [delegate_ progressViewIsComplete:self];
1944 - (void) _detachNewThreadData:(ProgressData *)data {
1945 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1947 [[data target] performSelector:[data selector] withObject:[data object]];
1950 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
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];
1960 [status_ setText:nil];
1961 [output_ setText:@""];
1962 [progress_ setProgress:0];
1964 [transition_ transition:6 toView:overlay_];
1967 detachNewThreadSelector:@selector(_detachNewThreadData:)
1969 withObject:[[ProgressData alloc]
1970 initWithSelector:selector
1977 - (void) setError:(NSString *)error {
1979 performSelectorOnMainThread:@selector(_setError:)
1985 - (void) _setError:(NSString *)error {
1986 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
1987 initWithTitle:@"Package Error"
1988 buttons:[NSArray arrayWithObjects:@"Okay", nil]
1989 defaultButtonIndex:0
1994 [sheet setBodyText:error];
1995 [sheet popupAlertAnimated:YES];
1998 - (void) setTitle:(NSString *)title {
2000 performSelectorOnMainThread:@selector(_setTitle:)
2006 - (void) _setTitle:(NSString *)title {
2007 [status_ setText:[title stringByAppendingString:@"..."]];
2010 - (void) setPercent:(float)percent {
2012 performSelectorOnMainThread:@selector(_setPercent:)
2013 withObject:[NSNumber numberWithFloat:percent]
2018 - (void) _setPercent:(NSNumber *)percent {
2019 [progress_ setProgress:[percent floatValue]];
2022 - (void) addOutput:(NSString *)output {
2024 performSelectorOnMainThread:@selector(_addOutput:)
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];
2040 /* Package Table {{{ */
2041 @protocol PackageTableDelegate
2042 - (void) packageTable:(id)table packageSelected:(Package *)package;
2045 @interface PackageTable : UIView {
2047 UISectionList *list_;
2051 NSMutableArray *sections_;
2056 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
2057 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
2058 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
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;
2066 - (id) initWithFrame:(CGRect)frame versioner:(SEL)versioner;
2068 - (void) setDelegate:(id)delegate;
2069 - (void) setPackages:(NSArray *)packages;
2071 - (void) resetViewAnimated:(BOOL)animated;
2072 - (UITable *) table;
2075 @implementation PackageTable
2079 [sections_ release];
2080 if (packages_ != nil)
2081 [packages_ release];
2085 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2086 return [sections_ count];
2089 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2090 return [[sections_ objectAtIndex:section] name];
2093 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2094 return [[sections_ objectAtIndex:section] row];
2097 - (int) numberOfRowsInTable:(UITable *)table {
2098 return [packages_ count];
2101 - (float) table:(UITable *)table heightForRow:(int)row {
2105 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2107 reusing = [[[PackageCell alloc] initWithVersioner:versioner_] autorelease];
2108 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2112 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2116 - (void) tableRowSelected:(NSNotification *)notification {
2117 int row = [[notification object] selectedRow];
2118 [delegate_ packageTable:self packageSelected:(row == INT_MAX ? nil : [packages_ objectAtIndex:row])];
2121 - (id) initWithFrame:(CGRect)frame versioner:(SEL)versioner {
2122 if ((self = [super initWithFrame:frame]) != nil) {
2123 versioner_ = versioner;
2124 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
2126 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
2127 [list_ setDataSource:self];
2129 UITableColumn *column = [[[UITableColumn alloc]
2130 initWithTitle:@"Name"
2132 width:frame.size.width
2135 UITable *table = [list_ table];
2136 [table setSeparatorStyle:1];
2137 [table addTableColumn:column];
2138 [table setDelegate:self];
2139 [table setReusesTableCells:YES];
2141 [self addSubview:list_];
2145 - (void) setDelegate:(id)delegate {
2146 delegate_ = delegate;
2149 - (void) setPackages:(NSArray *)packages {
2150 if (packages_ != nil)
2151 [packages_ autorelease];
2152 _assert(packages != nil);
2153 packages_ = [packages retain];
2155 [sections_ removeAllObjects];
2157 Section *section = nil;
2159 for (size_t offset(0); offset != [packages_ count]; ++offset) {
2160 Package *package = [packages_ objectAtIndex:offset];
2161 NSString *name = [package index];
2163 if (section == nil || ![[section name] isEqual:name]) {
2164 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2165 [sections_ addObject:section];
2168 [section addPackage:package];
2174 - (void) resetViewAnimated:(BOOL)animated {
2175 [[list_ table] selectRow:-1 byExtendingSelection:NO withFade:animated];
2178 - (UITable *) table {
2179 return [list_ table];
2185 /* Section Cell {{{ */
2186 @interface SectionCell : UITableCell {
2188 UITextLabel *count_;
2194 - (void) setSection:(Section *)section;
2196 - (void) _setSelected:(float)fraction;
2197 - (void) setSelected:(BOOL)selected;
2198 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2199 - (void) _setSelectionFadeFraction:(float)fraction;
2203 @implementation SectionCell
2212 if ((self = [super init]) != nil) {
2213 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2214 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 12);
2216 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2217 CGColor clear(space, 0, 0, 0, 0);
2218 CGColor white(space, 1, 1, 1, 1);
2220 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(47, 9, 250, 25)];
2221 [name_ setBackgroundColor:clear];
2222 [name_ setFont:bold];
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];
2230 UIImageView *folder = [[[UIImageView alloc] initWithFrame:CGRectMake(8, 7, 32, 32)] autorelease];
2231 [folder setImage:[UIImage applicationImageNamed:@"folder.png"]];
2233 [self addSubview:folder];
2234 [self addSubview:name_];
2235 [self addSubview:count_];
2237 [self _setSelected:0];
2239 CGColorSpaceRelease(space);
2246 - (void) setSection:(Section *)section {
2247 if (section == nil) {
2248 [name_ setText:@"All Packages"];
2249 [count_ setText:nil];
2251 [name_ setText:[section name]];
2252 [count_ setText:[NSString stringWithFormat:@"%d", [section count]]];
2256 - (void) _setSelected:(float)fraction {
2257 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
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),
2265 [name_ setColor:black];
2267 CGColorSpaceRelease(space);
2270 - (void) setSelected:(BOOL)selected {
2271 [self _setSelected:(selected ? 1.0 : 0.0)];
2272 [super setSelected:selected];
2275 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2277 [self _setSelected:(selected ? 1.0 : 0.0)];
2278 [super setSelected:selected withFade:fade];
2281 - (void) _setSelectionFadeFraction:(float)fraction {
2282 [self _setSelected:fraction];
2283 [super _setSelectionFadeFraction:fraction];
2288 /* Install View {{{ */
2289 @interface InstallView : ResetView <
2290 PackageTableDelegate
2294 PackageTable *table_;
2298 NSMutableArray *packages_;
2303 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
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;
2311 - (void) packageTable:(id)table packageSelected:(Package *)package;
2313 - (id) initWithFrame:(CGRect)frame;
2314 - (void) setPackages:(NSArray *)packages;
2315 - (void) setDelegate:(id)delegate;
2318 @implementation InstallView
2321 [packages_ release];
2322 if (sections_ != nil)
2323 [sections_ release];
2330 if (section_ != nil)
2332 if (package_ != nil)
2337 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2339 [[view_ package] install];
2340 [delegate_ resolve];
2341 [delegate_ perform];
2345 - (int) numberOfRowsInTable:(UITable *)table {
2346 return [sections_ count] + 1;
2349 - (float) table:(UITable *)table heightForRow:(int)row {
2353 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2355 reusing = [[[SectionCell alloc] init] autorelease];
2357 [(SectionCell *)reusing setSection:nil];
2359 [(SectionCell *)reusing setSection:[sections_ objectAtIndex:(row - 1)]];
2363 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2367 - (void) tableRowSelected:(NSNotification *)notification {
2368 int row = [[notification object] selectedRow];
2370 if (row == INT_MAX) {
2377 _assert(section_ == nil);
2378 _assert(table_ == nil);
2386 name = @"All Packages";
2388 section = [sections_ objectAtIndex:(row - 1)];
2389 name = [section name];
2390 section_ = [name retain];
2393 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
2394 [table_ setDelegate:self];
2395 [table_ setPackages:(section == nil ? packages_ : [section packages])];
2397 [self pushView:table_ withTitle:name backButtonTitle:@"Packages" rightButton:nil];
2401 - (void) packageTable:(id)table packageSelected:(Package *)package {
2402 if (package == nil) {
2409 _assert(package_ == nil);
2410 _assert(view_ == nil);
2412 package_ = [[package name] retain];
2414 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2415 [view_ setDelegate:delegate_];
2417 [view_ setPackage:package];
2419 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:@"Install"];
2423 - (id) initWithFrame:(CGRect)frame {
2424 if ((self = [super initWithFrame:frame]) != nil) {
2425 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2427 list_ = [[UITable alloc] initWithFrame:[transition_ bounds]];
2428 [self pushView:list_ withTitle:@"Install" backButtonTitle:@"Sections" rightButton:nil];
2430 UITableColumn *column = [[[UITableColumn alloc]
2431 initWithTitle:@"Name"
2433 width:frame.size.width
2436 [list_ setDataSource:self];
2437 [list_ setSeparatorStyle:1];
2438 [list_ addTableColumn:column];
2439 [list_ setDelegate:self];
2440 [list_ setReusesTableCells:YES];
2442 [transition_ transition:0 toView:list_];
2446 - (void) setPackages:(NSArray *)packages {
2447 [packages_ removeAllObjects];
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];
2455 [packages_ sortUsingSelector:@selector(compareBySectionAndName:)];
2456 NSMutableArray *sections = [NSMutableArray arrayWithCapacity:16];
2458 Section *nsection = nil;
2459 Package *npackage = nil;
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];
2466 if (section == nil || ![[section name] isEqual:name]) {
2467 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2469 if ([name isEqualToString:section_])
2471 [sections addObject:section];
2474 if ([[package name] isEqualToString:package_])
2476 [section addPackage:package];
2479 if (sections_ != nil)
2480 [sections_ release];
2481 sections_ = [sections retain];
2483 [packages_ sortUsingSelector:@selector(compareByName:)];
2489 if (npackage != nil)
2490 [view_ setPackage:npackage];
2491 else if (package_ != nil)
2494 if (nsection != nil)
2495 [table_ setPackages:[nsection packages]];
2496 else if (section_ != nil)
2499 [self popViews:views];
2503 - (void) setDelegate:(id)delegate {
2505 [view_ setDelegate:delegate];
2506 [super setDelegate:delegate];
2511 /* Changes View {{{ */
2512 @interface ChangesView : ResetView <
2513 PackageTableDelegate
2515 UISectionList *list_;
2516 NSMutableArray *packages_;
2517 NSMutableArray *sections_;
2525 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2527 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
2528 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
2529 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
2531 - (int) numberOfRowsInTable:(UITable *)table;
2532 - (float) table:(UITable *)table heightForRow:(int)row;
2533 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2534 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2535 - (void) tableRowSelected:(NSNotification *)notification;
2537 - (id) initWithFrame:(CGRect)frame;
2538 - (void) setPackages:(NSArray *)packages;
2539 - (void) _resetView;
2542 - (void) setDelegate:(id)delegate;
2545 @implementation ChangesView
2549 [packages_ release];
2550 [sections_ release];
2553 if (package_ != nil)
2558 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2559 return [sections_ count];
2562 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2563 return [[sections_ objectAtIndex:section] name];
2566 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2567 return [[sections_ objectAtIndex:section] row];
2570 - (int) numberOfRowsInTable:(UITable *)table {
2571 return [packages_ count];
2574 - (float) table:(UITable *)table heightForRow:(int)row {
2578 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2580 reusing = [[[PackageCell alloc] initWithVersioner:NULL] autorelease];
2581 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2585 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2589 - (void) tableRowSelected:(NSNotification *)notification {
2590 int row = [[notification object] selectedRow];
2591 [self packageTable:self packageSelected:(row == INT_MAX ? nil : [packages_ objectAtIndex:row])];
2594 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2597 [[view_ package] install];
2598 [delegate_ resolve];
2599 [delegate_ perform];
2603 [delegate_ upgrade];
2608 - (void) packageTable:(id)table packageSelected:(Package *)package {
2609 if (package == nil) {
2616 _assert(package_ == nil);
2617 _assert(view_ == nil);
2619 package_ = [[package name] retain];
2621 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2622 [view_ setDelegate:delegate_];
2624 [view_ setPackage:package];
2626 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:(
2627 [package upgradable] ? @"Upgrade" : @"Install"
2632 - (id) initWithFrame:(CGRect)frame {
2633 if ((self = [super initWithFrame:frame]) != nil) {
2634 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2635 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
2637 list_ = [[UISectionList alloc] initWithFrame:[transition_ bounds] showSectionIndex:NO];
2638 [list_ setShouldHideHeaderInShortLists:NO];
2639 [list_ setDataSource:self];
2640 //[list_ setSectionListStyle:1];
2642 UITableColumn *column = [[[UITableColumn alloc]
2643 initWithTitle:@"Name"
2645 width:frame.size.width
2648 UITable *table = [list_ table];
2649 [table setSeparatorStyle:1];
2650 [table addTableColumn:column];
2651 [table setDelegate:self];
2652 [table setReusesTableCells:YES];
2654 [self pushView:list_ withTitle:@"Changes" backButtonTitle:nil rightButton:nil];
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];
2666 [packages_ sortUsingSelector:@selector(compareForChanges:)];
2668 [sections_ removeAllObjects];
2670 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades" row:0] autorelease];
2671 Section *section = nil;
2674 Package *npackage = nil;
2675 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
2676 Package *package = [packages_ objectAtIndex:offset];
2677 if ([[package name] isEqualToString:package_])
2680 if ([package upgradable])
2681 [upgradable addPackage:package];
2683 NSDate *seen = [package seen];
2685 CFLocaleRef locale = CFLocaleCopyCurrent();
2686 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
2687 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
2689 NSString *name = (NSString *) formatted;
2691 if (section == nil || ![[section name] isEqual:name]) {
2692 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2693 [sections_ addObject:section];
2696 [section addPackage:package];
2698 CFRelease(formatter);
2699 CFRelease(formatted);
2704 count_ = [[upgradable packages] count];
2706 [sections_ insertObject:upgradable atIndex:0];
2710 if (npackage != nil)
2711 [view_ setPackage:npackage];
2712 else if (package_ != nil)
2714 if ([views_ count] == 1)
2720 - (void) _resetView {
2721 [navbar_ showButtonsWithLeftTitle:(count_ == 0 ? nil : @"Upgrade All") rightTitle:nil];
2728 - (void) setDelegate:(id)delegate {
2730 [view_ setDelegate:delegate];
2731 [super setDelegate:delegate];
2736 /* Manage View {{{ */
2737 @interface ManageView : ResetView <
2738 PackageTableDelegate
2740 PackageTable *table_;
2747 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2749 - (void) packageTable:(id)table packageSelected:(Package *)package;
2751 - (id) initWithFrame:(CGRect)frame;
2752 - (void) setPackages:(NSArray *)packages;
2754 - (void) setDelegate:(id)delegate;
2757 @implementation ManageView
2763 if (package_ != nil)
2768 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2770 [[view_ package] remove];
2771 [delegate_ resolve];
2772 [delegate_ perform];
2776 - (void) packageTable:(id)table packageSelected:(Package *)package {
2777 if (package == nil) {
2784 _assert(package_ == nil);
2785 _assert(view_ == nil);
2787 package_ = [[package name] retain];
2789 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2790 [view_ setDelegate:delegate_];
2792 [view_ setPackage:package];
2794 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:@"Uninstall"];
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];
2803 [self pushView:table_ withTitle:@"Uninstall" backButtonTitle:@"Packages" rightButton:nil];
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];
2815 [local sortUsingSelector:@selector(compareByName:)];
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_])
2824 [table_ setPackages:local];
2826 if (npackage != nil)
2827 [view_ setPackage:npackage];
2828 else if (package_ != nil)
2834 - (void) setDelegate:(id)delegate {
2836 [view_ setDelegate:delegate];
2837 [super setDelegate:delegate];
2842 /* Search View {{{ */
2843 @protocol SearchViewDelegate
2844 - (void) showKeyboard:(BOOL)show;
2847 @interface SearchView : ResetView <
2848 PackageTableDelegate
2850 NSMutableArray *packages_;
2852 UISearchField *field_;
2853 PackageTable *table_;
2860 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2861 - (void) packageTable:(id)table packageSelected:(Package *)package;
2863 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field;
2864 - (void) textFieldDidResignFirstResponder:(UITextField *)field;
2866 - (void) keyboardInputChanged:(UIFieldEditor *)editor;
2867 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked;
2869 - (id) initWithFrame:(CGRect)frame;
2870 - (void) setPackages:(NSArray *)packages;
2872 - (void) setDelegate:(id)delegate;
2873 - (void) resetPackage:(Package *)package;
2874 - (void) searchPackages;
2878 @implementation SearchView
2881 [packages_ release];
2882 [accessory_ release];
2887 if (package_ != nil)
2892 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2894 Package *package = [view_ package];
2895 if ([package installed] == nil)
2899 [delegate_ resolve];
2900 [delegate_ perform];
2904 - (void) packageTable:(id)table packageSelected:(Package *)package {
2905 if (package == nil) {
2906 [navbar_ setAccessoryView:accessory_ animate:(resetting_ ? NO : YES) goingBack:YES];
2914 [navbar_ setAccessoryView:nil animate:YES goingBack:NO];
2916 _assert(package_ == nil);
2917 _assert(view_ == nil);
2919 package_ = [[package name] retain];
2921 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2922 [view_ setDelegate:delegate_];
2924 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:nil];
2925 [self resetPackage:package];
2929 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
2930 [delegate_ showKeyboard:YES];
2931 [table_ setEnabled:NO];
2933 /*CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2934 CGColor dimmed(alpha, 0, 0, 0, 0.5);
2935 [editor_ setBackgroundColor:dimmed];
2936 CGColorSpaceRelease(space);*/
2939 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
2940 [table_ setEnabled:YES];
2941 [delegate_ showKeyboard:NO];
2944 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
2945 NSString *text([field_ text]);
2946 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
2949 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
2950 if ([text length] != 1 || [text characterAtIndex:0] != '\n')
2953 [self searchPackages];
2954 [field_ resignFirstResponder];
2958 - (id) initWithFrame:(CGRect)frame {
2959 if ((self = [super initWithFrame:frame]) != nil) {
2960 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2962 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
2963 [table_ setDelegate:self];
2965 CGRect area = [self bounds];
2968 area.size.width -= 12;
2969 area.size.height = [UISearchField defaultHeight];
2971 field_ = [[UISearchField alloc] initWithFrame:area];
2973 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
2974 [field_ setFont:font];
2977 [field_ setPlaceholder:@"Package Names & Descriptions"];
2978 [field_ setPaddingTop:5];
2979 [field_ setDelegate:self];
2981 UITextTraits *traits = [field_ textTraits];
2982 [traits setEditingDelegate:self];
2983 [traits setReturnKeyType:6];
2985 accessory_ = [[UIView alloc] initWithFrame:CGRectMake(6, 6, area.size.width, area.size.height + 30)];
2986 [accessory_ addSubview:field_];
2988 [navbar_ setAccessoryView:accessory_];
2989 [self pushView:table_ withTitle:nil backButtonTitle:@"Search" rightButton:nil];
2991 /* XXX: for the love of god just fix this */
2992 [navbar_ removeFromSuperview];
2993 [self addSubview:navbar_];
2997 - (void) setPackages:(NSArray *)packages {
2998 [packages_ removeAllObjects];
2999 [packages_ addObjectsFromArray:packages];
3000 [packages_ sortUsingSelector:@selector(compareByName:)];
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_])
3009 [self searchPackages];
3011 if (npackage != nil)
3012 [self resetPackage:npackage];
3013 else if (package_ != nil)
3019 - (void) setDelegate:(id)delegate {
3021 [view_ setDelegate:delegate];
3022 [super setDelegate:delegate];
3025 - (void) resetPackage:(Package *)package {
3026 [view_ setPackage:package];
3027 NSString *right = [package installed] == nil ? @"Install" : @"Uninstall";
3028 [navbar_ showButtonsWithLeftTitle:nil rightTitle:right];
3031 - (void) searchPackages {
3032 NSString *text([field_ text]);
3034 NSMutableArray *packages([NSMutableArray arrayWithCapacity:16]);
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];
3042 [table_ setPackages:packages];
3043 [[table_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3049 @interface Cydia : UIApplication <
3050 ConfirmationViewDelegate,
3051 ProgressViewDelegate,
3057 UITransitionView *transition_;
3058 UIButtonBar *buttonbar_;
3060 ConfirmationView *confirm_;
3062 Database *database_;
3063 ProgressView *progress_;
3066 UINavigationBar *navbar_;
3067 UIScroller *scroller_;
3068 UIWebView *webview_;
3070 UIProgressIndicator *indicator_;
3072 InstallView *install_;
3073 ChangesView *changes_;
3074 ManageView *manage_;
3075 SearchView *search_;
3079 UIKeyboard *keyboard_;
3083 - (void) reloadData:(BOOL)reset;
3094 - (void) progressViewIsComplete:(ProgressView *)progress;
3096 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
3097 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
3098 - (void) buttonBarItemTapped:(id)sender;
3100 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old;
3102 - (void) applicationWillSuspend;
3103 - (void) applicationDidFinishLaunching:(id)unused;
3106 @implementation Cydia
3109 NSMutableURLRequest *request = [NSMutableURLRequest
3111 cachePolicy:NSURLRequestReloadIgnoringCacheData
3112 timeoutInterval:30.0
3115 [request addValue:[NSString stringWithCString:Machine_] forHTTPHeaderField:@"X-Machine"];
3116 [request addValue:[NSString stringWithCString:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
3118 [webview_ loadRequest:request];
3119 [indicator_ startAnimation];
3122 - (void) reloadData:(BOOL)reset {
3123 [database_ reloadData];
3127 if (Packages_ == nil) {
3128 Packages_ = [[NSMutableDictionary alloc] initWithCapacity:count];
3129 [Metadata_ setObject:Packages_ forKey:@"Packages"];
3132 now_ = [NSDate date];
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];
3139 [install_ setPackages:packages];
3140 [changes_ setPackages:packages];
3141 [manage_ setPackages:packages];
3142 [search_ setPackages:packages];
3145 if (size_t count = [changes_ count]) {
3146 NSString *badge([[NSNumber numberWithInt:count] stringValue]);
3147 [buttonbar_ setBadgeValue:badge forButton:3];
3148 [buttonbar_ setBadgeAnimated:YES forButton:3];
3149 [self setApplicationBadge:badge];
3151 [buttonbar_ setBadgeValue:nil forButton:3];
3152 [buttonbar_ setBadgeAnimated:NO forButton:3];
3153 [self removeApplicationBadge];
3156 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
3159 - (void) setPrompt {
3160 [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
3164 pkgProblemResolver *resolver = [database_ resolver];
3166 resolver->InstallProtect();
3167 if (!resolver->Resolve(true))
3172 [database_ prepare];
3173 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
3177 [database_ upgrade];
3182 [self reloadData:NO];
3188 [overlay_ removeFromSuperview];
3192 detachNewThreadSelector:@selector(perform)
3199 - (void) bootstrap_ {
3201 [database_ upgrade];
3202 [database_ prepare];
3203 [database_ perform];
3206 - (void) bootstrap {
3208 detachNewThreadSelector:@selector(bootstrap_)
3211 title:@"Bootstrap Install..."
3217 detachNewThreadSelector:@selector(update)
3220 title:@"Refreshing Sources..."
3224 - (void) progressViewIsComplete:(ProgressView *)progress {
3225 [self reloadData:YES];
3227 if (confirm_ != nil) {
3228 [underlay_ addSubview:overlay_];
3229 [confirm_ removeFromSuperview];
3235 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
3242 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3243 initWithTitle:@"About Cydia Packager"
3244 buttons:[NSArray arrayWithObjects:@"Close", nil]
3245 defaultButtonIndex:0
3251 @"Copyright (C) 2008\n"
3252 "Jay Freeman (saurik)\n"
3253 "saurik@saurik.com\n"
3254 "http://www.saurik.com/\n"
3257 "http://www.theokorigroup.com/\n"
3259 "College of Creative Studies,\n"
3260 "University of California,\n"
3262 "http://www.ccs.ucsb.edu/\n"
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"
3272 [sheet presentSheetFromButtonBar:buttonbar_];
3277 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3281 - (void) buttonBarItemTapped:(id)sender {
3284 switch ([sender tag]) {
3285 case 1: view = featured_; break;
3286 case 2: view = install_; break;
3287 case 3: view = changes_; break;
3288 case 4: view = manage_; break;
3289 case 5: view = search_; break;
3295 if ([view respondsToSelector:@selector(resetView)])
3296 [(id) view resetView];
3297 [transition_ transition:0 toView:view];
3300 - (void) view:(UIView *)view didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
3301 [scroller_ setContentSize:frame.size];
3302 [indicator_ stopAnimation];
3305 - (void) applicationWillSuspend {
3307 system("launchctl stop com.apple.SpringBoard");
3310 - (void) applicationDidFinishLaunching:(id)unused {
3311 _assert(pkgInitConfig(*_config));
3312 _assert(pkgInitSystem(*_config, _system));
3317 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
3318 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
3320 [window_ orderFront: self];
3321 [window_ makeKey: self];
3322 [window_ _setHidden: NO];
3324 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] delegate:self];
3325 [window_ setContentView:progress_];
3327 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
3328 [progress_ setContentView:underlay_];
3330 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
3333 [underlay_ addSubview:overlay_];
3335 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
3336 0, 0, screenrect.size.width, screenrect.size.height - 48
3339 [overlay_ addSubview:transition_];
3341 featured_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
3343 CGSize navsize = [UINavigationBar defaultSizeWithPrompt];
3344 CGRect navrect = {{0, 0}, navsize};
3346 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
3347 [featured_ addSubview:navbar_];
3349 [navbar_ setBarStyle:1];
3350 [navbar_ setDelegate:self];
3351 [navbar_ setPrompt:@"Welcome to Cydia Packager"];
3353 [navbar_ showButtonsWithLeftTitle:@"About" rightTitle:@"Reload"];
3355 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Featured"] autorelease];
3356 [navbar_ pushNavigationItem:navitem];
3358 struct CGRect subbounds = [featured_ bounds];
3359 subbounds.origin.y += navsize.height;
3360 subbounds.size.height -= navsize.height;
3362 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:subbounds] autorelease];
3363 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
3364 [featured_ addSubview:pinstripe];
3366 scroller_ = [[UIScroller alloc] initWithFrame:subbounds];
3367 [featured_ addSubview:scroller_];
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];
3376 webview_ = [[UIWebView alloc] initWithFrame:[scroller_ bounds]];
3377 [scroller_ addSubview:webview_];
3379 [webview_ setTilingEnabled:YES];
3380 [webview_ setTileSize:CGSizeMake(screenrect.size.width, 500)];
3381 [webview_ setAutoresizes:YES];
3382 [webview_ setDelegate:self];
3384 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:2];
3385 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(87, 45, indsize.width, indsize.height)];
3386 [indicator_ setStyle:2];
3387 [featured_ addSubview:indicator_];
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,
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,
3410 [NSDictionary dictionaryWithObjectsAndKeys:
3411 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3412 @"changes-up.png", kUIButtonBarButtonInfo,
3413 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
3414 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
3415 self, kUIButtonBarButtonTarget,
3416 @"Changes", kUIButtonBarButtonTitle,
3417 @"0", kUIButtonBarButtonType,
3420 [NSDictionary dictionaryWithObjectsAndKeys:
3421 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3422 @"manage-up.png", kUIButtonBarButtonInfo,
3423 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
3424 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
3425 self, kUIButtonBarButtonTarget,
3426 @"Uninstall", kUIButtonBarButtonTitle,
3427 @"0", kUIButtonBarButtonType,
3430 [NSDictionary dictionaryWithObjectsAndKeys:
3431 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3432 @"search-up.png", kUIButtonBarButtonInfo,
3433 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
3434 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
3435 self, kUIButtonBarButtonTarget,
3436 @"Search", kUIButtonBarButtonTitle,
3437 @"0", kUIButtonBarButtonType,
3441 buttonbar_ = [[UIButtonBar alloc]
3443 withFrame:CGRectMake(
3444 0, screenrect.size.height - 48,
3445 screenrect.size.width, 48
3447 withItemList:buttonitems
3450 [buttonbar_ setDelegate:self];
3451 [buttonbar_ setBarStyle:1];
3452 [buttonbar_ setButtonBarTrackingMode:2];
3454 int buttons[5] = {1, 2, 3, 4, 5};
3455 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
3456 [buttonbar_ showButtonGroup:0 withDuration:0];
3458 for (int i = 0; i != 5; ++i)
3459 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
3460 i * 64 + 2, 1, 60, 48
3463 [buttonbar_ showSelectionForButton:1];
3464 [transition_ transition:0 toView:featured_];
3466 [overlay_ addSubview:buttonbar_];
3468 [UIKeyboard initImplementationNow];
3470 CGRect edtrect = [overlay_ bounds];
3471 edtrect.origin.y += navsize.height;
3472 edtrect.size.height -= navsize.height;
3474 CGSize keysize = [UIKeyboard defaultSize];
3475 CGRect keyrect = {{0, [overlay_ bounds].size.height - keysize.height}, keysize};
3476 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
3478 database_ = [[Database alloc] init];
3479 [database_ setDelegate:progress_];
3481 install_ = [[InstallView alloc] initWithFrame:[transition_ bounds]];
3482 [install_ setDelegate:self];
3484 changes_ = [[ChangesView alloc] initWithFrame:[transition_ bounds]];
3485 [changes_ setDelegate:self];
3487 manage_ = [[ManageView alloc] initWithFrame:[transition_ bounds]];
3488 [manage_ setDelegate:self];
3490 search_ = [[SearchView alloc] initWithFrame:[transition_ bounds]];
3491 [search_ setDelegate:self];
3493 [self reloadData:NO];
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];
3500 url_ = [NSURL URLWithString:@"http://cydia.saurik.com/"];
3503 [progress_ resetView];
3509 - (void) showKeyboard:(BOOL)show {
3511 [overlay_ addSubview:keyboard_];
3513 [keyboard_ removeFromSuperview];
3518 void AddPreferences(NSString *plist) {
3519 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
3521 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
3522 _assert(settings != NULL);
3523 NSMutableArray *items = [settings objectForKey:@"items"];
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"]) {
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",
3547 nil] atIndex:(i + 1)];
3553 _assert([settings writeToFile:plist atomically:YES] == YES);
3560 id Alloc_(id self, SEL selector) {
3561 id object = alloc_(self, selector);
3562 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
3566 int main(int argc, char *argv[]) {
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;
3574 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
3579 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
3580 alloc_ = alloc->method_imp;
3581 alloc->method_imp = (IMP) &Alloc_;*/
3583 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
3586 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
3587 char *machine = new char[size];
3588 sysctlbyname("hw.machine", machine, &size, NULL, 0);
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()));
3598 IOObjectRelease(service);
3601 AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
3602 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");
3604 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
3605 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
3607 Packages_ = [Metadata_ objectForKey:@"Packages"];
3609 UIApplicationMain(argc, argv, [Cydia class]);