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 @protocol ProgressDelegate
182 - (void) setError:(NSString *)error;
183 - (void) setTitle:(NSString *)title;
184 - (void) setPercent:(float)percent;
185 - (void) addOutput:(NSString *)output;
188 NSString *SizeString(double size) {
190 while (size > 1024) {
195 static const char *powers_[] = {"B", "kB", "MB", "GB"};
197 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
200 static const float TextViewOffset_ = 22;
202 UITextView *GetTextView(NSString *value, float left, bool html) {
203 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
204 [text setEditable:NO];
205 [text setTextSize:16];
207 [text setHTML:value];
209 [text setText:value];
210 [text setEnabled:NO];
212 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
213 CGColor clear(space, 0, 0, 0, 0);
214 [text setBackgroundColor:clear];
215 CGColorSpaceRelease(space);
217 CGRect frame = [text frame];
218 [text setFrame:frame];
219 CGRect rect = [text visibleTextRect];
220 frame.size.height = rect.size.height;
221 [text setFrame:frame];
226 /* Status Delegation {{{ */
228 public pkgAcquireStatus
239 void setDelegate(id delegate) {
240 delegate_ = delegate;
243 virtual bool MediaChange(std::string media, std::string drive) {
247 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
250 virtual void Fetch(pkgAcquire::ItemDesc &item) {
251 [delegate_ setTitle:[NSString stringWithCString:("Downloading " + item.ShortDesc).c_str()]];
254 virtual void Done(pkgAcquire::ItemDesc &item) {
257 virtual void Fail(pkgAcquire::ItemDesc &item) {
259 item.Owner->Status == pkgAcquire::Item::StatIdle ||
260 item.Owner->Status == pkgAcquire::Item::StatDone
264 [delegate_ setError:[NSString stringWithCString:item.Owner->ErrorText.c_str()]];
267 virtual bool Pulse(pkgAcquire *Owner) {
268 bool value = pkgAcquireStatus::Pulse(Owner);
271 double(CurrentBytes + CurrentItems) /
272 double(TotalBytes + TotalItems)
275 [delegate_ setPercent:percent];
279 virtual void Start() {
282 virtual void Stop() {
286 /* Progress Delegation {{{ */
294 virtual void Update() {
295 [delegate_ setTitle:[NSString stringWithCString:Op.c_str()]];
296 [delegate_ setPercent:(Percent / 100)];
305 void setDelegate(id delegate) {
306 delegate_ = delegate;
309 virtual void Done() {
310 [delegate_ setPercent:1];
315 /* External Constants {{{ */
316 extern NSString *kUIButtonBarButtonAction;
317 extern NSString *kUIButtonBarButtonInfo;
318 extern NSString *kUIButtonBarButtonInfoOffset;
319 extern NSString *kUIButtonBarButtonSelectedInfo;
320 extern NSString *kUIButtonBarButtonStyle;
321 extern NSString *kUIButtonBarButtonTag;
322 extern NSString *kUIButtonBarButtonTarget;
323 extern NSString *kUIButtonBarButtonTitle;
324 extern NSString *kUIButtonBarButtonTitleVerticalHeight;
325 extern NSString *kUIButtonBarButtonTitleWidth;
326 extern NSString *kUIButtonBarButtonType;
328 /* Mime Addresses {{{ */
329 Pcre email_r("^\"?(.*)\"? <([^>]*)>$");
331 @interface Address : NSObject {
339 - (NSString *) email;
341 + (Address *) addressWithString:(NSString *)string;
342 - (Address *) initWithString:(NSString *)string;
345 @implementation Address
354 - (NSString *) name {
358 - (NSString *) email {
362 + (Address *) addressWithString:(NSString *)string {
363 return [[[Address alloc] initWithString:string] autorelease];
366 - (Address *) initWithString:(NSString *)string {
367 if ((self = [super init]) != nil) {
368 const char *data = [string UTF8String];
369 size_t size = [string length];
371 if (email_r(data, size)) {
372 name_ = [email_r[1] retain];
373 email_ = [email_r[2] retain];
375 name_ = [[NSString stringWithCString:data length:size] retain];
384 /* Right Alignment {{{ */
385 @interface UIRightTextLabel : UITextLabel {
386 float _savedRightEdgeX;
387 BOOL _sizedtofit_flag;
390 - (void) setFrame:(CGRect)frame;
391 - (void) setText:(NSString *)text;
392 - (void) realignText;
395 @implementation UIRightTextLabel
397 - (void) setFrame:(CGRect)frame {
398 [super setFrame:frame];
399 if (_sizedtofit_flag == NO) {
400 _savedRightEdgeX = frame.origin.x;
405 - (void) setText:(NSString *)text {
406 [super setText:text];
410 - (void) realignText {
411 CGRect oldFrame = [self frame];
413 _sizedtofit_flag = YES;
414 [self sizeToFit]; // shrink down size so I can right align it
416 CGRect newFrame = [self frame];
418 oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width;
419 oldFrame.size.width = newFrame.size.width;
420 [super setFrame:oldFrame];
421 _sizedtofit_flag = NO;
426 /* Linear Algebra {{{ */
427 inline float interpolate(float begin, float end, float fraction) {
428 return (end - begin) * fraction + begin;
434 /* Database Interface {{{ */
435 @interface Database : NSObject {
437 pkgRecords *records_;
438 pkgProblemResolver *resolver_;
439 pkgAcquire *fetcher_;
441 SPtr<pkgPackageManager> manager_;
451 - (void) _readStatus:(NSNumber *)fd;
452 - (void) _readOutput:(NSNumber *)fd;
454 - (Package *) packageWithName:(NSString *)name;
457 - (pkgCacheFile &) cache;
458 - (pkgRecords *) records;
459 - (pkgProblemResolver *) resolver;
460 - (pkgAcquire &) fetcher;
468 - (void) setDelegate:(id)delegate;
473 @interface ResetView : UIView {
474 UIPushButton *reload_;
475 NSMutableArray *views_;
476 UINavigationBar *navbar_;
477 UITransitionView *transition_;
484 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item;
486 - (id) initWithFrame:(CGRect)frame;
487 - (void) setDelegate:(id)delegate;
488 - (void) reloadPushed;
490 - (void) pushView:(UIView *)view withTitle:(NSString *)title backButtonTitle:(NSString *)back rightButton:(NSString *)right;
491 - (void) popViews:(unsigned)views;
497 @implementation ResetView
501 [transition_ release];
507 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item {
508 [views_ removeLastObject];
509 UIView *view([views_ lastObject]);
510 [view resetViewAnimated:!resetting_];
512 [transition_ transition:2 toView:view];
514 if ([views_ count] == 1)
518 - (id) initWithFrame:(CGRect)frame {
519 if ((self = [super initWithFrame:frame]) != nil) {
520 views_ = [[NSMutableArray arrayWithCapacity:4] retain];
522 struct CGRect bounds = [self bounds];
523 CGSize navsize = [UINavigationBar defaultSizeWithPrompt];
524 CGRect navrect = {{0, 0}, navsize};
526 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
527 [self addSubview:navbar_];
529 [navbar_ setBarStyle:1];
530 [navbar_ setDelegate:self];
532 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
533 bounds.origin.x, bounds.origin.y + navsize.height, bounds.size.width, bounds.size.height - navsize.height
536 //reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(284, 8, 29, 23)];
537 reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(282, 5, 29, 23)];
538 [reload_ setShowPressFeedback:YES];
539 [reload_ setImage:[UIImage applicationImageNamed:@"reload.png"]];
540 [reload_ addTarget:self action:@selector(reloadPushed) forEvents:1];
542 [navbar_ addSubview:reload_];
544 [self addSubview:transition_];
548 - (void) setDelegate:(id)delegate {
549 delegate_ = delegate;
552 - (void) reloadPushed {
556 - (void) pushView:(UIView *)view withTitle:(NSString *)title backButtonTitle:(NSString *)back rightButton:(NSString *)right {
557 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:title] autorelease];
558 [navbar_ pushNavigationItem:navitem];
559 [navitem setBackButtonTitle:back];
561 [navbar_ showButtonsWithLeftTitle:nil rightTitle:right];
563 [transition_ transition:([views_ count] == 0 ? 0 : 1) toView:view];
564 [views_ addObject:view];
567 - (void) popViews:(unsigned)views {
569 for (unsigned i(0); i != views; ++i)
570 [navbar_ popNavigationItem];
573 [transition_ transition:2 toView:[views_ lastObject]];
578 if ([[navbar_ navigationItems] count] == 1)
581 [navbar_ popNavigationItem];
582 while ([[navbar_ navigationItems] count] != 1);
585 [transition_ transition:0 toView:[views_ lastObject]];
588 - (void) _resetView {
592 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
594 CFLocaleRef locale = CFLocaleCopyCurrent();
595 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
596 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
598 [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", (NSString *) formatted]];
600 CFRelease(formatter);
601 CFRelease(formatted);
607 /* Confirmation View {{{ */
608 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
609 if ([packages count] == 0)
612 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 110, false);
613 [fields setObject:text forKey:key];
615 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
616 CGColor blue(space, 0, 0, 0.4, 1);
617 [text setTextColor:blue];
618 CGColorSpaceRelease(space);
621 @protocol ConfirmationViewDelegate
626 @interface ConfirmationView : UIView {
629 UITransitionView *transition_;
631 UINavigationBar *navbar_;
632 UIPreferencesTable *table_;
633 NSMutableDictionary *fields_;
634 UIAlertSheet *essential_;
640 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
641 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
642 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
644 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
645 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group;
646 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed;
647 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
648 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
650 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
654 @implementation ConfirmationView
657 [transition_ release];
662 if (essential_ != nil)
663 [essential_ release];
668 [transition_ transition:7 toView:nil];
672 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
673 if (from != nil && to == nil)
674 [self removeFromSuperview];
677 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
680 if (essential_ != nil)
681 [essential_ popupAlertAnimated:YES];
692 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
693 [essential_ dismiss];
697 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
701 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
703 case 0: return @"Statistics";
704 case 1: return @"Modifications";
706 default: _assert(false);
710 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
713 case 1: return [fields_ count];
715 default: _assert(false);
719 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
720 if (group != 1 || row == -1)
723 _assert(size_t(row) < [fields_ count]);
724 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
728 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
729 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
730 [cell setShowSelection:NO];
733 case 0: switch (row) {
735 [cell setTitle:@"Downloading"];
736 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
740 [cell setTitle:@"Resuming At"];
741 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
745 double size([database_ cache]->UsrSize());
748 [cell setTitle:@"Disk Freeing"];
749 [cell setValue:SizeString(-size)];
751 [cell setTitle:@"Disk Using"];
752 [cell setValue:SizeString(size)];
756 default: _assert(false);
760 _assert(size_t(row) < [fields_ count]);
761 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
762 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
765 default: _assert(false);
771 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
772 if ((self = [super initWithFrame:[view bounds]]) != nil) {
773 database_ = database;
774 delegate_ = delegate;
776 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
777 [self addSubview:transition_];
779 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
781 CGSize navsize = [UINavigationBar defaultSize];
782 CGRect navrect = {{0, 0}, navsize};
783 CGRect bounds = [overlay_ bounds];
785 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
786 [navbar_ setBarStyle:1];
787 [navbar_ setDelegate:self];
789 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
790 [navbar_ pushNavigationItem:navitem];
791 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
793 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
795 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
796 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
797 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
799 bool essential(false);
801 pkgCacheFile &cache([database_ cache]);
802 for (pkgCache::PkgIterator iterator = cache->PkgBegin(); !iterator.end(); ++iterator) {
803 NSString *name([NSString stringWithCString:iterator.Name()]);
804 if (cache[iterator].NewInstall())
805 [installing addObject:name];
806 else if (cache[iterator].Upgrade())
807 [upgrading addObject:name];
808 else if (cache[iterator].Delete()) {
809 [removing addObject:name];
810 if ((iterator->Flags & pkgCache::Flag::Essential) != 0)
818 essential_ = [[UIAlertSheet alloc]
819 initWithTitle:@"Unable to Comply"
820 buttons:[NSArray arrayWithObjects:@"Okay", nil]
826 [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."];
829 AddTextView(fields_, installing, @"Installing");
830 AddTextView(fields_, upgrading, @"Upgrading");
831 AddTextView(fields_, removing, @"Removing");
833 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
834 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
837 [table_ setReusesTableCells:YES];
838 [table_ setDataSource:self];
841 [overlay_ addSubview:navbar_];
842 [overlay_ addSubview:table_];
844 [view addSubview:self];
846 [transition_ setDelegate:self];
848 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
849 [transition_ transition:0 toView:blank];
850 [transition_ transition:3 toView:overlay_];
857 /* Package Class {{{ */
858 NSString *Scour(const char *field, const char *begin, const char *end) {
859 size_t i(0), l(strlen(field));
862 const char *name = begin + i;
863 const char *colon = name + l;
864 const char *value = colon + 1;
869 memcmp(name, field, l) == 0
871 while (value != end && value[0] == ' ')
873 const char *line = std::find(value, end, '\n');
874 while (line != value && line[-1] == ' ')
876 return [NSString stringWithCString:value length:(line - value)];
878 begin = std::find(begin, end, '\n');
886 @interface Package : NSObject {
887 pkgCache::PkgIterator iterator_;
889 pkgCache::VerIterator version_;
890 pkgCache::VerFileIterator file_;
893 NSString *installed_;
904 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file;
905 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
907 - (NSString *) section;
908 - (Address *) maintainer;
910 - (NSString *) description;
911 - (NSString *) index;
915 - (NSString *) latest;
916 - (NSString *) installed;
921 - (NSString *) tagline;
923 - (NSString *) bundle;
925 - (BOOL) matches:(NSString *)text;
927 - (NSComparisonResult) compareByName:(Package *)package;
928 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
929 - (NSComparisonResult) compareForChanges:(Package *)package;
935 @implementation Package
939 if (installed_ != nil)
940 [installed_ release];
953 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file {
954 if ((self = [super init]) != nil) {
955 iterator_ = iterator;
956 database_ = database;
961 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
963 const char *begin, *end;
964 parser->GetRec(begin, end);
966 latest_ = [[NSString stringWithCString:version_.VerStr()] retain];
967 installed_ = iterator_.CurrentVer().end() ? nil : [[NSString stringWithCString:iterator_.CurrentVer().VerStr()] retain];
969 id_ = [[[NSString stringWithCString:iterator_.Name()] lowercaseString] retain];
970 name_ = Scour("Name", begin, end);
972 name_ = [name_ retain];
973 tagline_ = [[NSString stringWithCString:parser->ShortDesc().c_str()] retain];
974 icon_ = Scour("Icon", begin, end);
976 icon_ = [icon_ retain];
977 bundle_ = Scour("Bundle", begin, end);
979 bundle_ = [bundle_ retain];
981 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
982 if (metadata == nil) {
983 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
987 [Packages_ setObject:metadata forKey:id_];
992 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
993 for (pkgCache::VerIterator version = iterator.VersionList(); !version.end(); ++version)
994 for (pkgCache::VerFileIterator file = version.FileList(); !file.end(); ++file)
995 return [[[Package alloc]
996 initWithIterator:iterator
1004 - (NSString *) section {
1005 return [[NSString stringWithCString:iterator_.Section()] stringByReplacingCharacter:'_' withCharacter:' '];
1008 - (Address *) maintainer {
1009 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1010 return [Address addressWithString:[NSString stringWithCString:parser->Maintainer().c_str()]];
1014 return version_->InstalledSize;
1017 - (NSString *) description {
1018 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1019 NSString *description([NSString stringWithCString:parser->LongDesc().c_str()]);
1021 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1022 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1023 if ([lines count] < 2)
1026 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1027 for (size_t i(1); i != [lines count]; ++i) {
1028 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1029 [trimmed addObject:trim];
1032 return [trimmed componentsJoinedByString:@"\n"];
1035 - (NSString *) index {
1036 return [[[self name] substringToIndex:1] uppercaseString];
1040 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1043 - (NSString *) latest {
1047 - (NSString *) installed {
1051 - (BOOL) upgradable {
1052 NSString *installed = [self installed];
1053 return installed != nil && [[self latest] compare:installed] != NSOrderedSame ? YES : NO;
1060 - (NSString *) name {
1061 return name_ == nil ? id_ : name_;
1064 - (NSString *) tagline {
1068 - (NSString *) icon {
1072 - (NSString *) bundle {
1076 - (BOOL) matches:(NSString *)text {
1082 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1083 if (range.location != NSNotFound)
1086 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1087 if (range.location != NSNotFound)
1093 - (NSComparisonResult) compareByName:(Package *)package {
1094 return [[self name] caseInsensitiveCompare:[package name]];
1097 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1098 NSComparisonResult result = [[self section] caseInsensitiveCompare:[package section]];
1099 if (result != NSOrderedSame)
1101 return [self compareByName:package];
1104 - (NSComparisonResult) compareForChanges:(Package *)package {
1105 BOOL lhs = [self upgradable];
1106 BOOL rhs = [package upgradable];
1109 return lhs ? NSOrderedAscending : NSOrderedDescending;
1111 switch ([[self seen] compare:[package seen]]) {
1112 case NSOrderedAscending:
1113 return NSOrderedDescending;
1116 case NSOrderedDescending:
1117 return NSOrderedAscending;
1123 return [self compareByName:package];
1127 pkgProblemResolver *resolver = [database_ resolver];
1128 resolver->Clear(iterator_);
1129 resolver->Protect(iterator_);
1130 [database_ cache]->MarkInstall(iterator_, false);
1134 pkgProblemResolver *resolver = [database_ resolver];
1135 resolver->Clear(iterator_);
1136 resolver->Protect(iterator_);
1137 resolver->Remove(iterator_);
1138 [database_ cache]->MarkDelete(iterator_, true);
1143 /* Section Class {{{ */
1144 @interface Section : NSObject {
1147 NSMutableArray *packages_;
1152 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1153 - (NSString *) name;
1155 - (NSArray *) packages;
1157 - (void) addPackage:(Package *)package;
1160 @implementation Section
1164 [packages_ release];
1168 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1169 if ((self = [super init]) != nil) {
1170 name_ = [name retain];
1172 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1176 - (NSString *) name {
1184 - (NSArray *) packages {
1189 return [packages_ count];
1192 - (void) addPackage:(Package *)package {
1193 [packages_ addObject:package];
1199 /* Package View {{{ */
1200 @protocol PackageViewDelegate
1201 - (void) performPackage:(Package *)package;
1204 @interface PackageView : UIView {
1205 UIPreferencesTable *table_;
1207 UITextView *description_;
1213 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
1214 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group;
1215 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed;
1216 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
1217 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
1219 - (BOOL) canSelectRow:(int)row;
1220 - (void) tableRowSelected:(NSNotification *)notification;
1222 - (Package *) package;
1224 - (id) initWithFrame:(struct CGRect)frame;
1225 - (void) setPackage:(Package *)package;
1226 - (void) setDelegate:(id)delegate;
1229 @implementation PackageView
1232 if (package_ != nil)
1234 if (description_ != nil)
1235 [description_ release];
1240 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
1244 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
1247 case 1: return @"Details";
1248 case 2: return @"Source";
1250 default: _assert(false);
1254 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
1255 if (group != 0 || row != 1)
1258 return [description_ visibleTextRect].size.height + TextViewOffset_;
1261 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
1267 default: _assert(false);
1271 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
1272 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
1273 [cell setShowSelection:NO];
1276 case 0: switch (row) {
1278 [cell setTitle:[package_ name]];
1279 [cell setValue:[package_ latest]];
1283 [cell addSubview:description_];
1286 default: _assert(false);
1289 case 1: switch (row) {
1291 [cell setTitle:@"Identifier"];
1292 [cell setValue:[package_ id]];
1296 [cell setTitle:@"Installed Version"];
1297 NSString *installed([package_ installed]);
1298 [cell setValue:(installed == nil ? @"n/a" : installed)];
1302 [cell setTitle:@"Section"];
1303 [cell setValue:[package_ section]];
1307 [cell setTitle:@"Expanded Size"];
1308 [cell setValue:SizeString([package_ size])];
1312 [cell setTitle:@"Maintainer"];
1313 [cell setValue:[[package_ maintainer] name]];
1314 [cell setShowDisclosure:YES];
1315 [cell setShowSelection:YES];
1318 default: _assert(false);
1321 case 2: switch (row) {
1324 default: _assert(false);
1330 - (BOOL) canSelectRow:(int)row {
1334 - (void) tableRowSelected:(NSNotification *)notification {
1335 printf("%d\n", [table_ selectedRow]);
1336 switch ([table_ selectedRow]) {
1338 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
1339 [[package_ maintainer] email],
1340 [[NSString stringWithFormat:@"regarding apt package \"%@\"", [package_ name]] stringByAddingPercentEscapes]
1346 - (Package *) package {
1350 - (id) initWithFrame:(struct CGRect)frame {
1351 if ((self = [super initWithFrame:frame]) != nil) {
1352 table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]];
1353 [self addSubview:table_];
1355 [table_ setDataSource:self];
1356 [table_ setDelegate:self];
1360 - (void) setPackage:(Package *)package {
1361 if (package_ != nil) {
1362 [package_ autorelease];
1366 if (description_ != nil) {
1367 [description_ release];
1371 if (package != nil) {
1372 package_ = [package retain];
1374 NSString *description([package description]);
1375 if (description == nil)
1376 description = [package tagline];
1377 description_ = [GetTextView(description, 12, true) retain];
1379 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1380 CGColor black(space, 0, 0, 0, 1);
1381 [description_ setTextColor:black];
1382 CGColorSpaceRelease(space);
1384 [table_ reloadData];
1388 - (void) setDelegate:(id)delegate {
1389 delegate_ = delegate;
1394 /* Package Cell {{{ */
1395 @interface PackageCell : UITableCell {
1397 UITextLabel *version_;
1398 UITextLabel *description_;
1404 - (PackageCell *) initWithVersioner:(SEL)versioner;
1405 - (void) setPackage:(Package *)package;
1407 - (void) _setSelected:(float)fraction;
1408 - (void) setSelected:(BOOL)selected;
1409 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
1410 - (void) _setSelectionFadeFraction:(float)fraction;
1414 @implementation PackageCell
1419 [description_ release];
1423 - (PackageCell *) initWithVersioner:(SEL)versioner {
1424 if ((self = [super init]) != nil) {
1425 versioner_ = versioner;
1427 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
1428 GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
1429 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
1431 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1433 CGColor clear(space, 0, 0, 0, 0);
1435 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 7, 250, 25)];
1436 [name_ setBackgroundColor:clear];
1437 [name_ setFont:bold];
1439 version_ = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(286, 7, 70, 25)];
1440 [version_ setBackgroundColor:clear];
1441 [version_ setFont:large];
1443 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(13, 35, 315, 20)];
1444 [description_ setBackgroundColor:clear];
1445 [description_ setFont:small];
1447 [self addSubview:name_];
1448 [self addSubview:version_];
1449 [self addSubview:description_];
1451 CGColorSpaceRelease(space);
1459 - (void) setPackage:(Package *)package {
1460 [name_ setText:[package name]];
1461 [version_ setText:[package latest]];
1462 [description_ setText:[package tagline]];
1465 - (void) _setSelected:(float)fraction {
1466 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1468 CGColor black(space,
1469 interpolate(0.0, 1.0, fraction),
1470 interpolate(0.0, 1.0, fraction),
1471 interpolate(0.0, 1.0, fraction),
1475 interpolate(0.2, 1.0, fraction),
1476 interpolate(0.2, 1.0, fraction),
1477 interpolate(1.0, 1.0, fraction),
1481 interpolate(0.4, 1.0, fraction),
1482 interpolate(0.4, 1.0, fraction),
1483 interpolate(0.4, 1.0, fraction),
1486 [name_ setColor:black];
1487 [version_ setColor:blue];
1488 [description_ setColor:gray];
1490 CGColorSpaceRelease(space);
1493 - (void) setSelected:(BOOL)selected {
1494 [self _setSelected:(selected ? 1.0 : 0.0)];
1495 [super setSelected:selected];
1498 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
1500 [self _setSelected:(selected ? 1.0 : 0.0)];
1501 [super setSelected:selected withFade:fade];
1504 - (void) _setSelectionFadeFraction:(float)fraction {
1505 [self _setSelected:fraction];
1506 [super _setSelectionFadeFraction:fraction];
1512 /* Database Implementation {{{ */
1513 @implementation Database
1520 - (void) _readStatus:(NSNumber *)fd {
1521 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1523 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1524 std::istream is(&ib);
1529 pcre *code = pcre_compile("^([^:]*):([^:]*):([^:]*):(.*)$", 0, &error, &offset, NULL);
1531 pcre_extra *study = NULL;
1533 pcre_fullinfo(code, study, PCRE_INFO_CAPTURECOUNT, &capture);
1534 int matches[(capture + 1) * 3];
1536 while (std::getline(is, line)) {
1537 const char *data(line.c_str());
1539 _assert(pcre_exec(code, study, data, line.size(), 0, 0, matches, sizeof(matches) / sizeof(matches[0])) >= 0);
1541 std::istringstream buffer(line.substr(matches[6], matches[7] - matches[6]));
1544 [delegate_ setPercent:(percent / 100)];
1546 NSString *string = [NSString stringWithCString:(data + matches[8]) length:(matches[9] - matches[8])];
1547 std::string type(line.substr(matches[2], matches[3] - matches[2]));
1549 if (type == "pmerror")
1550 [delegate_ setError:string];
1551 else if (type == "pmstatus")
1552 [delegate_ setTitle:string];
1553 else if (type == "pmconffile")
1555 else _assert(false);
1562 - (void) _readOutput:(NSNumber *)fd {
1563 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1565 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1566 std::istream is(&ib);
1569 while (std::getline(is, line))
1570 [delegate_ addOutput:[NSString stringWithCString:line.c_str()]];
1576 - (Package *) packageWithName:(NSString *)name {
1577 pkgCache::PkgIterator iterator(cache_->FindPkg([name cString]));
1578 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1581 - (Database *) init {
1582 if ((self = [super init]) != nil) {
1590 _assert(pipe(fds) != -1);
1594 detachNewThreadSelector:@selector(_readStatus:)
1596 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1599 _assert(pipe(fds) != -1);
1600 _assert(dup2(fds[1], 1) != -1);
1601 _assert(close(fds[1]) != -1);
1604 detachNewThreadSelector:@selector(_readOutput:)
1606 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1611 - (pkgCacheFile &) cache {
1615 - (pkgRecords *) records {
1619 - (pkgProblemResolver *) resolver {
1623 - (pkgAcquire &) fetcher {
1627 - (void) reloadData {
1635 _assert(cache_.Open(progress_, true));
1636 records_ = new pkgRecords(cache_);
1637 resolver_ = new pkgProblemResolver(cache_);
1638 fetcher_ = new pkgAcquire(&status_);
1643 pkgRecords records(cache_);
1645 lock_ = new FileFd();
1646 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1647 _assert(!_error->PendingError());
1650 _assert(list.ReadMainList());
1652 manager_ = (_system->CreatePM(cache_));
1653 _assert(manager_->GetArchives(fetcher_, &list, &records));
1654 _assert(!_error->PendingError());
1658 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue)
1662 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
1664 if (result == pkgPackageManager::Failed)
1666 if (_error->PendingError())
1668 if (result != pkgPackageManager::Completed)
1674 _assert(list.ReadMainList());
1677 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
1678 _assert(!_error->PendingError());
1680 pkgAcquire fetcher(&status_);
1681 _assert(list.GetIndexes(&fetcher));
1682 _assert(fetcher.Run(PulseInterval_) != pkgAcquire::Failed);
1684 bool failed = false;
1685 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
1686 if ((*item)->Status != pkgAcquire::Item::StatDone) {
1687 (*item)->Finished();
1691 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
1692 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
1693 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
1696 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
1700 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1701 _assert(pkgApplyStatus(cache_));
1703 if (cache_->BrokenCount() != 0) {
1704 _assert(pkgFixBroken(cache_));
1705 _assert(cache_->BrokenCount() == 0);
1706 _assert(pkgMinimizeUpgrade(cache_));
1709 _assert(pkgDistUpgrade(cache_));
1712 - (void) setDelegate:(id)delegate {
1713 delegate_ = delegate;
1714 status_.setDelegate(delegate);
1715 progress_.setDelegate(delegate);
1721 /* Progress Data {{{ */
1722 @interface ProgressData : NSObject {
1728 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
1735 @implementation ProgressData
1737 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
1738 if ((self = [super init]) != nil) {
1739 selector_ = selector;
1759 /* Progress View {{{ */
1760 @interface ProgressView : UIView <
1764 UIView *background_;
1765 UITransitionView *transition_;
1767 UINavigationBar *navbar_;
1768 UIProgressBar *progress_;
1769 UITextView *output_;
1770 UITextLabel *status_;
1776 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
1778 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate;
1779 - (void) setContentView:(UIView *)view;
1782 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
1784 - (void) _retachThread;
1785 - (void) _detachNewThreadData:(ProgressData *)data;
1786 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
1788 - (void) setError:(NSString *)error;
1789 - (void) _setError:(NSString *)error;
1791 - (void) setTitle:(NSString *)title;
1792 - (void) _setTitle:(NSString *)title;
1794 - (void) setPercent:(float)percent;
1795 - (void) _setPercent:(NSNumber *)percent;
1797 - (void) addOutput:(NSString *)output;
1798 - (void) _addOutput:(NSString *)output;
1801 @protocol ProgressViewDelegate
1802 - (void) progressViewIsComplete:(ProgressView *)sender;
1805 @implementation ProgressView
1809 if (background_ != nil)
1810 [background_ release];
1811 [transition_ release];
1814 [progress_ release];
1820 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
1821 if (bootstrap_ && from == overlay_ && to == view_)
1825 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate {
1826 if ((self = [super initWithFrame:frame]) != nil) {
1827 delegate_ = delegate;
1829 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1831 CGColor black(space, 0.0, 0.0, 0.0, 1.0);
1832 CGColor white(space, 1.0, 1.0, 1.0, 1.0);
1833 CGColor clear(space, 0.0, 0.0, 0.0, 0.0);
1835 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
1836 [transition_ setDelegate:self];
1838 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
1841 [overlay_ setBackgroundColor:black];
1843 background_ = [[UIView alloc] initWithFrame:[self bounds]];
1844 [background_ setBackgroundColor:black];
1845 [self addSubview:background_];
1848 [self addSubview:transition_];
1850 CGSize navsize = [UINavigationBar defaultSize];
1851 CGRect navrect = {{0, 0}, navsize};
1853 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
1854 [overlay_ addSubview:navbar_];
1856 [navbar_ setBarStyle:1];
1857 [navbar_ setDelegate:self];
1859 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
1860 [navbar_ pushNavigationItem:navitem];
1862 CGRect bounds = [overlay_ bounds];
1863 CGSize prgsize = [UIProgressBar defaultSize];
1866 (bounds.size.width - prgsize.width) / 2,
1867 bounds.size.height - prgsize.height - 20
1870 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
1871 [overlay_ addSubview:progress_];
1873 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
1875 bounds.size.height - prgsize.height - 50,
1876 bounds.size.width - 20,
1880 [status_ setColor:white];
1881 [status_ setBackgroundColor:clear];
1883 [status_ setCentersHorizontally:YES];
1884 //[status_ setFont:font];
1886 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
1888 navrect.size.height + 20,
1889 bounds.size.width - 20,
1890 bounds.size.height - navsize.height - 62 - navrect.size.height
1893 //[output_ setTextFont:@"Courier New"];
1894 [output_ setTextSize:12];
1896 [output_ setTextColor:white];
1897 [output_ setBackgroundColor:clear];
1899 [output_ setMarginTop:0];
1900 [output_ setAllowsRubberBanding:YES];
1902 [overlay_ addSubview:output_];
1903 [overlay_ addSubview:status_];
1905 [progress_ setStyle:0];
1907 CGColorSpaceRelease(space);
1911 - (void) setContentView:(UIView *)view {
1912 view_ = [view retain];
1915 - (void) resetView {
1916 [transition_ transition:6 toView:view_];
1919 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
1923 - (void) _retachThread {
1924 [delegate_ progressViewIsComplete:self];
1928 - (void) _detachNewThreadData:(ProgressData *)data {
1929 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1931 [[data target] performSelector:[data selector] withObject:[data object]];
1934 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
1939 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
1940 [navbar_ popNavigationItem];
1941 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:title] autorelease];
1942 [navbar_ pushNavigationItem:navitem];
1944 [status_ setText:nil];
1945 [output_ setText:@""];
1946 [progress_ setProgress:0];
1948 [transition_ transition:6 toView:overlay_];
1951 detachNewThreadSelector:@selector(_detachNewThreadData:)
1953 withObject:[[ProgressData alloc]
1954 initWithSelector:selector
1961 - (void) setError:(NSString *)error {
1963 performSelectorOnMainThread:@selector(_setError:)
1969 - (void) _setError:(NSString *)error {
1970 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
1971 initWithTitle:@"Package Error"
1972 buttons:[NSArray arrayWithObjects:@"Okay", nil]
1973 defaultButtonIndex:0
1978 [sheet setBodyText:error];
1979 [sheet popupAlertAnimated:YES];
1982 - (void) setTitle:(NSString *)title {
1984 performSelectorOnMainThread:@selector(_setTitle:)
1990 - (void) _setTitle:(NSString *)title {
1991 [status_ setText:[title stringByAppendingString:@"..."]];
1994 - (void) setPercent:(float)percent {
1996 performSelectorOnMainThread:@selector(_setPercent:)
1997 withObject:[NSNumber numberWithFloat:percent]
2002 - (void) _setPercent:(NSNumber *)percent {
2003 [progress_ setProgress:[percent floatValue]];
2006 - (void) addOutput:(NSString *)output {
2008 performSelectorOnMainThread:@selector(_addOutput:)
2014 - (void) _addOutput:(NSString *)output {
2015 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2016 CGSize size = [output_ contentSize];
2017 CGRect rect = {{0, size.height}, {size.width, 0}};
2018 [output_ scrollRectToVisible:rect animated:YES];
2024 /* Package Table {{{ */
2025 @protocol PackageTableDelegate
2026 - (void) packageTable:(id)table packageSelected:(Package *)package;
2029 @interface PackageTable : UIView {
2031 UISectionList *list_;
2035 NSMutableArray *sections_;
2040 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
2041 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
2042 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
2044 - (int) numberOfRowsInTable:(UITable *)table;
2045 - (float) table:(UITable *)table heightForRow:(int)row;
2046 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2047 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2048 - (void) tableRowSelected:(NSNotification *)notification;
2050 - (id) initWithFrame:(CGRect)frame versioner:(SEL)versioner;
2052 - (void) setDelegate:(id)delegate;
2053 - (void) setPackages:(NSArray *)packages;
2055 - (void) resetViewAnimated:(BOOL)animated;
2056 - (UITable *) table;
2059 @implementation PackageTable
2063 [sections_ release];
2064 if (packages_ != nil)
2065 [packages_ release];
2069 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2070 return [sections_ count];
2073 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2074 return [[sections_ objectAtIndex:section] name];
2077 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2078 return [[sections_ objectAtIndex:section] row];
2081 - (int) numberOfRowsInTable:(UITable *)table {
2082 return [packages_ count];
2085 - (float) table:(UITable *)table heightForRow:(int)row {
2089 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2091 reusing = [[[PackageCell alloc] initWithVersioner:versioner_] autorelease];
2092 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2096 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2100 - (void) tableRowSelected:(NSNotification *)notification {
2101 int row = [[notification object] selectedRow];
2102 [delegate_ packageTable:self packageSelected:(row == INT_MAX ? nil : [packages_ objectAtIndex:row])];
2105 - (id) initWithFrame:(CGRect)frame versioner:(SEL)versioner {
2106 if ((self = [super initWithFrame:frame]) != nil) {
2107 versioner_ = versioner;
2108 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
2110 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
2111 [list_ setDataSource:self];
2113 UITableColumn *column = [[[UITableColumn alloc]
2114 initWithTitle:@"Name"
2116 width:frame.size.width
2119 UITable *table = [list_ table];
2120 [table setSeparatorStyle:1];
2121 [table addTableColumn:column];
2122 [table setDelegate:self];
2123 [table setReusesTableCells:YES];
2125 [self addSubview:list_];
2129 - (void) setDelegate:(id)delegate {
2130 delegate_ = delegate;
2133 - (void) setPackages:(NSArray *)packages {
2134 if (packages_ != nil)
2135 [packages_ autorelease];
2136 _assert(packages != nil);
2137 packages_ = [packages retain];
2139 [sections_ removeAllObjects];
2141 Section *section = nil;
2143 for (size_t offset(0); offset != [packages_ count]; ++offset) {
2144 Package *package = [packages_ objectAtIndex:offset];
2145 NSString *name = [package index];
2147 if (section == nil || ![[section name] isEqual:name]) {
2148 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2149 [sections_ addObject:section];
2152 [section addPackage:package];
2158 - (void) resetViewAnimated:(BOOL)animated {
2159 [[list_ table] selectRow:-1 byExtendingSelection:NO withFade:animated];
2162 - (UITable *) table {
2163 return [list_ table];
2169 /* Section Cell {{{ */
2170 @interface SectionCell : UITableCell {
2172 UITextLabel *count_;
2178 - (void) setSection:(Section *)section;
2180 - (void) _setSelected:(float)fraction;
2181 - (void) setSelected:(BOOL)selected;
2182 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2183 - (void) _setSelectionFadeFraction:(float)fraction;
2187 @implementation SectionCell
2196 if ((self = [super init]) != nil) {
2197 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2198 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 12);
2200 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2201 CGColor clear(space, 0, 0, 0, 0);
2202 CGColor white(space, 1, 1, 1, 1);
2204 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(47, 9, 250, 25)];
2205 [name_ setBackgroundColor:clear];
2206 [name_ setFont:bold];
2208 count_ = [[UITextLabel alloc] initWithFrame:CGRectMake(11, 7, 29, 32)];
2209 [count_ setCentersHorizontally:YES];
2210 [count_ setBackgroundColor:clear];
2211 [count_ setFont:small];
2212 [count_ setColor:white];
2214 UIImageView *folder = [[[UIImageView alloc] initWithFrame:CGRectMake(8, 7, 32, 32)] autorelease];
2215 [folder setImage:[UIImage applicationImageNamed:@"folder.png"]];
2217 [self addSubview:folder];
2218 [self addSubview:name_];
2219 [self addSubview:count_];
2221 [self _setSelected:0];
2223 CGColorSpaceRelease(space);
2230 - (void) setSection:(Section *)section {
2231 if (section == nil) {
2232 [name_ setText:@"All Packages"];
2233 [count_ setText:nil];
2235 [name_ setText:[section name]];
2236 [count_ setText:[NSString stringWithFormat:@"%d", [section count]]];
2240 - (void) _setSelected:(float)fraction {
2241 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2243 CGColor black(space,
2244 interpolate(0.0, 1.0, fraction),
2245 interpolate(0.0, 1.0, fraction),
2246 interpolate(0.0, 1.0, fraction),
2249 [name_ setColor:black];
2251 CGColorSpaceRelease(space);
2254 - (void) setSelected:(BOOL)selected {
2255 [self _setSelected:(selected ? 1.0 : 0.0)];
2256 [super setSelected:selected];
2259 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2261 [self _setSelected:(selected ? 1.0 : 0.0)];
2262 [super setSelected:selected withFade:fade];
2265 - (void) _setSelectionFadeFraction:(float)fraction {
2266 [self _setSelected:fraction];
2267 [super _setSelectionFadeFraction:fraction];
2272 /* Install View {{{ */
2273 @interface InstallView : ResetView <
2274 PackageTableDelegate
2278 PackageTable *table_;
2282 NSMutableArray *packages_;
2287 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2289 - (int) numberOfRowsInTable:(UITable *)table;
2290 - (float) table:(UITable *)table heightForRow:(int)row;
2291 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2292 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2293 - (void) tableRowSelected:(NSNotification *)notification;
2295 - (void) packageTable:(id)table packageSelected:(Package *)package;
2297 - (id) initWithFrame:(CGRect)frame;
2298 - (void) setPackages:(NSArray *)packages;
2299 - (void) setDelegate:(id)delegate;
2302 @implementation InstallView
2305 [packages_ release];
2306 if (sections_ != nil)
2307 [sections_ release];
2314 if (section_ != nil)
2316 if (package_ != nil)
2321 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2323 [[view_ package] install];
2324 [delegate_ resolve];
2325 [delegate_ perform];
2329 - (int) numberOfRowsInTable:(UITable *)table {
2330 return [sections_ count] + 1;
2333 - (float) table:(UITable *)table heightForRow:(int)row {
2337 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2339 reusing = [[[SectionCell alloc] init] autorelease];
2341 [(SectionCell *)reusing setSection:nil];
2343 [(SectionCell *)reusing setSection:[sections_ objectAtIndex:(row - 1)]];
2347 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2351 - (void) tableRowSelected:(NSNotification *)notification {
2352 int row = [[notification object] selectedRow];
2354 if (row == INT_MAX) {
2361 _assert(section_ == nil);
2362 _assert(table_ == nil);
2370 name = @"All Packages";
2372 section = [sections_ objectAtIndex:(row - 1)];
2373 name = [section name];
2374 section_ = [name retain];
2377 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
2378 [table_ setDelegate:self];
2379 [table_ setPackages:(section == nil ? packages_ : [section packages])];
2381 [self pushView:table_ withTitle:name backButtonTitle:@"Packages" rightButton:nil];
2385 - (void) packageTable:(id)table packageSelected:(Package *)package {
2386 if (package == nil) {
2393 _assert(package_ == nil);
2394 _assert(view_ == nil);
2396 package_ = [[package name] retain];
2398 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2399 [view_ setDelegate:delegate_];
2401 [view_ setPackage:package];
2403 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:@"Install"];
2407 - (id) initWithFrame:(CGRect)frame {
2408 if ((self = [super initWithFrame:frame]) != nil) {
2409 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2411 list_ = [[UITable alloc] initWithFrame:[transition_ bounds]];
2412 [self pushView:list_ withTitle:@"Install" backButtonTitle:@"Sections" rightButton:nil];
2414 UITableColumn *column = [[[UITableColumn alloc]
2415 initWithTitle:@"Name"
2417 width:frame.size.width
2420 [list_ setDataSource:self];
2421 [list_ setSeparatorStyle:1];
2422 [list_ addTableColumn:column];
2423 [list_ setDelegate:self];
2424 [list_ setReusesTableCells:YES];
2426 [transition_ transition:0 toView:list_];
2430 - (void) setPackages:(NSArray *)packages {
2431 [packages_ removeAllObjects];
2433 for (size_t i(0); i != [packages count]; ++i) {
2434 Package *package([packages objectAtIndex:i]);
2435 if ([package installed] == nil)
2436 [packages_ addObject:package];
2439 [packages_ sortUsingSelector:@selector(compareBySectionAndName:)];
2440 NSMutableArray *sections = [NSMutableArray arrayWithCapacity:16];
2442 Section *nsection = nil;
2443 Package *npackage = nil;
2445 Section *section = nil;
2446 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
2447 Package *package = [packages_ objectAtIndex:offset];
2448 NSString *name = [package section];
2450 if (section == nil || ![[section name] isEqual:name]) {
2451 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2453 if ([name isEqualToString:section_])
2455 [sections addObject:section];
2458 if ([[package name] isEqualToString:package_])
2460 [section addPackage:package];
2463 if (sections_ != nil)
2464 [sections_ release];
2465 sections_ = [sections retain];
2467 [packages_ sortUsingSelector:@selector(compareByName:)];
2473 if (npackage != nil)
2474 [view_ setPackage:npackage];
2475 else if (package_ != nil)
2478 if (nsection != nil)
2479 [table_ setPackages:[nsection packages]];
2480 else if (section_ != nil)
2483 [self popViews:views];
2487 - (void) setDelegate:(id)delegate {
2489 [view_ setDelegate:delegate];
2490 [super setDelegate:delegate];
2495 /* Changes View {{{ */
2496 @interface ChangesView : ResetView <
2497 PackageTableDelegate
2499 UISectionList *list_;
2500 NSMutableArray *packages_;
2501 NSMutableArray *sections_;
2509 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2511 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
2512 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
2513 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
2515 - (int) numberOfRowsInTable:(UITable *)table;
2516 - (float) table:(UITable *)table heightForRow:(int)row;
2517 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2518 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2519 - (void) tableRowSelected:(NSNotification *)notification;
2521 - (id) initWithFrame:(CGRect)frame;
2522 - (void) setPackages:(NSArray *)packages;
2523 - (void) _resetView;
2526 - (void) setDelegate:(id)delegate;
2529 @implementation ChangesView
2533 [packages_ release];
2534 [sections_ release];
2537 if (package_ != nil)
2542 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2543 return [sections_ count];
2546 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2547 return [[sections_ objectAtIndex:section] name];
2550 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2551 return [[sections_ objectAtIndex:section] row];
2554 - (int) numberOfRowsInTable:(UITable *)table {
2555 return [packages_ count];
2558 - (float) table:(UITable *)table heightForRow:(int)row {
2562 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2564 reusing = [[[PackageCell alloc] initWithVersioner:NULL] autorelease];
2565 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2569 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2573 - (void) tableRowSelected:(NSNotification *)notification {
2574 int row = [[notification object] selectedRow];
2575 [self packageTable:self packageSelected:(row == INT_MAX ? nil : [packages_ objectAtIndex:row])];
2578 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2581 [[view_ package] install];
2582 [delegate_ resolve];
2583 [delegate_ perform];
2587 [delegate_ upgrade];
2592 - (void) packageTable:(id)table packageSelected:(Package *)package {
2593 if (package == nil) {
2600 _assert(package_ == nil);
2601 _assert(view_ == nil);
2603 package_ = [[package name] retain];
2605 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2606 [view_ setDelegate:delegate_];
2608 [view_ setPackage:package];
2610 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:(
2611 [package upgradable] ? @"Upgrade" : @"Install"
2616 - (id) initWithFrame:(CGRect)frame {
2617 if ((self = [super initWithFrame:frame]) != nil) {
2618 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2619 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
2621 list_ = [[UISectionList alloc] initWithFrame:[transition_ bounds] showSectionIndex:NO];
2622 [list_ setShouldHideHeaderInShortLists:NO];
2623 [list_ setDataSource:self];
2624 //[list_ setSectionListStyle:1];
2626 UITableColumn *column = [[[UITableColumn alloc]
2627 initWithTitle:@"Name"
2629 width:frame.size.width
2632 UITable *table = [list_ table];
2633 [table setSeparatorStyle:1];
2634 [table addTableColumn:column];
2635 [table setDelegate:self];
2636 [table setReusesTableCells:YES];
2638 [self pushView:list_ withTitle:@"Changes" backButtonTitle:nil rightButton:nil];
2642 - (void) setPackages:(NSArray *)packages {
2643 [packages_ removeAllObjects];
2644 for (size_t i(0); i != [packages count]; ++i) {
2645 Package *package([packages objectAtIndex:i]);
2646 if ([package installed] == nil || [package upgradable])
2647 [packages_ addObject:package];
2650 [packages_ sortUsingSelector:@selector(compareForChanges:)];
2652 [sections_ removeAllObjects];
2654 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades" row:0] autorelease];
2655 Section *section = nil;
2658 Package *npackage = nil;
2659 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
2660 Package *package = [packages_ objectAtIndex:offset];
2661 if ([[package name] isEqualToString:package_])
2664 if ([package upgradable])
2665 [upgradable addPackage:package];
2667 NSDate *seen = [package seen];
2669 CFLocaleRef locale = CFLocaleCopyCurrent();
2670 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
2671 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
2673 NSString *name = (NSString *) formatted;
2675 if (section == nil || ![[section name] isEqual:name]) {
2676 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2677 [sections_ addObject:section];
2680 [section addPackage:package];
2682 CFRelease(formatter);
2683 CFRelease(formatted);
2688 count_ = [[upgradable packages] count];
2690 [sections_ insertObject:upgradable atIndex:0];
2694 if (npackage != nil)
2695 [view_ setPackage:npackage];
2696 else if (package_ != nil)
2698 if ([views_ count] == 1)
2704 - (void) _resetView {
2705 [navbar_ showButtonsWithLeftTitle:(count_ == 0 ? nil : @"Upgrade All") rightTitle:nil];
2713 - (void) setDelegate:(id)delegate {
2715 [view_ setDelegate:delegate];
2716 [super setDelegate:delegate];
2721 /* Manage View {{{ */
2722 @interface ManageView : ResetView <
2723 PackageTableDelegate
2725 PackageTable *table_;
2732 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2734 - (void) packageTable:(id)table packageSelected:(Package *)package;
2736 - (id) initWithFrame:(CGRect)frame;
2737 - (void) setPackages:(NSArray *)packages;
2739 - (void) setDelegate:(id)delegate;
2742 @implementation ManageView
2748 if (package_ != nil)
2753 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2755 [[view_ package] remove];
2756 [delegate_ resolve];
2757 [delegate_ perform];
2761 - (void) packageTable:(id)table packageSelected:(Package *)package {
2762 if (package == nil) {
2769 _assert(package_ == nil);
2770 _assert(view_ == nil);
2772 package_ = [[package name] retain];
2774 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2775 [view_ setDelegate:delegate_];
2777 [view_ setPackage:package];
2779 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:@"Uninstall"];
2783 - (id) initWithFrame:(CGRect)frame {
2784 if ((self = [super initWithFrame:frame]) != nil) {
2785 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
2786 [table_ setDelegate:self];
2788 [self pushView:table_ withTitle:@"Uninstall" backButtonTitle:@"Packages" rightButton:nil];
2792 - (void) setPackages:(NSArray *)packages {
2793 NSMutableArray *local = [NSMutableArray arrayWithCapacity:16];
2794 for (size_t i(0); i != [packages count]; ++i) {
2795 Package *package([packages objectAtIndex:i]);
2796 if ([package installed] != nil)
2797 [local addObject:package];
2800 [local sortUsingSelector:@selector(compareByName:)];
2802 Package *npackage = nil;
2803 for (size_t offset = 0, count = [local count]; offset != count; ++offset) {
2804 Package *package = [local objectAtIndex:offset];
2805 if ([[package name] isEqualToString:package_])
2809 [table_ setPackages:local];
2811 if (npackage != nil)
2812 [view_ setPackage:npackage];
2813 else if (package_ != nil)
2819 - (void) setDelegate:(id)delegate {
2821 [view_ setDelegate:delegate];
2822 [super setDelegate:delegate];
2827 /* Search View {{{ */
2828 @protocol SearchViewDelegate
2829 - (void) showKeyboard:(BOOL)show;
2832 @interface SearchView : ResetView <
2833 PackageTableDelegate
2835 NSMutableArray *packages_;
2837 UISearchField *field_;
2838 PackageTable *table_;
2845 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2846 - (void) packageTable:(id)table packageSelected:(Package *)package;
2848 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field;
2849 - (void) textFieldDidResignFirstResponder:(UITextField *)field;
2851 - (void) keyboardInputChanged:(UIFieldEditor *)editor;
2852 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked;
2854 - (id) initWithFrame:(CGRect)frame;
2855 - (void) setPackages:(NSArray *)packages;
2857 - (void) setDelegate:(id)delegate;
2858 - (void) resetPackage:(Package *)package;
2859 - (void) searchPackages;
2863 @implementation SearchView
2866 [packages_ release];
2867 [accessory_ release];
2872 if (package_ != nil)
2877 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2879 Package *package = [view_ package];
2880 if ([package installed] == nil)
2884 [delegate_ resolve];
2885 [delegate_ perform];
2889 - (void) packageTable:(id)table packageSelected:(Package *)package {
2890 if (package == nil) {
2891 [navbar_ setAccessoryView:accessory_ animate:(resetting_ ? NO : YES) goingBack:YES];
2899 [navbar_ setAccessoryView:nil animate:YES goingBack:NO];
2901 _assert(package_ == nil);
2902 _assert(view_ == nil);
2904 package_ = [[package name] retain];
2906 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2907 [view_ setDelegate:delegate_];
2909 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:nil];
2910 [self resetPackage:package];
2914 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
2915 [delegate_ showKeyboard:YES];
2916 [table_ setEnabled:NO];
2918 /*CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2919 CGColor dimmed(alpha, 0, 0, 0, 0.5);
2920 [editor_ setBackgroundColor:dimmed];
2921 CGColorSpaceRelease(space);*/
2924 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
2925 [table_ setEnabled:YES];
2926 [delegate_ showKeyboard:NO];
2929 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
2930 NSString *text([field_ text]);
2931 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
2934 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
2935 if ([text length] != 1 || [text characterAtIndex:0] != '\n')
2938 [self searchPackages];
2939 [field_ resignFirstResponder];
2943 - (id) initWithFrame:(CGRect)frame {
2944 if ((self = [super initWithFrame:frame]) != nil) {
2945 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2947 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
2948 [table_ setDelegate:self];
2950 CGRect area = [self bounds];
2953 area.size.width -= 12;
2954 area.size.height = [UISearchField defaultHeight];
2956 field_ = [[UISearchField alloc] initWithFrame:area];
2958 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
2959 [field_ setFont:font];
2962 [field_ setPlaceholder:@"Package Names & Descriptions"];
2963 [field_ setPaddingTop:5];
2964 [field_ setDelegate:self];
2966 UITextTraits *traits = [field_ textTraits];
2967 [traits setEditingDelegate:self];
2968 [traits setReturnKeyType:6];
2970 accessory_ = [[UIView alloc] initWithFrame:CGRectMake(6, 6, area.size.width, area.size.height + 30)];
2971 [accessory_ addSubview:field_];
2973 [navbar_ setAccessoryView:accessory_];
2974 [self pushView:table_ withTitle:nil backButtonTitle:@"Search" rightButton:nil];
2976 /* XXX: for the love of god just fix this */
2977 [navbar_ removeFromSuperview];
2978 [self addSubview:navbar_];
2982 - (void) setPackages:(NSArray *)packages {
2983 [packages_ removeAllObjects];
2984 [packages_ addObjectsFromArray:packages];
2985 [packages_ sortUsingSelector:@selector(compareByName:)];
2987 Package *npackage = nil;
2988 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
2989 Package *package = [packages_ objectAtIndex:offset];
2990 if ([[package name] isEqualToString:package_])
2994 [self searchPackages];
2996 if (npackage != nil)
2997 [self resetPackage:npackage];
2998 else if (package_ != nil)
3004 - (void) setDelegate:(id)delegate {
3006 [view_ setDelegate:delegate];
3007 [super setDelegate:delegate];
3010 - (void) resetPackage:(Package *)package {
3011 [view_ setPackage:package];
3012 NSString *right = [package installed] == nil ? @"Install" : @"Uninstall";
3013 [navbar_ showButtonsWithLeftTitle:nil rightTitle:right];
3016 - (void) searchPackages {
3017 NSString *text([field_ text]);
3019 NSMutableArray *packages([NSMutableArray arrayWithCapacity:16]);
3021 for (size_t offset(0), count([packages_ count]); offset != count; ++offset) {
3022 Package *package = [packages_ objectAtIndex:offset];
3023 if ([package matches:text])
3024 [packages addObject:package];
3027 [table_ setPackages:packages];
3028 [[table_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3034 @interface Cydia : UIApplication <
3035 ConfirmationViewDelegate,
3036 ProgressViewDelegate,
3042 UITransitionView *transition_;
3043 UIButtonBar *buttonbar_;
3045 ConfirmationView *confirm_;
3047 Database *database_;
3048 ProgressView *progress_;
3051 UINavigationBar *navbar_;
3052 UIScroller *scroller_;
3053 UIWebView *webview_;
3055 UIProgressIndicator *indicator_;
3057 InstallView *install_;
3058 ChangesView *changes_;
3059 ManageView *manage_;
3060 SearchView *search_;
3064 UIKeyboard *keyboard_;
3068 - (void) reloadData:(BOOL)reset;
3079 - (void) progressViewIsComplete:(ProgressView *)progress;
3081 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
3082 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
3083 - (void) buttonBarItemTapped:(id)sender;
3085 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old;
3087 - (void) applicationWillSuspend;
3088 - (void) applicationDidFinishLaunching:(id)unused;
3091 @implementation Cydia
3094 NSMutableURLRequest *request = [NSMutableURLRequest
3096 cachePolicy:NSURLRequestReloadIgnoringCacheData
3097 timeoutInterval:30.0
3100 [request addValue:[NSString stringWithCString:Machine_] forHTTPHeaderField:@"X-Machine"];
3101 [request addValue:[NSString stringWithCString:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
3103 [webview_ loadRequest:request];
3104 [indicator_ startAnimation];
3107 - (void) reloadData:(BOOL)reset {
3108 [database_ reloadData];
3112 if (Packages_ == nil) {
3113 Packages_ = [[NSMutableDictionary alloc] initWithCapacity:count];
3114 [Metadata_ setObject:Packages_ forKey:@"Packages"];
3117 now_ = [NSDate date];
3119 NSMutableArray *packages = [NSMutableArray arrayWithCapacity:count];
3120 for (pkgCache::PkgIterator iterator = [database_ cache]->PkgBegin(); !iterator.end(); ++iterator)
3121 if (Package *package = [Package packageWithIterator:iterator database:database_])
3122 [packages addObject:package];
3124 [install_ setPackages:packages];
3125 [changes_ setPackages:packages];
3126 [manage_ setPackages:packages];
3127 [search_ setPackages:packages];
3130 if (size_t count = [changes_ count]) {
3131 NSString *badge([[NSNumber numberWithInt:count] stringValue]);
3132 [buttonbar_ setBadgeValue:badge forButton:3];
3133 [buttonbar_ setBadgeAnimated:YES forButton:3];
3134 [self setApplicationBadge:badge];
3136 [buttonbar_ setBadgeValue:nil forButton:3];
3137 [buttonbar_ setBadgeAnimated:NO forButton:3];
3138 [self removeApplicationBadge];
3141 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
3144 - (void) setPrompt {
3145 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
3147 CFLocaleRef locale = CFLocaleCopyCurrent();
3148 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
3149 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
3151 [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", (NSString *) formatted]];
3153 CFRelease(formatter);
3154 CFRelease(formatted);
3159 pkgProblemResolver *resolver = [database_ resolver];
3161 resolver->InstallProtect();
3162 if (!resolver->Resolve(true))
3167 [database_ prepare];
3168 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
3172 [database_ upgrade];
3177 [self reloadData:NO];
3183 [overlay_ removeFromSuperview];
3187 detachNewThreadSelector:@selector(perform)
3194 - (void) bootstrap_ {
3196 [database_ upgrade];
3197 [database_ prepare];
3198 [database_ perform];
3201 - (void) bootstrap {
3203 detachNewThreadSelector:@selector(bootstrap_)
3206 title:@"Bootstrap Install..."
3212 detachNewThreadSelector:@selector(update)
3215 title:@"Refreshing Sources..."
3219 - (void) progressViewIsComplete:(ProgressView *)progress {
3220 [self reloadData:YES];
3222 if (confirm_ != nil) {
3223 [underlay_ addSubview:overlay_];
3224 [confirm_ removeFromSuperview];
3230 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
3237 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3238 initWithTitle:@"About Cydia Packager"
3239 buttons:[NSArray arrayWithObjects:@"Close", nil]
3240 defaultButtonIndex:0
3246 @"Copyright (C) 2008\n"
3247 "Jay Freeman (saurik)\n"
3248 "saurik@saurik.com\n"
3249 "http://www.saurik.com/\n"
3252 "http://www.theokorigroup.com/\n"
3254 "College of Creative Studies,\n"
3255 "University of California,\n"
3257 "http://www.ccs.ucsb.edu/\n"
3260 "bad_, BHSPitMonkey, cash, Cobra,\n"
3261 "core, Corona, crashx, cromas,\n"
3262 "Darken, dtzWill, Erica, francis,\n"
3263 "Godores, jerry, Kingstone, lounger,\n"
3264 "mbranes, rockabilly, tman, Wbiggs"
3267 [sheet presentSheetFromButtonBar:buttonbar_];
3272 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3276 - (void) buttonBarItemTapped:(id)sender {
3279 switch ([sender tag]) {
3280 case 1: view = featured_; break;
3281 case 2: view = install_; break;
3282 case 3: view = changes_; break;
3283 case 4: view = manage_; break;
3284 case 5: view = search_; break;
3290 if ([view respondsToSelector:@selector(resetView)])
3291 [(id) view resetView];
3292 [transition_ transition:0 toView:view];
3295 - (void) view:(UIView *)view didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
3296 [scroller_ setContentSize:frame.size];
3297 [indicator_ stopAnimation];
3300 - (void) applicationWillSuspend {
3302 system("launchctl stop com.apple.SpringBoard");
3305 - (void) applicationDidFinishLaunching:(id)unused {
3306 _assert(pkgInitConfig(*_config));
3307 _assert(pkgInitSystem(*_config, _system));
3312 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
3313 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
3315 [window_ orderFront: self];
3316 [window_ makeKey: self];
3317 [window_ _setHidden: NO];
3319 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] delegate:self];
3320 [window_ setContentView:progress_];
3322 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
3323 [progress_ setContentView:underlay_];
3325 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
3328 [underlay_ addSubview:overlay_];
3330 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
3331 0, 0, screenrect.size.width, screenrect.size.height - 48
3334 [overlay_ addSubview:transition_];
3336 featured_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
3338 CGSize navsize = [UINavigationBar defaultSizeWithPrompt];
3339 CGRect navrect = {{0, 0}, navsize};
3341 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
3342 [featured_ addSubview:navbar_];
3344 [navbar_ setBarStyle:1];
3345 [navbar_ setDelegate:self];
3346 [navbar_ setPrompt:@"Welcome to Cydia Packager"];
3348 [navbar_ showButtonsWithLeftTitle:@"About" rightTitle:@"Reload"];
3350 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Featured"] autorelease];
3351 [navbar_ pushNavigationItem:navitem];
3353 struct CGRect subbounds = [featured_ bounds];
3354 subbounds.origin.y += navsize.height;
3355 subbounds.size.height -= navsize.height;
3357 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:subbounds] autorelease];
3358 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
3359 [featured_ addSubview:pinstripe];
3361 scroller_ = [[UIScroller alloc] initWithFrame:subbounds];
3362 [featured_ addSubview:scroller_];
3364 [scroller_ setScrollingEnabled:YES];
3365 [scroller_ setAdjustForContentSizeChange:YES];
3366 [scroller_ setClipsSubviews:YES];
3367 [scroller_ setAllowsRubberBanding:YES];
3368 [scroller_ setScrollDecelerationFactor:0.99];
3369 [scroller_ setDelegate:self];
3371 webview_ = [[UIWebView alloc] initWithFrame:[scroller_ bounds]];
3372 [scroller_ addSubview:webview_];
3374 [webview_ setTilingEnabled:YES];
3375 [webview_ setTileSize:CGSizeMake(screenrect.size.width, 500)];
3376 [webview_ setAutoresizes:YES];
3377 [webview_ setDelegate:self];
3379 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:2];
3380 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(87, 45, indsize.width, indsize.height)];
3381 [indicator_ setStyle:2];
3382 [featured_ addSubview:indicator_];
3384 NSArray *buttonitems = [NSArray arrayWithObjects:
3385 [NSDictionary dictionaryWithObjectsAndKeys:
3386 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3387 @"featured-up.png", kUIButtonBarButtonInfo,
3388 @"featured-dn.png", kUIButtonBarButtonSelectedInfo,
3389 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
3390 self, kUIButtonBarButtonTarget,
3391 @"Featured", kUIButtonBarButtonTitle,
3392 @"0", kUIButtonBarButtonType,
3395 [NSDictionary dictionaryWithObjectsAndKeys:
3396 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3397 @"install-up.png", kUIButtonBarButtonInfo,
3398 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
3399 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
3400 self, kUIButtonBarButtonTarget,
3401 @"Install", kUIButtonBarButtonTitle,
3402 @"0", kUIButtonBarButtonType,
3405 [NSDictionary dictionaryWithObjectsAndKeys:
3406 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3407 @"changes-up.png", kUIButtonBarButtonInfo,
3408 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
3409 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
3410 self, kUIButtonBarButtonTarget,
3411 @"Changes", kUIButtonBarButtonTitle,
3412 @"0", kUIButtonBarButtonType,
3415 [NSDictionary dictionaryWithObjectsAndKeys:
3416 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3417 @"manage-up.png", kUIButtonBarButtonInfo,
3418 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
3419 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
3420 self, kUIButtonBarButtonTarget,
3421 @"Uninstall", kUIButtonBarButtonTitle,
3422 @"0", kUIButtonBarButtonType,
3425 [NSDictionary dictionaryWithObjectsAndKeys:
3426 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3427 @"search-up.png", kUIButtonBarButtonInfo,
3428 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
3429 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
3430 self, kUIButtonBarButtonTarget,
3431 @"Search", kUIButtonBarButtonTitle,
3432 @"0", kUIButtonBarButtonType,
3436 buttonbar_ = [[UIButtonBar alloc]
3438 withFrame:CGRectMake(
3439 0, screenrect.size.height - 48,
3440 screenrect.size.width, 48
3442 withItemList:buttonitems
3445 [buttonbar_ setDelegate:self];
3446 [buttonbar_ setBarStyle:1];
3447 [buttonbar_ setButtonBarTrackingMode:2];
3449 int buttons[5] = {1, 2, 3, 4, 5};
3450 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
3451 [buttonbar_ showButtonGroup:0 withDuration:0];
3453 for (int i = 0; i != 5; ++i)
3454 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
3455 i * 64 + 2, 1, 60, 48
3458 [buttonbar_ showSelectionForButton:1];
3459 [transition_ transition:0 toView:featured_];
3461 [overlay_ addSubview:buttonbar_];
3463 [UIKeyboard initImplementationNow];
3465 CGRect edtrect = [overlay_ bounds];
3466 edtrect.origin.y += navsize.height;
3467 edtrect.size.height -= navsize.height;
3469 CGSize keysize = [UIKeyboard defaultSize];
3470 CGRect keyrect = {{0, [overlay_ bounds].size.height - keysize.height}, keysize};
3471 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
3473 database_ = [[Database alloc] init];
3474 [database_ setDelegate:progress_];
3476 install_ = [[InstallView alloc] initWithFrame:[transition_ bounds]];
3477 [install_ setDelegate:self];
3479 changes_ = [[ChangesView alloc] initWithFrame:[transition_ bounds]];
3480 [changes_ setDelegate:self];
3482 manage_ = [[ManageView alloc] initWithFrame:[transition_ bounds]];
3483 [manage_ setDelegate:self];
3485 search_ = [[SearchView alloc] initWithFrame:[transition_ bounds]];
3486 [search_ setDelegate:self];
3488 [self reloadData:NO];
3490 Package *package([database_ packageWithName:@"cydia"]);
3491 NSString *application = package == nil ? @"Cydia" : [NSString stringWithFormat:@"Cydia/%@", [package installed]];
3492 WebView *webview = [webview_ webView];
3493 [webview setApplicationNameForUserAgent:application];
3495 url_ = [NSURL URLWithString:@"http://cydia.saurik.com/"];
3498 [progress_ resetView];
3504 - (void) showKeyboard:(BOOL)show {
3506 [overlay_ addSubview:keyboard_];
3508 [keyboard_ removeFromSuperview];
3513 void AddPreferences(NSString *plist) {
3514 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
3516 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
3517 _assert(settings != NULL);
3518 NSMutableArray *items = [settings objectForKey:@"items"];
3522 for (size_t i(0); i != [items count]; ++i) {
3523 NSMutableDictionary *item([items objectAtIndex:i]);
3524 NSString *label = [item objectForKey:@"label"];
3525 if (label != nil && [label isEqualToString:@"Cydia"]) {
3532 for (size_t i(0); i != [items count]; ++i) {
3533 NSDictionary *item([items objectAtIndex:i]);
3534 NSString *label = [item objectForKey:@"label"];
3535 if (label != nil && [label isEqualToString:@"General"]) {
3536 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
3537 @"CydiaSettings", @"bundle",
3538 @"PSLinkCell", @"cell",
3539 [NSNumber numberWithBool:YES], @"hasIcon",
3540 [NSNumber numberWithBool:YES], @"isController",
3542 nil] atIndex:(i + 1)];
3548 _assert([settings writeToFile:plist atomically:YES] == YES);
3555 id Alloc_(id self, SEL selector) {
3556 id object = alloc_(self, selector);
3557 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
3561 int main(int argc, char *argv[]) {
3563 memset(nl, 0, sizeof(nl));
3564 nl[0].n_un.n_name = "_useMDNSResponder";
3565 nlist("/usr/lib/libc.dylib", nl);
3566 if (nl[0].n_type != N_UNDF)
3567 *(int *) nl[0].n_value = 0;
3569 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
3574 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
3575 alloc_ = alloc->method_imp;
3576 alloc->method_imp = (IMP) &Alloc_;*/
3578 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
3581 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
3582 char *machine = new char[size];
3583 sysctlbyname("hw.machine", machine, &size, NULL, 0);
3586 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
3587 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
3588 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
3589 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
3593 IOObjectRelease(service);
3596 AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
3597 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");
3599 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
3600 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
3602 Packages_ = [Metadata_ objectForKey:@"Packages"];
3604 UIApplicationMain(argc, argv, [Cydia class]);