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);
192 CFRelease(formatted);
195 return [(NSString *) formatted autorelease];
198 @protocol ProgressDelegate
199 - (void) setError:(NSString *)error;
200 - (void) setTitle:(NSString *)title;
201 - (void) setPercent:(float)percent;
202 - (void) addOutput:(NSString *)output;
205 NSString *SizeString(double size) {
207 while (size > 1024) {
212 static const char *powers_[] = {"B", "kB", "MB", "GB"};
214 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
217 static const float TextViewOffset_ = 22;
219 UITextView *GetTextView(NSString *value, float left, bool html) {
220 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
221 [text setEditable:NO];
222 [text setTextSize:16];
224 [text setHTML:value];
226 [text setText:value];
227 [text setEnabled:NO];
229 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
230 CGColor clear(space, 0, 0, 0, 0);
231 [text setBackgroundColor:clear];
232 CGColorSpaceRelease(space);
234 CGRect frame = [text frame];
235 [text setFrame:frame];
236 CGRect rect = [text visibleTextRect];
237 frame.size.height = rect.size.height;
238 [text setFrame:frame];
243 /* Status Delegation {{{ */
245 public pkgAcquireStatus
256 void setDelegate(id delegate) {
257 delegate_ = delegate;
260 virtual bool MediaChange(std::string media, std::string drive) {
264 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
267 virtual void Fetch(pkgAcquire::ItemDesc &item) {
268 [delegate_ setTitle:[NSString stringWithCString:("Downloading " + item.ShortDesc).c_str()]];
271 virtual void Done(pkgAcquire::ItemDesc &item) {
274 virtual void Fail(pkgAcquire::ItemDesc &item) {
276 item.Owner->Status == pkgAcquire::Item::StatIdle ||
277 item.Owner->Status == pkgAcquire::Item::StatDone
281 [delegate_ setError:[NSString stringWithCString:item.Owner->ErrorText.c_str()]];
284 virtual bool Pulse(pkgAcquire *Owner) {
285 bool value = pkgAcquireStatus::Pulse(Owner);
288 double(CurrentBytes + CurrentItems) /
289 double(TotalBytes + TotalItems)
292 [delegate_ setPercent:percent];
296 virtual void Start() {
299 virtual void Stop() {
303 /* Progress Delegation {{{ */
311 virtual void Update() {
312 [delegate_ setTitle:[NSString stringWithCString:Op.c_str()]];
313 [delegate_ setPercent:(Percent / 100)];
322 void setDelegate(id delegate) {
323 delegate_ = delegate;
326 virtual void Done() {
327 [delegate_ setPercent:1];
332 /* External Constants {{{ */
333 extern NSString *kUIButtonBarButtonAction;
334 extern NSString *kUIButtonBarButtonInfo;
335 extern NSString *kUIButtonBarButtonInfoOffset;
336 extern NSString *kUIButtonBarButtonSelectedInfo;
337 extern NSString *kUIButtonBarButtonStyle;
338 extern NSString *kUIButtonBarButtonTag;
339 extern NSString *kUIButtonBarButtonTarget;
340 extern NSString *kUIButtonBarButtonTitle;
341 extern NSString *kUIButtonBarButtonTitleVerticalHeight;
342 extern NSString *kUIButtonBarButtonTitleWidth;
343 extern NSString *kUIButtonBarButtonType;
345 /* Mime Addresses {{{ */
346 Pcre email_r("^\"?(.*)\"? <([^>]*)>$");
348 @interface Address : NSObject {
356 - (NSString *) email;
358 + (Address *) addressWithString:(NSString *)string;
359 - (Address *) initWithString:(NSString *)string;
362 @implementation Address
371 - (NSString *) name {
375 - (NSString *) email {
379 + (Address *) addressWithString:(NSString *)string {
380 return [[[Address alloc] initWithString:string] autorelease];
383 - (Address *) initWithString:(NSString *)string {
384 if ((self = [super init]) != nil) {
385 const char *data = [string UTF8String];
386 size_t size = [string length];
388 if (email_r(data, size)) {
389 name_ = [email_r[1] retain];
390 email_ = [email_r[2] retain];
392 name_ = [[NSString stringWithCString:data length:size] retain];
401 /* Right Alignment {{{ */
402 @interface UIRightTextLabel : UITextLabel {
403 float _savedRightEdgeX;
404 BOOL _sizedtofit_flag;
407 - (void) setFrame:(CGRect)frame;
408 - (void) setText:(NSString *)text;
409 - (void) realignText;
412 @implementation UIRightTextLabel
414 - (void) setFrame:(CGRect)frame {
415 [super setFrame:frame];
416 if (_sizedtofit_flag == NO) {
417 _savedRightEdgeX = frame.origin.x;
422 - (void) setText:(NSString *)text {
423 [super setText:text];
427 - (void) realignText {
428 CGRect oldFrame = [self frame];
430 _sizedtofit_flag = YES;
431 [self sizeToFit]; // shrink down size so I can right align it
433 CGRect newFrame = [self frame];
435 oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width;
436 oldFrame.size.width = newFrame.size.width;
437 [super setFrame:oldFrame];
438 _sizedtofit_flag = NO;
443 /* Linear Algebra {{{ */
444 inline float interpolate(float begin, float end, float fraction) {
445 return (end - begin) * fraction + begin;
451 /* Database Interface {{{ */
452 @interface Database : NSObject {
454 pkgRecords *records_;
455 pkgProblemResolver *resolver_;
456 pkgAcquire *fetcher_;
458 SPtr<pkgPackageManager> manager_;
468 - (void) _readStatus:(NSNumber *)fd;
469 - (void) _readOutput:(NSNumber *)fd;
471 - (Package *) packageWithName:(NSString *)name;
474 - (pkgCacheFile &) cache;
475 - (pkgRecords *) records;
476 - (pkgProblemResolver *) resolver;
477 - (pkgAcquire &) fetcher;
485 - (void) setDelegate:(id)delegate;
490 @interface ResetView : UIView {
491 UIPushButton *reload_;
492 NSMutableArray *views_;
493 UINavigationBar *navbar_;
494 UITransitionView *transition_;
501 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item;
503 - (id) initWithFrame:(CGRect)frame;
504 - (void) setDelegate:(id)delegate;
505 - (void) reloadPushed;
507 - (void) pushView:(UIView *)view withTitle:(NSString *)title backButtonTitle:(NSString *)back rightButton:(NSString *)right;
508 - (void) popViews:(unsigned)views;
514 @implementation ResetView
518 [transition_ release];
524 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item {
525 [views_ removeLastObject];
526 UIView *view([views_ lastObject]);
527 [view resetViewAnimated:!resetting_];
529 [transition_ transition:2 toView:view];
531 if ([views_ count] == 1)
535 - (id) initWithFrame:(CGRect)frame {
536 if ((self = [super initWithFrame:frame]) != nil) {
537 views_ = [[NSMutableArray arrayWithCapacity:4] retain];
539 struct CGRect bounds = [self bounds];
540 CGSize navsize = [UINavigationBar defaultSizeWithPrompt];
541 CGRect navrect = {{0, 0}, navsize};
543 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
544 [self addSubview:navbar_];
546 [navbar_ setBarStyle:1];
547 [navbar_ setDelegate:self];
549 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
550 bounds.origin.x, bounds.origin.y + navsize.height, bounds.size.width, bounds.size.height - navsize.height
553 //reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(284, 8, 29, 23)];
554 reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(282, 5, 29, 23)];
555 [reload_ setShowPressFeedback:YES];
556 [reload_ setImage:[UIImage applicationImageNamed:@"reload.png"]];
557 [reload_ addTarget:self action:@selector(reloadPushed) forEvents:1];
559 [navbar_ addSubview:reload_];
561 [self addSubview:transition_];
565 - (void) setDelegate:(id)delegate {
566 delegate_ = delegate;
569 - (void) reloadPushed {
573 - (void) pushView:(UIView *)view withTitle:(NSString *)title backButtonTitle:(NSString *)back rightButton:(NSString *)right {
574 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:title] autorelease];
575 [navbar_ pushNavigationItem:navitem];
576 [navitem setBackButtonTitle:back];
578 [navbar_ showButtonsWithLeftTitle:nil rightTitle:right];
580 [transition_ transition:([views_ count] == 0 ? 0 : 1) toView:view];
581 [views_ addObject:view];
584 - (void) popViews:(unsigned)views {
586 for (unsigned i(0); i != views; ++i)
587 [navbar_ popNavigationItem];
590 [transition_ transition:2 toView:[views_ lastObject]];
595 if ([[navbar_ navigationItems] count] == 1)
598 [navbar_ popNavigationItem];
599 while ([[navbar_ navigationItems] count] != 1);
602 [transition_ transition:0 toView:[views_ lastObject]];
605 - (void) _resetView {
606 [navbar_ showButtonsWithLeftTitle:nil rightTitle:nil];
610 [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
615 /* Confirmation View {{{ */
616 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
617 if ([packages count] == 0)
620 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 110, false);
621 [fields setObject:text forKey:key];
623 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
624 CGColor blue(space, 0, 0, 0.4, 1);
625 [text setTextColor:blue];
626 CGColorSpaceRelease(space);
629 @protocol ConfirmationViewDelegate
634 @interface ConfirmationView : UIView {
637 UITransitionView *transition_;
639 UINavigationBar *navbar_;
640 UIPreferencesTable *table_;
641 NSMutableDictionary *fields_;
642 UIAlertSheet *essential_;
648 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
649 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
650 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
652 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
653 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group;
654 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed;
655 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
656 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
658 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
662 @implementation ConfirmationView
665 [transition_ release];
670 if (essential_ != nil)
671 [essential_ release];
676 [transition_ transition:7 toView:nil];
680 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
681 if (from != nil && to == nil)
682 [self removeFromSuperview];
685 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
688 if (essential_ != nil)
689 [essential_ popupAlertAnimated:YES];
700 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
701 [essential_ dismiss];
705 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
709 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
711 case 0: return @"Statistics";
712 case 1: return @"Modifications";
714 default: _assert(false);
718 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
721 case 1: return [fields_ count];
723 default: _assert(false);
727 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
728 if (group != 1 || row == -1)
731 _assert(size_t(row) < [fields_ count]);
732 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
736 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
737 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
738 [cell setShowSelection:NO];
741 case 0: switch (row) {
743 [cell setTitle:@"Downloading"];
744 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
748 [cell setTitle:@"Resuming At"];
749 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
753 double size([database_ cache]->UsrSize());
756 [cell setTitle:@"Disk Freeing"];
757 [cell setValue:SizeString(-size)];
759 [cell setTitle:@"Disk Using"];
760 [cell setValue:SizeString(size)];
764 default: _assert(false);
768 _assert(size_t(row) < [fields_ count]);
769 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
770 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
773 default: _assert(false);
779 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
780 if ((self = [super initWithFrame:[view bounds]]) != nil) {
781 database_ = database;
782 delegate_ = delegate;
784 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
785 [self addSubview:transition_];
787 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
789 CGSize navsize = [UINavigationBar defaultSize];
790 CGRect navrect = {{0, 0}, navsize};
791 CGRect bounds = [overlay_ bounds];
793 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
794 [navbar_ setBarStyle:1];
795 [navbar_ setDelegate:self];
797 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
798 [navbar_ pushNavigationItem:navitem];
799 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
801 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
803 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
804 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
805 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
807 bool essential(false);
809 pkgCacheFile &cache([database_ cache]);
810 for (pkgCache::PkgIterator iterator = cache->PkgBegin(); !iterator.end(); ++iterator) {
811 NSString *name([NSString stringWithCString:iterator.Name()]);
812 if (cache[iterator].NewInstall())
813 [installing addObject:name];
814 else if (cache[iterator].Upgrade())
815 [upgrading addObject:name];
816 else if (cache[iterator].Delete()) {
817 [removing addObject:name];
818 if ((iterator->Flags & pkgCache::Flag::Essential) != 0)
826 essential_ = [[UIAlertSheet alloc]
827 initWithTitle:@"Unable to Comply"
828 buttons:[NSArray arrayWithObjects:@"Okay", nil]
834 [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."];
837 AddTextView(fields_, installing, @"Installing");
838 AddTextView(fields_, upgrading, @"Upgrading");
839 AddTextView(fields_, removing, @"Removing");
841 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
842 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
845 [table_ setReusesTableCells:YES];
846 [table_ setDataSource:self];
849 [overlay_ addSubview:navbar_];
850 [overlay_ addSubview:table_];
852 [view addSubview:self];
854 [transition_ setDelegate:self];
856 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
857 [transition_ transition:0 toView:blank];
858 [transition_ transition:3 toView:overlay_];
865 /* Package Class {{{ */
866 NSString *Scour(const char *field, const char *begin, const char *end) {
867 size_t i(0), l(strlen(field));
870 const char *name = begin + i;
871 const char *colon = name + l;
872 const char *value = colon + 1;
877 memcmp(name, field, l) == 0
879 while (value != end && value[0] == ' ')
881 const char *line = std::find(value, end, '\n');
882 while (line != value && line[-1] == ' ')
884 return [NSString stringWithCString:value length:(line - value)];
886 begin = std::find(begin, end, '\n');
894 @interface Package : NSObject {
895 pkgCache::PkgIterator iterator_;
897 pkgCache::VerIterator version_;
898 pkgCache::VerFileIterator file_;
901 NSString *installed_;
913 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file;
914 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
916 - (NSString *) section;
917 - (Address *) maintainer;
919 - (NSString *) description;
920 - (NSString *) index;
924 - (NSString *) latest;
925 - (NSString *) installed;
930 - (NSString *) tagline;
932 - (NSString *) bundle;
933 - (NSString *) website;
935 - (BOOL) matches:(NSString *)text;
937 - (NSComparisonResult) compareByName:(Package *)package;
938 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
939 - (NSComparisonResult) compareForChanges:(Package *)package;
945 @implementation Package
949 if (installed_ != nil)
950 [installed_ release];
963 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file {
964 if ((self = [super init]) != nil) {
965 iterator_ = iterator;
966 database_ = database;
971 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
973 const char *begin, *end;
974 parser->GetRec(begin, end);
976 latest_ = [[NSString stringWithCString:version_.VerStr()] retain];
977 installed_ = iterator_.CurrentVer().end() ? nil : [[NSString stringWithCString:iterator_.CurrentVer().VerStr()] retain];
979 id_ = [[[NSString stringWithCString:iterator_.Name()] lowercaseString] retain];
980 name_ = Scour("Name", begin, end);
982 name_ = [name_ retain];
983 tagline_ = [[NSString stringWithCString:parser->ShortDesc().c_str()] retain];
984 icon_ = Scour("Icon", begin, end);
986 icon_ = [icon_ retain];
987 bundle_ = Scour("Bundle", begin, end);
989 bundle_ = [bundle_ retain];
990 website_ = Scour("Website", begin, end);
992 website_ = [website_ retain];
994 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
995 if (metadata == nil) {
996 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
1000 [Packages_ setObject:metadata forKey:id_];
1005 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1006 for (pkgCache::VerIterator version = iterator.VersionList(); !version.end(); ++version)
1007 for (pkgCache::VerFileIterator file = version.FileList(); !file.end(); ++file)
1008 return [[[Package alloc]
1009 initWithIterator:iterator
1017 - (NSString *) section {
1018 return [[NSString stringWithCString:iterator_.Section()] stringByReplacingCharacter:'_' withCharacter:' '];
1021 - (Address *) maintainer {
1022 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1023 return [Address addressWithString:[NSString stringWithCString:parser->Maintainer().c_str()]];
1027 return version_->InstalledSize;
1030 - (NSString *) description {
1031 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1032 NSString *description([NSString stringWithCString:parser->LongDesc().c_str()]);
1034 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1035 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1036 if ([lines count] < 2)
1039 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1040 for (size_t i(1); i != [lines count]; ++i) {
1041 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1042 [trimmed addObject:trim];
1045 return [trimmed componentsJoinedByString:@"\n"];
1048 - (NSString *) index {
1049 return [[[self name] substringToIndex:1] uppercaseString];
1053 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1056 - (NSString *) latest {
1060 - (NSString *) installed {
1064 - (BOOL) upgradable {
1065 NSString *installed = [self installed];
1066 return installed != nil && [[self latest] compare:installed] != NSOrderedSame ? YES : NO;
1073 - (NSString *) name {
1074 return name_ == nil ? id_ : name_;
1077 - (NSString *) tagline {
1081 - (NSString *) icon {
1085 - (NSString *) bundle {
1089 - (NSString *) website {
1093 - (BOOL) matches:(NSString *)text {
1099 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1100 if (range.location != NSNotFound)
1103 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1104 if (range.location != NSNotFound)
1110 - (NSComparisonResult) compareByName:(Package *)package {
1111 return [[self name] caseInsensitiveCompare:[package name]];
1114 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1115 NSComparisonResult result = [[self section] caseInsensitiveCompare:[package section]];
1116 if (result != NSOrderedSame)
1118 return [self compareByName:package];
1121 - (NSComparisonResult) compareForChanges:(Package *)package {
1122 BOOL lhs = [self upgradable];
1123 BOOL rhs = [package upgradable];
1126 return lhs ? NSOrderedAscending : NSOrderedDescending;
1128 switch ([[self seen] compare:[package seen]]) {
1129 case NSOrderedAscending:
1130 return NSOrderedDescending;
1133 case NSOrderedDescending:
1134 return NSOrderedAscending;
1140 return [self compareByName:package];
1144 pkgProblemResolver *resolver = [database_ resolver];
1145 resolver->Clear(iterator_);
1146 resolver->Protect(iterator_);
1147 [database_ cache]->MarkInstall(iterator_, false);
1151 pkgProblemResolver *resolver = [database_ resolver];
1152 resolver->Clear(iterator_);
1153 resolver->Protect(iterator_);
1154 resolver->Remove(iterator_);
1155 [database_ cache]->MarkDelete(iterator_, true);
1160 /* Section Class {{{ */
1161 @interface Section : NSObject {
1164 NSMutableArray *packages_;
1169 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1170 - (NSString *) name;
1172 - (NSArray *) packages;
1174 - (void) addPackage:(Package *)package;
1177 @implementation Section
1181 [packages_ release];
1185 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1186 if ((self = [super init]) != nil) {
1187 name_ = [name retain];
1189 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1193 - (NSString *) name {
1201 - (NSArray *) packages {
1206 return [packages_ count];
1209 - (void) addPackage:(Package *)package {
1210 [packages_ addObject:package];
1216 /* Package View {{{ */
1217 @protocol PackageViewDelegate
1218 - (void) performPackage:(Package *)package;
1221 @interface PackageView : UIView {
1222 UIPreferencesTable *table_;
1224 UITextView *description_;
1230 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
1231 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group;
1232 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed;
1233 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
1234 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
1236 - (BOOL) canSelectRow:(int)row;
1237 - (void) tableRowSelected:(NSNotification *)notification;
1239 - (Package *) package;
1241 - (id) initWithFrame:(struct CGRect)frame;
1242 - (void) setPackage:(Package *)package;
1243 - (void) setDelegate:(id)delegate;
1246 @implementation PackageView
1249 if (package_ != nil)
1251 if (description_ != nil)
1252 [description_ release];
1257 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
1261 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
1264 case 1: return @"Details";
1265 case 2: return @"Source";
1267 default: _assert(false);
1271 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
1272 if (group != 0 || row != 1)
1275 return [description_ visibleTextRect].size.height + TextViewOffset_;
1278 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
1284 default: _assert(false);
1288 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
1289 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
1290 [cell setShowSelection:NO];
1293 case 0: switch (row) {
1295 [cell setTitle:[package_ name]];
1296 [cell setValue:[package_ latest]];
1300 [cell addSubview:description_];
1303 default: _assert(false);
1306 case 1: switch (row) {
1308 [cell setTitle:@"Identifier"];
1309 [cell setValue:[package_ id]];
1313 [cell setTitle:@"Installed Version"];
1314 NSString *installed([package_ installed]);
1315 [cell setValue:(installed == nil ? @"n/a" : installed)];
1319 [cell setTitle:@"Section"];
1320 [cell setValue:[package_ section]];
1324 [cell setTitle:@"Expanded Size"];
1325 [cell setValue:SizeString([package_ size])];
1329 [cell setTitle:@"Maintainer"];
1330 [cell setValue:[[package_ maintainer] name]];
1331 [cell setShowDisclosure:YES];
1332 [cell setShowSelection:YES];
1335 default: _assert(false);
1338 case 2: switch (row) {
1341 default: _assert(false);
1347 - (BOOL) canSelectRow:(int)row {
1351 - (void) tableRowSelected:(NSNotification *)notification {
1352 printf("%d\n", [table_ selectedRow]);
1353 switch ([table_ selectedRow]) {
1355 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
1356 [[package_ maintainer] email],
1357 [[NSString stringWithFormat:@"regarding apt package \"%@\"", [package_ name]] stringByAddingPercentEscapes]
1363 - (Package *) package {
1367 - (id) initWithFrame:(struct CGRect)frame {
1368 if ((self = [super initWithFrame:frame]) != nil) {
1369 table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]];
1370 [self addSubview:table_];
1372 [table_ setDataSource:self];
1373 [table_ setDelegate:self];
1377 - (void) setPackage:(Package *)package {
1378 if (package_ != nil) {
1379 [package_ autorelease];
1383 if (description_ != nil) {
1384 [description_ release];
1388 if (package != nil) {
1389 package_ = [package retain];
1391 NSString *description([package description]);
1392 if (description == nil)
1393 description = [package tagline];
1394 description_ = [GetTextView(description, 12, true) retain];
1396 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1397 CGColor black(space, 0, 0, 0, 1);
1398 [description_ setTextColor:black];
1399 CGColorSpaceRelease(space);
1401 [table_ reloadData];
1405 - (void) setDelegate:(id)delegate {
1406 delegate_ = delegate;
1411 /* Package Cell {{{ */
1412 @interface PackageCell : UITableCell {
1414 UITextLabel *version_;
1415 UITextLabel *description_;
1421 - (PackageCell *) initWithVersioner:(SEL)versioner;
1422 - (void) setPackage:(Package *)package;
1424 - (void) _setSelected:(float)fraction;
1425 - (void) setSelected:(BOOL)selected;
1426 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
1427 - (void) _setSelectionFadeFraction:(float)fraction;
1431 @implementation PackageCell
1436 [description_ release];
1440 - (PackageCell *) initWithVersioner:(SEL)versioner {
1441 if ((self = [super init]) != nil) {
1442 versioner_ = versioner;
1444 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
1445 GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
1446 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
1448 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1450 CGColor clear(space, 0, 0, 0, 0);
1452 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 7, 250, 25)];
1453 [name_ setBackgroundColor:clear];
1454 [name_ setFont:bold];
1456 version_ = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(286, 7, 70, 25)];
1457 [version_ setBackgroundColor:clear];
1458 [version_ setFont:large];
1460 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(13, 35, 315, 20)];
1461 [description_ setBackgroundColor:clear];
1462 [description_ setFont:small];
1464 [self addSubview:name_];
1465 [self addSubview:version_];
1466 [self addSubview:description_];
1468 CGColorSpaceRelease(space);
1476 - (void) setPackage:(Package *)package {
1477 [name_ setText:[package name]];
1478 [version_ setText:[package latest]];
1479 [description_ setText:[package tagline]];
1482 - (void) _setSelected:(float)fraction {
1483 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1485 CGColor black(space,
1486 interpolate(0.0, 1.0, fraction),
1487 interpolate(0.0, 1.0, fraction),
1488 interpolate(0.0, 1.0, fraction),
1492 interpolate(0.2, 1.0, fraction),
1493 interpolate(0.2, 1.0, fraction),
1494 interpolate(1.0, 1.0, fraction),
1498 interpolate(0.4, 1.0, fraction),
1499 interpolate(0.4, 1.0, fraction),
1500 interpolate(0.4, 1.0, fraction),
1503 [name_ setColor:black];
1504 [version_ setColor:blue];
1505 [description_ setColor:gray];
1507 CGColorSpaceRelease(space);
1510 - (void) setSelected:(BOOL)selected {
1511 [self _setSelected:(selected ? 1.0 : 0.0)];
1512 [super setSelected:selected];
1515 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
1517 [self _setSelected:(selected ? 1.0 : 0.0)];
1518 [super setSelected:selected withFade:fade];
1521 - (void) _setSelectionFadeFraction:(float)fraction {
1522 [self _setSelected:fraction];
1523 [super _setSelectionFadeFraction:fraction];
1529 /* Database Implementation {{{ */
1530 @implementation Database
1537 - (void) _readStatus:(NSNumber *)fd {
1538 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1540 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1541 std::istream is(&ib);
1546 pcre *code = pcre_compile("^([^:]*):([^:]*):([^:]*):(.*)$", 0, &error, &offset, NULL);
1548 pcre_extra *study = NULL;
1550 pcre_fullinfo(code, study, PCRE_INFO_CAPTURECOUNT, &capture);
1551 int matches[(capture + 1) * 3];
1553 while (std::getline(is, line)) {
1554 const char *data(line.c_str());
1556 _assert(pcre_exec(code, study, data, line.size(), 0, 0, matches, sizeof(matches) / sizeof(matches[0])) >= 0);
1558 std::istringstream buffer(line.substr(matches[6], matches[7] - matches[6]));
1561 [delegate_ setPercent:(percent / 100)];
1563 NSString *string = [NSString stringWithCString:(data + matches[8]) length:(matches[9] - matches[8])];
1564 std::string type(line.substr(matches[2], matches[3] - matches[2]));
1566 if (type == "pmerror")
1567 [delegate_ setError:string];
1568 else if (type == "pmstatus")
1569 [delegate_ setTitle:string];
1570 else if (type == "pmconffile")
1572 else _assert(false);
1579 - (void) _readOutput:(NSNumber *)fd {
1580 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1582 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1583 std::istream is(&ib);
1586 while (std::getline(is, line))
1587 [delegate_ addOutput:[NSString stringWithCString:line.c_str()]];
1593 - (Package *) packageWithName:(NSString *)name {
1594 pkgCache::PkgIterator iterator(cache_->FindPkg([name cString]));
1595 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1598 - (Database *) init {
1599 if ((self = [super init]) != nil) {
1607 _assert(pipe(fds) != -1);
1611 detachNewThreadSelector:@selector(_readStatus:)
1613 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1616 _assert(pipe(fds) != -1);
1617 _assert(dup2(fds[1], 1) != -1);
1618 _assert(close(fds[1]) != -1);
1621 detachNewThreadSelector:@selector(_readOutput:)
1623 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1628 - (pkgCacheFile &) cache {
1632 - (pkgRecords *) records {
1636 - (pkgProblemResolver *) resolver {
1640 - (pkgAcquire &) fetcher {
1644 - (void) reloadData {
1652 _assert(cache_.Open(progress_, true));
1653 records_ = new pkgRecords(cache_);
1654 resolver_ = new pkgProblemResolver(cache_);
1655 fetcher_ = new pkgAcquire(&status_);
1660 pkgRecords records(cache_);
1662 lock_ = new FileFd();
1663 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1664 _assert(!_error->PendingError());
1667 _assert(list.ReadMainList());
1669 manager_ = (_system->CreatePM(cache_));
1670 _assert(manager_->GetArchives(fetcher_, &list, &records));
1671 _assert(!_error->PendingError());
1675 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue)
1679 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
1681 if (result == pkgPackageManager::Failed)
1683 if (_error->PendingError())
1685 if (result != pkgPackageManager::Completed)
1691 _assert(list.ReadMainList());
1694 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
1695 _assert(!_error->PendingError());
1697 pkgAcquire fetcher(&status_);
1698 _assert(list.GetIndexes(&fetcher));
1699 _assert(fetcher.Run(PulseInterval_) != pkgAcquire::Failed);
1701 bool failed = false;
1702 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
1703 if ((*item)->Status != pkgAcquire::Item::StatDone) {
1704 (*item)->Finished();
1708 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
1709 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
1710 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
1713 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
1717 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1718 _assert(pkgApplyStatus(cache_));
1720 if (cache_->BrokenCount() != 0) {
1721 _assert(pkgFixBroken(cache_));
1722 _assert(cache_->BrokenCount() == 0);
1723 _assert(pkgMinimizeUpgrade(cache_));
1726 _assert(pkgDistUpgrade(cache_));
1729 - (void) setDelegate:(id)delegate {
1730 delegate_ = delegate;
1731 status_.setDelegate(delegate);
1732 progress_.setDelegate(delegate);
1738 /* Progress Data {{{ */
1739 @interface ProgressData : NSObject {
1745 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
1752 @implementation ProgressData
1754 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
1755 if ((self = [super init]) != nil) {
1756 selector_ = selector;
1776 /* Progress View {{{ */
1777 @interface ProgressView : UIView <
1781 UIView *background_;
1782 UITransitionView *transition_;
1784 UINavigationBar *navbar_;
1785 UIProgressBar *progress_;
1786 UITextView *output_;
1787 UITextLabel *status_;
1793 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
1795 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate;
1796 - (void) setContentView:(UIView *)view;
1799 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
1801 - (void) _retachThread;
1802 - (void) _detachNewThreadData:(ProgressData *)data;
1803 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
1805 - (void) setError:(NSString *)error;
1806 - (void) _setError:(NSString *)error;
1808 - (void) setTitle:(NSString *)title;
1809 - (void) _setTitle:(NSString *)title;
1811 - (void) setPercent:(float)percent;
1812 - (void) _setPercent:(NSNumber *)percent;
1814 - (void) addOutput:(NSString *)output;
1815 - (void) _addOutput:(NSString *)output;
1818 @protocol ProgressViewDelegate
1819 - (void) progressViewIsComplete:(ProgressView *)sender;
1822 @implementation ProgressView
1826 if (background_ != nil)
1827 [background_ release];
1828 [transition_ release];
1831 [progress_ release];
1837 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
1838 if (bootstrap_ && from == overlay_ && to == view_)
1842 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate {
1843 if ((self = [super initWithFrame:frame]) != nil) {
1844 delegate_ = delegate;
1846 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1848 CGColor black(space, 0.0, 0.0, 0.0, 1.0);
1849 CGColor white(space, 1.0, 1.0, 1.0, 1.0);
1850 CGColor clear(space, 0.0, 0.0, 0.0, 0.0);
1852 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
1853 [transition_ setDelegate:self];
1855 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
1858 [overlay_ setBackgroundColor:black];
1860 background_ = [[UIView alloc] initWithFrame:[self bounds]];
1861 [background_ setBackgroundColor:black];
1862 [self addSubview:background_];
1865 [self addSubview:transition_];
1867 CGSize navsize = [UINavigationBar defaultSize];
1868 CGRect navrect = {{0, 0}, navsize};
1870 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
1871 [overlay_ addSubview:navbar_];
1873 [navbar_ setBarStyle:1];
1874 [navbar_ setDelegate:self];
1876 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
1877 [navbar_ pushNavigationItem:navitem];
1879 CGRect bounds = [overlay_ bounds];
1880 CGSize prgsize = [UIProgressBar defaultSize];
1883 (bounds.size.width - prgsize.width) / 2,
1884 bounds.size.height - prgsize.height - 20
1887 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
1888 [overlay_ addSubview:progress_];
1890 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
1892 bounds.size.height - prgsize.height - 50,
1893 bounds.size.width - 20,
1897 [status_ setColor:white];
1898 [status_ setBackgroundColor:clear];
1900 [status_ setCentersHorizontally:YES];
1901 //[status_ setFont:font];
1903 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
1905 navrect.size.height + 20,
1906 bounds.size.width - 20,
1907 bounds.size.height - navsize.height - 62 - navrect.size.height
1910 //[output_ setTextFont:@"Courier New"];
1911 [output_ setTextSize:12];
1913 [output_ setTextColor:white];
1914 [output_ setBackgroundColor:clear];
1916 [output_ setMarginTop:0];
1917 [output_ setAllowsRubberBanding:YES];
1919 [overlay_ addSubview:output_];
1920 [overlay_ addSubview:status_];
1922 [progress_ setStyle:0];
1924 CGColorSpaceRelease(space);
1928 - (void) setContentView:(UIView *)view {
1929 view_ = [view retain];
1932 - (void) resetView {
1933 [transition_ transition:6 toView:view_];
1936 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
1940 - (void) _retachThread {
1941 [delegate_ progressViewIsComplete:self];
1945 - (void) _detachNewThreadData:(ProgressData *)data {
1946 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1948 [[data target] performSelector:[data selector] withObject:[data object]];
1951 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
1956 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
1957 [navbar_ popNavigationItem];
1958 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:title] autorelease];
1959 [navbar_ pushNavigationItem:navitem];
1961 [status_ setText:nil];
1962 [output_ setText:@""];
1963 [progress_ setProgress:0];
1965 [transition_ transition:6 toView:overlay_];
1968 detachNewThreadSelector:@selector(_detachNewThreadData:)
1970 withObject:[[ProgressData alloc]
1971 initWithSelector:selector
1978 - (void) setError:(NSString *)error {
1980 performSelectorOnMainThread:@selector(_setError:)
1986 - (void) _setError:(NSString *)error {
1987 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
1988 initWithTitle:@"Package Error"
1989 buttons:[NSArray arrayWithObjects:@"Okay", nil]
1990 defaultButtonIndex:0
1995 [sheet setBodyText:error];
1996 [sheet popupAlertAnimated:YES];
1999 - (void) setTitle:(NSString *)title {
2001 performSelectorOnMainThread:@selector(_setTitle:)
2007 - (void) _setTitle:(NSString *)title {
2008 [status_ setText:[title stringByAppendingString:@"..."]];
2011 - (void) setPercent:(float)percent {
2013 performSelectorOnMainThread:@selector(_setPercent:)
2014 withObject:[NSNumber numberWithFloat:percent]
2019 - (void) _setPercent:(NSNumber *)percent {
2020 [progress_ setProgress:[percent floatValue]];
2023 - (void) addOutput:(NSString *)output {
2025 performSelectorOnMainThread:@selector(_addOutput:)
2031 - (void) _addOutput:(NSString *)output {
2032 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2033 CGSize size = [output_ contentSize];
2034 CGRect rect = {{0, size.height}, {size.width, 0}};
2035 [output_ scrollRectToVisible:rect animated:YES];
2041 /* Package Table {{{ */
2042 @protocol PackageTableDelegate
2043 - (void) packageTable:(id)table packageSelected:(Package *)package;
2046 @interface PackageTable : UIView {
2048 UISectionList *list_;
2052 NSMutableArray *sections_;
2057 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
2058 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
2059 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
2061 - (int) numberOfRowsInTable:(UITable *)table;
2062 - (float) table:(UITable *)table heightForRow:(int)row;
2063 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2064 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2065 - (void) tableRowSelected:(NSNotification *)notification;
2067 - (id) initWithFrame:(CGRect)frame versioner:(SEL)versioner;
2069 - (void) setDelegate:(id)delegate;
2070 - (void) setPackages:(NSArray *)packages;
2072 - (void) resetViewAnimated:(BOOL)animated;
2073 - (UITable *) table;
2076 @implementation PackageTable
2080 [sections_ release];
2081 if (packages_ != nil)
2082 [packages_ release];
2086 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2087 return [sections_ count];
2090 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2091 return [[sections_ objectAtIndex:section] name];
2094 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2095 return [[sections_ objectAtIndex:section] row];
2098 - (int) numberOfRowsInTable:(UITable *)table {
2099 return [packages_ count];
2102 - (float) table:(UITable *)table heightForRow:(int)row {
2106 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2108 reusing = [[[PackageCell alloc] initWithVersioner:versioner_] autorelease];
2109 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2113 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2117 - (void) tableRowSelected:(NSNotification *)notification {
2118 int row = [[notification object] selectedRow];
2119 [delegate_ packageTable:self packageSelected:(row == INT_MAX ? nil : [packages_ objectAtIndex:row])];
2122 - (id) initWithFrame:(CGRect)frame versioner:(SEL)versioner {
2123 if ((self = [super initWithFrame:frame]) != nil) {
2124 versioner_ = versioner;
2125 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
2127 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
2128 [list_ setDataSource:self];
2130 UITableColumn *column = [[[UITableColumn alloc]
2131 initWithTitle:@"Name"
2133 width:frame.size.width
2136 UITable *table = [list_ table];
2137 [table setSeparatorStyle:1];
2138 [table addTableColumn:column];
2139 [table setDelegate:self];
2140 [table setReusesTableCells:YES];
2142 [self addSubview:list_];
2146 - (void) setDelegate:(id)delegate {
2147 delegate_ = delegate;
2150 - (void) setPackages:(NSArray *)packages {
2151 if (packages_ != nil)
2152 [packages_ autorelease];
2153 _assert(packages != nil);
2154 packages_ = [packages retain];
2156 [sections_ removeAllObjects];
2158 Section *section = nil;
2160 for (size_t offset(0); offset != [packages_ count]; ++offset) {
2161 Package *package = [packages_ objectAtIndex:offset];
2162 NSString *name = [package index];
2164 if (section == nil || ![[section name] isEqual:name]) {
2165 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2166 [sections_ addObject:section];
2169 [section addPackage:package];
2175 - (void) resetViewAnimated:(BOOL)animated {
2176 [[list_ table] selectRow:-1 byExtendingSelection:NO withFade:animated];
2179 - (UITable *) table {
2180 return [list_ table];
2186 /* Section Cell {{{ */
2187 @interface SectionCell : UITableCell {
2189 UITextLabel *count_;
2195 - (void) setSection:(Section *)section;
2197 - (void) _setSelected:(float)fraction;
2198 - (void) setSelected:(BOOL)selected;
2199 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2200 - (void) _setSelectionFadeFraction:(float)fraction;
2204 @implementation SectionCell
2213 if ((self = [super init]) != nil) {
2214 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2215 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 12);
2217 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2218 CGColor clear(space, 0, 0, 0, 0);
2219 CGColor white(space, 1, 1, 1, 1);
2221 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(47, 9, 250, 25)];
2222 [name_ setBackgroundColor:clear];
2223 [name_ setFont:bold];
2225 count_ = [[UITextLabel alloc] initWithFrame:CGRectMake(11, 7, 29, 32)];
2226 [count_ setCentersHorizontally:YES];
2227 [count_ setBackgroundColor:clear];
2228 [count_ setFont:small];
2229 [count_ setColor:white];
2231 UIImageView *folder = [[[UIImageView alloc] initWithFrame:CGRectMake(8, 7, 32, 32)] autorelease];
2232 [folder setImage:[UIImage applicationImageNamed:@"folder.png"]];
2234 [self addSubview:folder];
2235 [self addSubview:name_];
2236 [self addSubview:count_];
2238 [self _setSelected:0];
2240 CGColorSpaceRelease(space);
2247 - (void) setSection:(Section *)section {
2248 if (section == nil) {
2249 [name_ setText:@"All Packages"];
2250 [count_ setText:nil];
2252 [name_ setText:[section name]];
2253 [count_ setText:[NSString stringWithFormat:@"%d", [section count]]];
2257 - (void) _setSelected:(float)fraction {
2258 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2260 CGColor black(space,
2261 interpolate(0.0, 1.0, fraction),
2262 interpolate(0.0, 1.0, fraction),
2263 interpolate(0.0, 1.0, fraction),
2266 [name_ setColor:black];
2268 CGColorSpaceRelease(space);
2271 - (void) setSelected:(BOOL)selected {
2272 [self _setSelected:(selected ? 1.0 : 0.0)];
2273 [super setSelected:selected];
2276 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2278 [self _setSelected:(selected ? 1.0 : 0.0)];
2279 [super setSelected:selected withFade:fade];
2282 - (void) _setSelectionFadeFraction:(float)fraction {
2283 [self _setSelected:fraction];
2284 [super _setSelectionFadeFraction:fraction];
2289 /* Install View {{{ */
2290 @interface InstallView : ResetView <
2291 PackageTableDelegate
2295 PackageTable *table_;
2299 NSMutableArray *packages_;
2304 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2306 - (int) numberOfRowsInTable:(UITable *)table;
2307 - (float) table:(UITable *)table heightForRow:(int)row;
2308 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2309 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2310 - (void) tableRowSelected:(NSNotification *)notification;
2312 - (void) packageTable:(id)table packageSelected:(Package *)package;
2314 - (id) initWithFrame:(CGRect)frame;
2315 - (void) setPackages:(NSArray *)packages;
2316 - (void) setDelegate:(id)delegate;
2319 @implementation InstallView
2322 [packages_ release];
2323 if (sections_ != nil)
2324 [sections_ release];
2331 if (section_ != nil)
2333 if (package_ != nil)
2338 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2340 [[view_ package] install];
2341 [delegate_ resolve];
2342 [delegate_ perform];
2346 - (int) numberOfRowsInTable:(UITable *)table {
2347 return [sections_ count] + 1;
2350 - (float) table:(UITable *)table heightForRow:(int)row {
2354 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2356 reusing = [[[SectionCell alloc] init] autorelease];
2358 [(SectionCell *)reusing setSection:nil];
2360 [(SectionCell *)reusing setSection:[sections_ objectAtIndex:(row - 1)]];
2364 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2368 - (void) tableRowSelected:(NSNotification *)notification {
2369 int row = [[notification object] selectedRow];
2371 if (row == INT_MAX) {
2378 _assert(section_ == nil);
2379 _assert(table_ == nil);
2387 name = @"All Packages";
2389 section = [sections_ objectAtIndex:(row - 1)];
2390 name = [section name];
2391 section_ = [name retain];
2394 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
2395 [table_ setDelegate:self];
2396 [table_ setPackages:(section == nil ? packages_ : [section packages])];
2398 [self pushView:table_ withTitle:name backButtonTitle:@"Packages" rightButton:nil];
2402 - (void) packageTable:(id)table packageSelected:(Package *)package {
2403 if (package == nil) {
2410 _assert(package_ == nil);
2411 _assert(view_ == nil);
2413 package_ = [[package name] retain];
2415 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2416 [view_ setDelegate:delegate_];
2418 [view_ setPackage:package];
2420 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:@"Install"];
2424 - (id) initWithFrame:(CGRect)frame {
2425 if ((self = [super initWithFrame:frame]) != nil) {
2426 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2428 list_ = [[UITable alloc] initWithFrame:[transition_ bounds]];
2429 [self pushView:list_ withTitle:@"Install" backButtonTitle:@"Sections" rightButton:nil];
2431 UITableColumn *column = [[[UITableColumn alloc]
2432 initWithTitle:@"Name"
2434 width:frame.size.width
2437 [list_ setDataSource:self];
2438 [list_ setSeparatorStyle:1];
2439 [list_ addTableColumn:column];
2440 [list_ setDelegate:self];
2441 [list_ setReusesTableCells:YES];
2443 [transition_ transition:0 toView:list_];
2447 - (void) setPackages:(NSArray *)packages {
2448 [packages_ removeAllObjects];
2450 for (size_t i(0); i != [packages count]; ++i) {
2451 Package *package([packages objectAtIndex:i]);
2452 if ([package installed] == nil)
2453 [packages_ addObject:package];
2456 [packages_ sortUsingSelector:@selector(compareBySectionAndName:)];
2457 NSMutableArray *sections = [NSMutableArray arrayWithCapacity:16];
2459 Section *nsection = nil;
2460 Package *npackage = nil;
2462 Section *section = nil;
2463 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
2464 Package *package = [packages_ objectAtIndex:offset];
2465 NSString *name = [package section];
2467 if (section == nil || ![[section name] isEqual:name]) {
2468 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2470 if ([name isEqualToString:section_])
2472 [sections addObject:section];
2475 if ([[package name] isEqualToString:package_])
2477 [section addPackage:package];
2480 if (sections_ != nil)
2481 [sections_ release];
2482 sections_ = [sections retain];
2484 [packages_ sortUsingSelector:@selector(compareByName:)];
2490 if (npackage != nil)
2491 [view_ setPackage:npackage];
2492 else if (package_ != nil)
2495 if (nsection != nil)
2496 [table_ setPackages:[nsection packages]];
2497 else if (section_ != nil)
2500 [self popViews:views];
2504 - (void) setDelegate:(id)delegate {
2506 [view_ setDelegate:delegate];
2507 [super setDelegate:delegate];
2512 /* Changes View {{{ */
2513 @interface ChangesView : ResetView <
2514 PackageTableDelegate
2516 UISectionList *list_;
2517 NSMutableArray *packages_;
2518 NSMutableArray *sections_;
2526 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2528 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
2529 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
2530 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
2532 - (int) numberOfRowsInTable:(UITable *)table;
2533 - (float) table:(UITable *)table heightForRow:(int)row;
2534 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2535 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2536 - (void) tableRowSelected:(NSNotification *)notification;
2538 - (id) initWithFrame:(CGRect)frame;
2539 - (void) setPackages:(NSArray *)packages;
2540 - (void) _resetView;
2543 - (void) setDelegate:(id)delegate;
2546 @implementation ChangesView
2550 [packages_ release];
2551 [sections_ release];
2554 if (package_ != nil)
2559 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2560 return [sections_ count];
2563 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2564 return [[sections_ objectAtIndex:section] name];
2567 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2568 return [[sections_ objectAtIndex:section] row];
2571 - (int) numberOfRowsInTable:(UITable *)table {
2572 return [packages_ count];
2575 - (float) table:(UITable *)table heightForRow:(int)row {
2579 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2581 reusing = [[[PackageCell alloc] initWithVersioner:NULL] autorelease];
2582 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2586 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2590 - (void) tableRowSelected:(NSNotification *)notification {
2591 int row = [[notification object] selectedRow];
2592 [self packageTable:self packageSelected:(row == INT_MAX ? nil : [packages_ objectAtIndex:row])];
2595 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2598 [[view_ package] install];
2599 [delegate_ resolve];
2600 [delegate_ perform];
2604 [delegate_ upgrade];
2609 - (void) packageTable:(id)table packageSelected:(Package *)package {
2610 if (package == nil) {
2617 _assert(package_ == nil);
2618 _assert(view_ == nil);
2620 package_ = [[package name] retain];
2622 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2623 [view_ setDelegate:delegate_];
2625 [view_ setPackage:package];
2627 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:(
2628 [package upgradable] ? @"Upgrade" : @"Install"
2633 - (id) initWithFrame:(CGRect)frame {
2634 if ((self = [super initWithFrame:frame]) != nil) {
2635 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2636 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
2638 list_ = [[UISectionList alloc] initWithFrame:[transition_ bounds] showSectionIndex:NO];
2639 [list_ setShouldHideHeaderInShortLists:NO];
2640 [list_ setDataSource:self];
2641 //[list_ setSectionListStyle:1];
2643 UITableColumn *column = [[[UITableColumn alloc]
2644 initWithTitle:@"Name"
2646 width:frame.size.width
2649 UITable *table = [list_ table];
2650 [table setSeparatorStyle:1];
2651 [table addTableColumn:column];
2652 [table setDelegate:self];
2653 [table setReusesTableCells:YES];
2655 [self pushView:list_ withTitle:@"Changes" backButtonTitle:nil rightButton:nil];
2659 - (void) setPackages:(NSArray *)packages {
2660 [packages_ removeAllObjects];
2661 for (size_t i(0); i != [packages count]; ++i) {
2662 Package *package([packages objectAtIndex:i]);
2663 if ([package installed] == nil || [package upgradable])
2664 [packages_ addObject:package];
2667 [packages_ sortUsingSelector:@selector(compareForChanges:)];
2669 [sections_ removeAllObjects];
2671 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades" row:0] autorelease];
2672 Section *section = nil;
2675 Package *npackage = nil;
2676 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
2677 Package *package = [packages_ objectAtIndex:offset];
2678 if ([[package name] isEqualToString:package_])
2681 if ([package upgradable])
2682 [upgradable addPackage:package];
2684 NSDate *seen = [package seen];
2686 CFLocaleRef locale = CFLocaleCopyCurrent();
2687 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
2688 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
2690 NSString *name = (NSString *) formatted;
2692 if (section == nil || ![[section name] isEqual:name]) {
2693 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2694 [sections_ addObject:section];
2697 [section addPackage:package];
2699 CFRelease(formatter);
2700 CFRelease(formatted);
2705 count_ = [[upgradable packages] count];
2707 [sections_ insertObject:upgradable atIndex:0];
2711 if (npackage != nil)
2712 [view_ setPackage:npackage];
2713 else if (package_ != nil)
2715 if ([views_ count] == 1)
2721 - (void) _resetView {
2722 [navbar_ showButtonsWithLeftTitle:(count_ == 0 ? nil : @"Upgrade All") rightTitle:nil];
2729 - (void) setDelegate:(id)delegate {
2731 [view_ setDelegate:delegate];
2732 [super setDelegate:delegate];
2737 /* Manage View {{{ */
2738 @interface ManageView : ResetView <
2739 PackageTableDelegate
2741 PackageTable *table_;
2748 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2750 - (void) packageTable:(id)table packageSelected:(Package *)package;
2752 - (id) initWithFrame:(CGRect)frame;
2753 - (void) setPackages:(NSArray *)packages;
2755 - (void) setDelegate:(id)delegate;
2758 @implementation ManageView
2764 if (package_ != nil)
2769 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2771 [[view_ package] remove];
2772 [delegate_ resolve];
2773 [delegate_ perform];
2777 - (void) packageTable:(id)table packageSelected:(Package *)package {
2778 if (package == nil) {
2785 _assert(package_ == nil);
2786 _assert(view_ == nil);
2788 package_ = [[package name] retain];
2790 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2791 [view_ setDelegate:delegate_];
2793 [view_ setPackage:package];
2795 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:@"Uninstall"];
2799 - (id) initWithFrame:(CGRect)frame {
2800 if ((self = [super initWithFrame:frame]) != nil) {
2801 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
2802 [table_ setDelegate:self];
2804 [self pushView:table_ withTitle:@"Uninstall" backButtonTitle:@"Packages" rightButton:nil];
2808 - (void) setPackages:(NSArray *)packages {
2809 NSMutableArray *local = [NSMutableArray arrayWithCapacity:16];
2810 for (size_t i(0); i != [packages count]; ++i) {
2811 Package *package([packages objectAtIndex:i]);
2812 if ([package installed] != nil)
2813 [local addObject:package];
2816 [local sortUsingSelector:@selector(compareByName:)];
2818 Package *npackage = nil;
2819 for (size_t offset = 0, count = [local count]; offset != count; ++offset) {
2820 Package *package = [local objectAtIndex:offset];
2821 if ([[package name] isEqualToString:package_])
2825 [table_ setPackages:local];
2827 if (npackage != nil)
2828 [view_ setPackage:npackage];
2829 else if (package_ != nil)
2835 - (void) setDelegate:(id)delegate {
2837 [view_ setDelegate:delegate];
2838 [super setDelegate:delegate];
2843 /* Search View {{{ */
2844 @protocol SearchViewDelegate
2845 - (void) showKeyboard:(BOOL)show;
2848 @interface SearchView : ResetView <
2849 PackageTableDelegate
2851 NSMutableArray *packages_;
2853 UISearchField *field_;
2854 PackageTable *table_;
2861 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2862 - (void) packageTable:(id)table packageSelected:(Package *)package;
2864 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field;
2865 - (void) textFieldDidResignFirstResponder:(UITextField *)field;
2867 - (void) keyboardInputChanged:(UIFieldEditor *)editor;
2868 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked;
2870 - (id) initWithFrame:(CGRect)frame;
2871 - (void) setPackages:(NSArray *)packages;
2873 - (void) setDelegate:(id)delegate;
2874 - (void) resetPackage:(Package *)package;
2875 - (void) searchPackages;
2879 @implementation SearchView
2882 [packages_ release];
2883 [accessory_ release];
2888 if (package_ != nil)
2893 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2895 Package *package = [view_ package];
2896 if ([package installed] == nil)
2900 [delegate_ resolve];
2901 [delegate_ perform];
2905 - (void) packageTable:(id)table packageSelected:(Package *)package {
2906 if (package == nil) {
2907 [navbar_ setAccessoryView:accessory_ animate:(resetting_ ? NO : YES) goingBack:YES];
2915 [navbar_ setAccessoryView:nil animate:YES goingBack:NO];
2917 _assert(package_ == nil);
2918 _assert(view_ == nil);
2920 package_ = [[package name] retain];
2922 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2923 [view_ setDelegate:delegate_];
2925 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:nil];
2926 [self resetPackage:package];
2930 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
2931 [delegate_ showKeyboard:YES];
2932 [table_ setEnabled:NO];
2934 /*CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2935 CGColor dimmed(alpha, 0, 0, 0, 0.5);
2936 [editor_ setBackgroundColor:dimmed];
2937 CGColorSpaceRelease(space);*/
2940 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
2941 [table_ setEnabled:YES];
2942 [delegate_ showKeyboard:NO];
2945 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
2946 NSString *text([field_ text]);
2947 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
2950 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
2951 if ([text length] != 1 || [text characterAtIndex:0] != '\n')
2954 [self searchPackages];
2955 [field_ resignFirstResponder];
2959 - (id) initWithFrame:(CGRect)frame {
2960 if ((self = [super initWithFrame:frame]) != nil) {
2961 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2963 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
2964 [table_ setDelegate:self];
2966 CGRect area = [self bounds];
2969 area.size.width -= 12;
2970 area.size.height = [UISearchField defaultHeight];
2972 field_ = [[UISearchField alloc] initWithFrame:area];
2974 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
2975 [field_ setFont:font];
2978 [field_ setPlaceholder:@"Package Names & Descriptions"];
2979 [field_ setPaddingTop:5];
2980 [field_ setDelegate:self];
2982 UITextTraits *traits = [field_ textTraits];
2983 [traits setEditingDelegate:self];
2984 [traits setReturnKeyType:6];
2986 accessory_ = [[UIView alloc] initWithFrame:CGRectMake(6, 6, area.size.width, area.size.height + 30)];
2987 [accessory_ addSubview:field_];
2989 [navbar_ setAccessoryView:accessory_];
2990 [self pushView:table_ withTitle:nil backButtonTitle:@"Search" rightButton:nil];
2992 /* XXX: for the love of god just fix this */
2993 [navbar_ removeFromSuperview];
2994 [self addSubview:navbar_];
2998 - (void) setPackages:(NSArray *)packages {
2999 [packages_ removeAllObjects];
3000 [packages_ addObjectsFromArray:packages];
3001 [packages_ sortUsingSelector:@selector(compareByName:)];
3003 Package *npackage = nil;
3004 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
3005 Package *package = [packages_ objectAtIndex:offset];
3006 if ([[package name] isEqualToString:package_])
3010 [self searchPackages];
3012 if (npackage != nil)
3013 [self resetPackage:npackage];
3014 else if (package_ != nil)
3020 - (void) setDelegate:(id)delegate {
3022 [view_ setDelegate:delegate];
3023 [super setDelegate:delegate];
3026 - (void) resetPackage:(Package *)package {
3027 [view_ setPackage:package];
3028 NSString *right = [package installed] == nil ? @"Install" : @"Uninstall";
3029 [navbar_ showButtonsWithLeftTitle:nil rightTitle:right];
3032 - (void) searchPackages {
3033 NSString *text([field_ text]);
3035 NSMutableArray *packages([NSMutableArray arrayWithCapacity:16]);
3037 for (size_t offset(0), count([packages_ count]); offset != count; ++offset) {
3038 Package *package = [packages_ objectAtIndex:offset];
3039 if ([package matches:text])
3040 [packages addObject:package];
3043 [table_ setPackages:packages];
3044 [[table_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3050 @interface Cydia : UIApplication <
3051 ConfirmationViewDelegate,
3052 ProgressViewDelegate,
3058 UITransitionView *transition_;
3059 UIButtonBar *buttonbar_;
3061 ConfirmationView *confirm_;
3063 Database *database_;
3064 ProgressView *progress_;
3067 UINavigationBar *navbar_;
3068 UIScroller *scroller_;
3069 UIWebView *webview_;
3071 UIProgressIndicator *indicator_;
3073 InstallView *install_;
3074 ChangesView *changes_;
3075 ManageView *manage_;
3076 SearchView *search_;
3080 UIKeyboard *keyboard_;
3084 - (void) reloadData:(BOOL)reset;
3095 - (void) progressViewIsComplete:(ProgressView *)progress;
3097 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
3098 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
3099 - (void) buttonBarItemTapped:(id)sender;
3101 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old;
3103 - (void) applicationWillSuspend;
3104 - (void) applicationDidFinishLaunching:(id)unused;
3107 @implementation Cydia
3110 NSMutableURLRequest *request = [NSMutableURLRequest
3112 cachePolicy:NSURLRequestReloadIgnoringCacheData
3113 timeoutInterval:30.0
3116 [request addValue:[NSString stringWithCString:Machine_] forHTTPHeaderField:@"X-Machine"];
3117 [request addValue:[NSString stringWithCString:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
3119 [webview_ loadRequest:request];
3120 [indicator_ startAnimation];
3123 - (void) reloadData:(BOOL)reset {
3124 [database_ reloadData];
3128 if (Packages_ == nil) {
3129 Packages_ = [[NSMutableDictionary alloc] initWithCapacity:count];
3130 [Metadata_ setObject:Packages_ forKey:@"Packages"];
3133 now_ = [NSDate date];
3135 NSMutableArray *packages = [NSMutableArray arrayWithCapacity:count];
3136 for (pkgCache::PkgIterator iterator = [database_ cache]->PkgBegin(); !iterator.end(); ++iterator)
3137 if (Package *package = [Package packageWithIterator:iterator database:database_])
3138 [packages addObject:package];
3140 [install_ setPackages:packages];
3141 [changes_ setPackages:packages];
3142 [manage_ setPackages:packages];
3143 [search_ setPackages:packages];
3146 if (size_t count = [changes_ count]) {
3147 NSString *badge([[NSNumber numberWithInt:count] stringValue]);
3148 [buttonbar_ setBadgeValue:badge forButton:3];
3149 [buttonbar_ setBadgeAnimated:YES forButton:3];
3150 [self setApplicationBadge:badge];
3152 [buttonbar_ setBadgeValue:nil forButton:3];
3153 [buttonbar_ setBadgeAnimated:NO forButton:3];
3154 [self removeApplicationBadge];
3157 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
3160 - (void) setPrompt {
3161 [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
3165 pkgProblemResolver *resolver = [database_ resolver];
3167 resolver->InstallProtect();
3168 if (!resolver->Resolve(true))
3173 [database_ prepare];
3174 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
3178 [database_ upgrade];
3183 [self reloadData:NO];
3189 [overlay_ removeFromSuperview];
3193 detachNewThreadSelector:@selector(perform)
3200 - (void) bootstrap_ {
3202 [database_ upgrade];
3203 [database_ prepare];
3204 [database_ perform];
3207 - (void) bootstrap {
3209 detachNewThreadSelector:@selector(bootstrap_)
3212 title:@"Bootstrap Install..."
3218 detachNewThreadSelector:@selector(update)
3221 title:@"Refreshing Sources..."
3225 - (void) progressViewIsComplete:(ProgressView *)progress {
3226 [self reloadData:YES];
3228 if (confirm_ != nil) {
3229 [underlay_ addSubview:overlay_];
3230 [confirm_ removeFromSuperview];
3236 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
3243 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3244 initWithTitle:@"About Cydia Packager"
3245 buttons:[NSArray arrayWithObjects:@"Close", nil]
3246 defaultButtonIndex:0
3252 @"Copyright (C) 2008\n"
3253 "Jay Freeman (saurik)\n"
3254 "saurik@saurik.com\n"
3255 "http://www.saurik.com/\n"
3258 "http://www.theokorigroup.com/\n"
3260 "College of Creative Studies,\n"
3261 "University of California,\n"
3263 "http://www.ccs.ucsb.edu/\n"
3266 "bad_, BHSPitMonkey, cash, Cobra,\n"
3267 "core, Corona, crashx, cromas,\n"
3268 "Darken, dtzWill, Erica, francis,\n"
3269 "Godores, jerry, Kingstone, lounger,\n"
3270 "mbranes, rockabilly, tman, Wbiggs"
3273 [sheet presentSheetFromButtonBar:buttonbar_];
3278 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3282 - (void) buttonBarItemTapped:(id)sender {
3285 switch ([sender tag]) {
3286 case 1: view = featured_; break;
3287 case 2: view = install_; break;
3288 case 3: view = changes_; break;
3289 case 4: view = manage_; break;
3290 case 5: view = search_; break;
3296 if ([view respondsToSelector:@selector(resetView)])
3297 [(id) view resetView];
3298 [transition_ transition:0 toView:view];
3301 - (void) view:(UIView *)view didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
3302 [scroller_ setContentSize:frame.size];
3303 [indicator_ stopAnimation];
3306 - (void) applicationWillSuspend {
3308 system("launchctl stop com.apple.SpringBoard");
3311 - (void) applicationDidFinishLaunching:(id)unused {
3312 _assert(pkgInitConfig(*_config));
3313 _assert(pkgInitSystem(*_config, _system));
3318 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
3319 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
3321 [window_ orderFront: self];
3322 [window_ makeKey: self];
3323 [window_ _setHidden: NO];
3325 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] delegate:self];
3326 [window_ setContentView:progress_];
3328 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
3329 [progress_ setContentView:underlay_];
3331 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
3334 [underlay_ addSubview:overlay_];
3336 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
3337 0, 0, screenrect.size.width, screenrect.size.height - 48
3340 [overlay_ addSubview:transition_];
3342 featured_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
3344 CGSize navsize = [UINavigationBar defaultSizeWithPrompt];
3345 CGRect navrect = {{0, 0}, navsize};
3347 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
3348 [featured_ addSubview:navbar_];
3350 [navbar_ setBarStyle:1];
3351 [navbar_ setDelegate:self];
3352 [navbar_ setPrompt:@"Welcome to Cydia Packager"];
3354 [navbar_ showButtonsWithLeftTitle:@"About" rightTitle:@"Reload"];
3356 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Featured"] autorelease];
3357 [navbar_ pushNavigationItem:navitem];
3359 struct CGRect subbounds = [featured_ bounds];
3360 subbounds.origin.y += navsize.height;
3361 subbounds.size.height -= navsize.height;
3363 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:subbounds] autorelease];
3364 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
3365 [featured_ addSubview:pinstripe];
3367 scroller_ = [[UIScroller alloc] initWithFrame:subbounds];
3368 [featured_ addSubview:scroller_];
3370 [scroller_ setScrollingEnabled:YES];
3371 [scroller_ setAdjustForContentSizeChange:YES];
3372 [scroller_ setClipsSubviews:YES];
3373 [scroller_ setAllowsRubberBanding:YES];
3374 [scroller_ setScrollDecelerationFactor:0.99];
3375 [scroller_ setDelegate:self];
3377 webview_ = [[UIWebView alloc] initWithFrame:[scroller_ bounds]];
3378 [scroller_ addSubview:webview_];
3380 [webview_ setTilingEnabled:YES];
3381 [webview_ setTileSize:CGSizeMake(screenrect.size.width, 500)];
3382 [webview_ setAutoresizes:YES];
3383 [webview_ setDelegate:self];
3385 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:2];
3386 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(87, 45, indsize.width, indsize.height)];
3387 [indicator_ setStyle:2];
3388 [featured_ addSubview:indicator_];
3390 NSArray *buttonitems = [NSArray arrayWithObjects:
3391 [NSDictionary dictionaryWithObjectsAndKeys:
3392 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3393 @"featured-up.png", kUIButtonBarButtonInfo,
3394 @"featured-dn.png", kUIButtonBarButtonSelectedInfo,
3395 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
3396 self, kUIButtonBarButtonTarget,
3397 @"Featured", kUIButtonBarButtonTitle,
3398 @"0", kUIButtonBarButtonType,
3401 [NSDictionary dictionaryWithObjectsAndKeys:
3402 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3403 @"install-up.png", kUIButtonBarButtonInfo,
3404 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
3405 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
3406 self, kUIButtonBarButtonTarget,
3407 @"Install", kUIButtonBarButtonTitle,
3408 @"0", kUIButtonBarButtonType,
3411 [NSDictionary dictionaryWithObjectsAndKeys:
3412 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3413 @"changes-up.png", kUIButtonBarButtonInfo,
3414 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
3415 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
3416 self, kUIButtonBarButtonTarget,
3417 @"Changes", kUIButtonBarButtonTitle,
3418 @"0", kUIButtonBarButtonType,
3421 [NSDictionary dictionaryWithObjectsAndKeys:
3422 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3423 @"manage-up.png", kUIButtonBarButtonInfo,
3424 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
3425 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
3426 self, kUIButtonBarButtonTarget,
3427 @"Uninstall", kUIButtonBarButtonTitle,
3428 @"0", kUIButtonBarButtonType,
3431 [NSDictionary dictionaryWithObjectsAndKeys:
3432 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3433 @"search-up.png", kUIButtonBarButtonInfo,
3434 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
3435 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
3436 self, kUIButtonBarButtonTarget,
3437 @"Search", kUIButtonBarButtonTitle,
3438 @"0", kUIButtonBarButtonType,
3442 buttonbar_ = [[UIButtonBar alloc]
3444 withFrame:CGRectMake(
3445 0, screenrect.size.height - 48,
3446 screenrect.size.width, 48
3448 withItemList:buttonitems
3451 [buttonbar_ setDelegate:self];
3452 [buttonbar_ setBarStyle:1];
3453 [buttonbar_ setButtonBarTrackingMode:2];
3455 int buttons[5] = {1, 2, 3, 4, 5};
3456 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
3457 [buttonbar_ showButtonGroup:0 withDuration:0];
3459 for (int i = 0; i != 5; ++i)
3460 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
3461 i * 64 + 2, 1, 60, 48
3464 [buttonbar_ showSelectionForButton:1];
3465 [transition_ transition:0 toView:featured_];
3467 [overlay_ addSubview:buttonbar_];
3469 [UIKeyboard initImplementationNow];
3471 CGRect edtrect = [overlay_ bounds];
3472 edtrect.origin.y += navsize.height;
3473 edtrect.size.height -= navsize.height;
3475 CGSize keysize = [UIKeyboard defaultSize];
3476 CGRect keyrect = {{0, [overlay_ bounds].size.height - keysize.height}, keysize};
3477 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
3479 database_ = [[Database alloc] init];
3480 [database_ setDelegate:progress_];
3482 install_ = [[InstallView alloc] initWithFrame:[transition_ bounds]];
3483 [install_ setDelegate:self];
3485 changes_ = [[ChangesView alloc] initWithFrame:[transition_ bounds]];
3486 [changes_ setDelegate:self];
3488 manage_ = [[ManageView alloc] initWithFrame:[transition_ bounds]];
3489 [manage_ setDelegate:self];
3491 search_ = [[SearchView alloc] initWithFrame:[transition_ bounds]];
3492 [search_ setDelegate:self];
3494 [self reloadData:NO];
3496 Package *package([database_ packageWithName:@"cydia"]);
3497 NSString *application = package == nil ? @"Cydia" : [NSString stringWithFormat:@"Cydia/%@", [package installed]];
3498 WebView *webview = [webview_ webView];
3499 [webview setApplicationNameForUserAgent:application];
3501 url_ = [NSURL URLWithString:@"http://cydia.saurik.com/"];
3504 [progress_ resetView];
3510 - (void) showKeyboard:(BOOL)show {
3512 [overlay_ addSubview:keyboard_];
3514 [keyboard_ removeFromSuperview];
3519 void AddPreferences(NSString *plist) {
3520 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
3522 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
3523 _assert(settings != NULL);
3524 NSMutableArray *items = [settings objectForKey:@"items"];
3528 for (size_t i(0); i != [items count]; ++i) {
3529 NSMutableDictionary *item([items objectAtIndex:i]);
3530 NSString *label = [item objectForKey:@"label"];
3531 if (label != nil && [label isEqualToString:@"Cydia"]) {
3538 for (size_t i(0); i != [items count]; ++i) {
3539 NSDictionary *item([items objectAtIndex:i]);
3540 NSString *label = [item objectForKey:@"label"];
3541 if (label != nil && [label isEqualToString:@"General"]) {
3542 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
3543 @"CydiaSettings", @"bundle",
3544 @"PSLinkCell", @"cell",
3545 [NSNumber numberWithBool:YES], @"hasIcon",
3546 [NSNumber numberWithBool:YES], @"isController",
3548 nil] atIndex:(i + 1)];
3554 _assert([settings writeToFile:plist atomically:YES] == YES);
3561 id Alloc_(id self, SEL selector) {
3562 id object = alloc_(self, selector);
3563 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
3567 int main(int argc, char *argv[]) {
3569 memset(nl, 0, sizeof(nl));
3570 nl[0].n_un.n_name = "_useMDNSResponder";
3571 nlist("/usr/lib/libc.dylib", nl);
3572 if (nl[0].n_type != N_UNDF)
3573 *(int *) nl[0].n_value = 0;
3575 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
3580 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
3581 alloc_ = alloc->method_imp;
3582 alloc->method_imp = (IMP) &Alloc_;*/
3584 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
3587 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
3588 char *machine = new char[size];
3589 sysctlbyname("hw.machine", machine, &size, NULL, 0);
3592 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
3593 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
3594 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
3595 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
3599 IOObjectRelease(service);
3602 AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
3603 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");
3605 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
3606 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
3608 Packages_ = [Metadata_ objectForKey:@"Packages"];
3610 UIApplicationMain(argc, argv, [Cydia class]);