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 {
589 [navbar_ showButtonsWithLeftTitle:nil rightTitle:nil];
593 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
595 CFLocaleRef locale = CFLocaleCopyCurrent();
596 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
597 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
599 [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", (NSString *) formatted]];
601 CFRelease(formatter);
602 CFRelease(formatted);
608 /* Confirmation View {{{ */
609 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
610 if ([packages count] == 0)
613 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 110, false);
614 [fields setObject:text forKey:key];
616 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
617 CGColor blue(space, 0, 0, 0.4, 1);
618 [text setTextColor:blue];
619 CGColorSpaceRelease(space);
622 @protocol ConfirmationViewDelegate
627 @interface ConfirmationView : UIView {
630 UITransitionView *transition_;
632 UINavigationBar *navbar_;
633 UIPreferencesTable *table_;
634 NSMutableDictionary *fields_;
635 UIAlertSheet *essential_;
641 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
642 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
643 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
645 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
646 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group;
647 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed;
648 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
649 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
651 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
655 @implementation ConfirmationView
658 [transition_ release];
663 if (essential_ != nil)
664 [essential_ release];
669 [transition_ transition:7 toView:nil];
673 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
674 if (from != nil && to == nil)
675 [self removeFromSuperview];
678 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
681 if (essential_ != nil)
682 [essential_ popupAlertAnimated:YES];
693 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
694 [essential_ dismiss];
698 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
702 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
704 case 0: return @"Statistics";
705 case 1: return @"Modifications";
707 default: _assert(false);
711 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
714 case 1: return [fields_ count];
716 default: _assert(false);
720 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
721 if (group != 1 || row == -1)
724 _assert(size_t(row) < [fields_ count]);
725 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
729 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
730 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
731 [cell setShowSelection:NO];
734 case 0: switch (row) {
736 [cell setTitle:@"Downloading"];
737 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
741 [cell setTitle:@"Resuming At"];
742 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
746 double size([database_ cache]->UsrSize());
749 [cell setTitle:@"Disk Freeing"];
750 [cell setValue:SizeString(-size)];
752 [cell setTitle:@"Disk Using"];
753 [cell setValue:SizeString(size)];
757 default: _assert(false);
761 _assert(size_t(row) < [fields_ count]);
762 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
763 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
766 default: _assert(false);
772 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
773 if ((self = [super initWithFrame:[view bounds]]) != nil) {
774 database_ = database;
775 delegate_ = delegate;
777 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
778 [self addSubview:transition_];
780 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
782 CGSize navsize = [UINavigationBar defaultSize];
783 CGRect navrect = {{0, 0}, navsize};
784 CGRect bounds = [overlay_ bounds];
786 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
787 [navbar_ setBarStyle:1];
788 [navbar_ setDelegate:self];
790 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
791 [navbar_ pushNavigationItem:navitem];
792 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
794 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
796 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
797 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
798 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
800 bool essential(false);
802 pkgCacheFile &cache([database_ cache]);
803 for (pkgCache::PkgIterator iterator = cache->PkgBegin(); !iterator.end(); ++iterator) {
804 NSString *name([NSString stringWithCString:iterator.Name()]);
805 if (cache[iterator].NewInstall())
806 [installing addObject:name];
807 else if (cache[iterator].Upgrade())
808 [upgrading addObject:name];
809 else if (cache[iterator].Delete()) {
810 [removing addObject:name];
811 if ((iterator->Flags & pkgCache::Flag::Essential) != 0)
819 essential_ = [[UIAlertSheet alloc]
820 initWithTitle:@"Unable to Comply"
821 buttons:[NSArray arrayWithObjects:@"Okay", nil]
827 [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."];
830 AddTextView(fields_, installing, @"Installing");
831 AddTextView(fields_, upgrading, @"Upgrading");
832 AddTextView(fields_, removing, @"Removing");
834 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
835 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
838 [table_ setReusesTableCells:YES];
839 [table_ setDataSource:self];
842 [overlay_ addSubview:navbar_];
843 [overlay_ addSubview:table_];
845 [view addSubview:self];
847 [transition_ setDelegate:self];
849 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
850 [transition_ transition:0 toView:blank];
851 [transition_ transition:3 toView:overlay_];
858 /* Package Class {{{ */
859 NSString *Scour(const char *field, const char *begin, const char *end) {
860 size_t i(0), l(strlen(field));
863 const char *name = begin + i;
864 const char *colon = name + l;
865 const char *value = colon + 1;
870 memcmp(name, field, l) == 0
872 while (value != end && value[0] == ' ')
874 const char *line = std::find(value, end, '\n');
875 while (line != value && line[-1] == ' ')
877 return [NSString stringWithCString:value length:(line - value)];
879 begin = std::find(begin, end, '\n');
887 @interface Package : NSObject {
888 pkgCache::PkgIterator iterator_;
890 pkgCache::VerIterator version_;
891 pkgCache::VerFileIterator file_;
894 NSString *installed_;
905 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file;
906 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
908 - (NSString *) section;
909 - (Address *) maintainer;
911 - (NSString *) description;
912 - (NSString *) index;
916 - (NSString *) latest;
917 - (NSString *) installed;
922 - (NSString *) tagline;
924 - (NSString *) bundle;
926 - (BOOL) matches:(NSString *)text;
928 - (NSComparisonResult) compareByName:(Package *)package;
929 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
930 - (NSComparisonResult) compareForChanges:(Package *)package;
936 @implementation Package
940 if (installed_ != nil)
941 [installed_ release];
954 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file {
955 if ((self = [super init]) != nil) {
956 iterator_ = iterator;
957 database_ = database;
962 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
964 const char *begin, *end;
965 parser->GetRec(begin, end);
967 latest_ = [[NSString stringWithCString:version_.VerStr()] retain];
968 installed_ = iterator_.CurrentVer().end() ? nil : [[NSString stringWithCString:iterator_.CurrentVer().VerStr()] retain];
970 id_ = [[[NSString stringWithCString:iterator_.Name()] lowercaseString] retain];
971 name_ = Scour("Name", begin, end);
973 name_ = [name_ retain];
974 tagline_ = [[NSString stringWithCString:parser->ShortDesc().c_str()] retain];
975 icon_ = Scour("Icon", begin, end);
977 icon_ = [icon_ retain];
978 bundle_ = Scour("Bundle", begin, end);
980 bundle_ = [bundle_ retain];
982 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
983 if (metadata == nil) {
984 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
988 [Packages_ setObject:metadata forKey:id_];
993 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
994 for (pkgCache::VerIterator version = iterator.VersionList(); !version.end(); ++version)
995 for (pkgCache::VerFileIterator file = version.FileList(); !file.end(); ++file)
996 return [[[Package alloc]
997 initWithIterator:iterator
1005 - (NSString *) section {
1006 return [[NSString stringWithCString:iterator_.Section()] stringByReplacingCharacter:'_' withCharacter:' '];
1009 - (Address *) maintainer {
1010 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1011 return [Address addressWithString:[NSString stringWithCString:parser->Maintainer().c_str()]];
1015 return version_->InstalledSize;
1018 - (NSString *) description {
1019 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1020 NSString *description([NSString stringWithCString:parser->LongDesc().c_str()]);
1022 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1023 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1024 if ([lines count] < 2)
1027 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1028 for (size_t i(1); i != [lines count]; ++i) {
1029 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1030 [trimmed addObject:trim];
1033 return [trimmed componentsJoinedByString:@"\n"];
1036 - (NSString *) index {
1037 return [[[self name] substringToIndex:1] uppercaseString];
1041 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1044 - (NSString *) latest {
1048 - (NSString *) installed {
1052 - (BOOL) upgradable {
1053 NSString *installed = [self installed];
1054 return installed != nil && [[self latest] compare:installed] != NSOrderedSame ? YES : NO;
1061 - (NSString *) name {
1062 return name_ == nil ? id_ : name_;
1065 - (NSString *) tagline {
1069 - (NSString *) icon {
1073 - (NSString *) bundle {
1077 - (BOOL) matches:(NSString *)text {
1083 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1084 if (range.location != NSNotFound)
1087 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1088 if (range.location != NSNotFound)
1094 - (NSComparisonResult) compareByName:(Package *)package {
1095 return [[self name] caseInsensitiveCompare:[package name]];
1098 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1099 NSComparisonResult result = [[self section] caseInsensitiveCompare:[package section]];
1100 if (result != NSOrderedSame)
1102 return [self compareByName:package];
1105 - (NSComparisonResult) compareForChanges:(Package *)package {
1106 BOOL lhs = [self upgradable];
1107 BOOL rhs = [package upgradable];
1110 return lhs ? NSOrderedAscending : NSOrderedDescending;
1112 switch ([[self seen] compare:[package seen]]) {
1113 case NSOrderedAscending:
1114 return NSOrderedDescending;
1117 case NSOrderedDescending:
1118 return NSOrderedAscending;
1124 return [self compareByName:package];
1128 pkgProblemResolver *resolver = [database_ resolver];
1129 resolver->Clear(iterator_);
1130 resolver->Protect(iterator_);
1131 [database_ cache]->MarkInstall(iterator_, false);
1135 pkgProblemResolver *resolver = [database_ resolver];
1136 resolver->Clear(iterator_);
1137 resolver->Protect(iterator_);
1138 resolver->Remove(iterator_);
1139 [database_ cache]->MarkDelete(iterator_, true);
1144 /* Section Class {{{ */
1145 @interface Section : NSObject {
1148 NSMutableArray *packages_;
1153 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1154 - (NSString *) name;
1156 - (NSArray *) packages;
1158 - (void) addPackage:(Package *)package;
1161 @implementation Section
1165 [packages_ release];
1169 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1170 if ((self = [super init]) != nil) {
1171 name_ = [name retain];
1173 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1177 - (NSString *) name {
1185 - (NSArray *) packages {
1190 return [packages_ count];
1193 - (void) addPackage:(Package *)package {
1194 [packages_ addObject:package];
1200 /* Package View {{{ */
1201 @protocol PackageViewDelegate
1202 - (void) performPackage:(Package *)package;
1205 @interface PackageView : UIView {
1206 UIPreferencesTable *table_;
1208 UITextView *description_;
1214 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
1215 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group;
1216 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed;
1217 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
1218 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
1220 - (BOOL) canSelectRow:(int)row;
1221 - (void) tableRowSelected:(NSNotification *)notification;
1223 - (Package *) package;
1225 - (id) initWithFrame:(struct CGRect)frame;
1226 - (void) setPackage:(Package *)package;
1227 - (void) setDelegate:(id)delegate;
1230 @implementation PackageView
1233 if (package_ != nil)
1235 if (description_ != nil)
1236 [description_ release];
1241 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
1245 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
1248 case 1: return @"Details";
1249 case 2: return @"Source";
1251 default: _assert(false);
1255 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
1256 if (group != 0 || row != 1)
1259 return [description_ visibleTextRect].size.height + TextViewOffset_;
1262 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
1268 default: _assert(false);
1272 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
1273 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
1274 [cell setShowSelection:NO];
1277 case 0: switch (row) {
1279 [cell setTitle:[package_ name]];
1280 [cell setValue:[package_ latest]];
1284 [cell addSubview:description_];
1287 default: _assert(false);
1290 case 1: switch (row) {
1292 [cell setTitle:@"Identifier"];
1293 [cell setValue:[package_ id]];
1297 [cell setTitle:@"Installed Version"];
1298 NSString *installed([package_ installed]);
1299 [cell setValue:(installed == nil ? @"n/a" : installed)];
1303 [cell setTitle:@"Section"];
1304 [cell setValue:[package_ section]];
1308 [cell setTitle:@"Expanded Size"];
1309 [cell setValue:SizeString([package_ size])];
1313 [cell setTitle:@"Maintainer"];
1314 [cell setValue:[[package_ maintainer] name]];
1315 [cell setShowDisclosure:YES];
1316 [cell setShowSelection:YES];
1319 default: _assert(false);
1322 case 2: switch (row) {
1325 default: _assert(false);
1331 - (BOOL) canSelectRow:(int)row {
1335 - (void) tableRowSelected:(NSNotification *)notification {
1336 printf("%d\n", [table_ selectedRow]);
1337 switch ([table_ selectedRow]) {
1339 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
1340 [[package_ maintainer] email],
1341 [[NSString stringWithFormat:@"regarding apt package \"%@\"", [package_ name]] stringByAddingPercentEscapes]
1347 - (Package *) package {
1351 - (id) initWithFrame:(struct CGRect)frame {
1352 if ((self = [super initWithFrame:frame]) != nil) {
1353 table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]];
1354 [self addSubview:table_];
1356 [table_ setDataSource:self];
1357 [table_ setDelegate:self];
1361 - (void) setPackage:(Package *)package {
1362 if (package_ != nil) {
1363 [package_ autorelease];
1367 if (description_ != nil) {
1368 [description_ release];
1372 if (package != nil) {
1373 package_ = [package retain];
1375 NSString *description([package description]);
1376 if (description == nil)
1377 description = [package tagline];
1378 description_ = [GetTextView(description, 12, true) retain];
1380 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1381 CGColor black(space, 0, 0, 0, 1);
1382 [description_ setTextColor:black];
1383 CGColorSpaceRelease(space);
1385 [table_ reloadData];
1389 - (void) setDelegate:(id)delegate {
1390 delegate_ = delegate;
1395 /* Package Cell {{{ */
1396 @interface PackageCell : UITableCell {
1398 UITextLabel *version_;
1399 UITextLabel *description_;
1405 - (PackageCell *) initWithVersioner:(SEL)versioner;
1406 - (void) setPackage:(Package *)package;
1408 - (void) _setSelected:(float)fraction;
1409 - (void) setSelected:(BOOL)selected;
1410 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
1411 - (void) _setSelectionFadeFraction:(float)fraction;
1415 @implementation PackageCell
1420 [description_ release];
1424 - (PackageCell *) initWithVersioner:(SEL)versioner {
1425 if ((self = [super init]) != nil) {
1426 versioner_ = versioner;
1428 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
1429 GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
1430 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
1432 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1434 CGColor clear(space, 0, 0, 0, 0);
1436 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 7, 250, 25)];
1437 [name_ setBackgroundColor:clear];
1438 [name_ setFont:bold];
1440 version_ = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(286, 7, 70, 25)];
1441 [version_ setBackgroundColor:clear];
1442 [version_ setFont:large];
1444 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(13, 35, 315, 20)];
1445 [description_ setBackgroundColor:clear];
1446 [description_ setFont:small];
1448 [self addSubview:name_];
1449 [self addSubview:version_];
1450 [self addSubview:description_];
1452 CGColorSpaceRelease(space);
1460 - (void) setPackage:(Package *)package {
1461 [name_ setText:[package name]];
1462 [version_ setText:[package latest]];
1463 [description_ setText:[package tagline]];
1466 - (void) _setSelected:(float)fraction {
1467 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1469 CGColor black(space,
1470 interpolate(0.0, 1.0, fraction),
1471 interpolate(0.0, 1.0, fraction),
1472 interpolate(0.0, 1.0, fraction),
1476 interpolate(0.2, 1.0, fraction),
1477 interpolate(0.2, 1.0, fraction),
1478 interpolate(1.0, 1.0, fraction),
1482 interpolate(0.4, 1.0, fraction),
1483 interpolate(0.4, 1.0, fraction),
1484 interpolate(0.4, 1.0, fraction),
1487 [name_ setColor:black];
1488 [version_ setColor:blue];
1489 [description_ setColor:gray];
1491 CGColorSpaceRelease(space);
1494 - (void) setSelected:(BOOL)selected {
1495 [self _setSelected:(selected ? 1.0 : 0.0)];
1496 [super setSelected:selected];
1499 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
1501 [self _setSelected:(selected ? 1.0 : 0.0)];
1502 [super setSelected:selected withFade:fade];
1505 - (void) _setSelectionFadeFraction:(float)fraction {
1506 [self _setSelected:fraction];
1507 [super _setSelectionFadeFraction:fraction];
1513 /* Database Implementation {{{ */
1514 @implementation Database
1521 - (void) _readStatus:(NSNumber *)fd {
1522 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1524 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1525 std::istream is(&ib);
1530 pcre *code = pcre_compile("^([^:]*):([^:]*):([^:]*):(.*)$", 0, &error, &offset, NULL);
1532 pcre_extra *study = NULL;
1534 pcre_fullinfo(code, study, PCRE_INFO_CAPTURECOUNT, &capture);
1535 int matches[(capture + 1) * 3];
1537 while (std::getline(is, line)) {
1538 const char *data(line.c_str());
1540 _assert(pcre_exec(code, study, data, line.size(), 0, 0, matches, sizeof(matches) / sizeof(matches[0])) >= 0);
1542 std::istringstream buffer(line.substr(matches[6], matches[7] - matches[6]));
1545 [delegate_ setPercent:(percent / 100)];
1547 NSString *string = [NSString stringWithCString:(data + matches[8]) length:(matches[9] - matches[8])];
1548 std::string type(line.substr(matches[2], matches[3] - matches[2]));
1550 if (type == "pmerror")
1551 [delegate_ setError:string];
1552 else if (type == "pmstatus")
1553 [delegate_ setTitle:string];
1554 else if (type == "pmconffile")
1556 else _assert(false);
1563 - (void) _readOutput:(NSNumber *)fd {
1564 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1566 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1567 std::istream is(&ib);
1570 while (std::getline(is, line))
1571 [delegate_ addOutput:[NSString stringWithCString:line.c_str()]];
1577 - (Package *) packageWithName:(NSString *)name {
1578 pkgCache::PkgIterator iterator(cache_->FindPkg([name cString]));
1579 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1582 - (Database *) init {
1583 if ((self = [super init]) != nil) {
1591 _assert(pipe(fds) != -1);
1595 detachNewThreadSelector:@selector(_readStatus:)
1597 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1600 _assert(pipe(fds) != -1);
1601 _assert(dup2(fds[1], 1) != -1);
1602 _assert(close(fds[1]) != -1);
1605 detachNewThreadSelector:@selector(_readOutput:)
1607 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1612 - (pkgCacheFile &) cache {
1616 - (pkgRecords *) records {
1620 - (pkgProblemResolver *) resolver {
1624 - (pkgAcquire &) fetcher {
1628 - (void) reloadData {
1636 _assert(cache_.Open(progress_, true));
1637 records_ = new pkgRecords(cache_);
1638 resolver_ = new pkgProblemResolver(cache_);
1639 fetcher_ = new pkgAcquire(&status_);
1644 pkgRecords records(cache_);
1646 lock_ = new FileFd();
1647 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1648 _assert(!_error->PendingError());
1651 _assert(list.ReadMainList());
1653 manager_ = (_system->CreatePM(cache_));
1654 _assert(manager_->GetArchives(fetcher_, &list, &records));
1655 _assert(!_error->PendingError());
1659 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue)
1663 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
1665 if (result == pkgPackageManager::Failed)
1667 if (_error->PendingError())
1669 if (result != pkgPackageManager::Completed)
1675 _assert(list.ReadMainList());
1678 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
1679 _assert(!_error->PendingError());
1681 pkgAcquire fetcher(&status_);
1682 _assert(list.GetIndexes(&fetcher));
1683 _assert(fetcher.Run(PulseInterval_) != pkgAcquire::Failed);
1685 bool failed = false;
1686 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
1687 if ((*item)->Status != pkgAcquire::Item::StatDone) {
1688 (*item)->Finished();
1692 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
1693 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
1694 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
1697 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
1701 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1702 _assert(pkgApplyStatus(cache_));
1704 if (cache_->BrokenCount() != 0) {
1705 _assert(pkgFixBroken(cache_));
1706 _assert(cache_->BrokenCount() == 0);
1707 _assert(pkgMinimizeUpgrade(cache_));
1710 _assert(pkgDistUpgrade(cache_));
1713 - (void) setDelegate:(id)delegate {
1714 delegate_ = delegate;
1715 status_.setDelegate(delegate);
1716 progress_.setDelegate(delegate);
1722 /* Progress Data {{{ */
1723 @interface ProgressData : NSObject {
1729 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
1736 @implementation ProgressData
1738 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
1739 if ((self = [super init]) != nil) {
1740 selector_ = selector;
1760 /* Progress View {{{ */
1761 @interface ProgressView : UIView <
1765 UIView *background_;
1766 UITransitionView *transition_;
1768 UINavigationBar *navbar_;
1769 UIProgressBar *progress_;
1770 UITextView *output_;
1771 UITextLabel *status_;
1777 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
1779 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate;
1780 - (void) setContentView:(UIView *)view;
1783 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
1785 - (void) _retachThread;
1786 - (void) _detachNewThreadData:(ProgressData *)data;
1787 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
1789 - (void) setError:(NSString *)error;
1790 - (void) _setError:(NSString *)error;
1792 - (void) setTitle:(NSString *)title;
1793 - (void) _setTitle:(NSString *)title;
1795 - (void) setPercent:(float)percent;
1796 - (void) _setPercent:(NSNumber *)percent;
1798 - (void) addOutput:(NSString *)output;
1799 - (void) _addOutput:(NSString *)output;
1802 @protocol ProgressViewDelegate
1803 - (void) progressViewIsComplete:(ProgressView *)sender;
1806 @implementation ProgressView
1810 if (background_ != nil)
1811 [background_ release];
1812 [transition_ release];
1815 [progress_ release];
1821 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
1822 if (bootstrap_ && from == overlay_ && to == view_)
1826 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate {
1827 if ((self = [super initWithFrame:frame]) != nil) {
1828 delegate_ = delegate;
1830 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1832 CGColor black(space, 0.0, 0.0, 0.0, 1.0);
1833 CGColor white(space, 1.0, 1.0, 1.0, 1.0);
1834 CGColor clear(space, 0.0, 0.0, 0.0, 0.0);
1836 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
1837 [transition_ setDelegate:self];
1839 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
1842 [overlay_ setBackgroundColor:black];
1844 background_ = [[UIView alloc] initWithFrame:[self bounds]];
1845 [background_ setBackgroundColor:black];
1846 [self addSubview:background_];
1849 [self addSubview:transition_];
1851 CGSize navsize = [UINavigationBar defaultSize];
1852 CGRect navrect = {{0, 0}, navsize};
1854 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
1855 [overlay_ addSubview:navbar_];
1857 [navbar_ setBarStyle:1];
1858 [navbar_ setDelegate:self];
1860 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
1861 [navbar_ pushNavigationItem:navitem];
1863 CGRect bounds = [overlay_ bounds];
1864 CGSize prgsize = [UIProgressBar defaultSize];
1867 (bounds.size.width - prgsize.width) / 2,
1868 bounds.size.height - prgsize.height - 20
1871 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
1872 [overlay_ addSubview:progress_];
1874 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
1876 bounds.size.height - prgsize.height - 50,
1877 bounds.size.width - 20,
1881 [status_ setColor:white];
1882 [status_ setBackgroundColor:clear];
1884 [status_ setCentersHorizontally:YES];
1885 //[status_ setFont:font];
1887 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
1889 navrect.size.height + 20,
1890 bounds.size.width - 20,
1891 bounds.size.height - navsize.height - 62 - navrect.size.height
1894 //[output_ setTextFont:@"Courier New"];
1895 [output_ setTextSize:12];
1897 [output_ setTextColor:white];
1898 [output_ setBackgroundColor:clear];
1900 [output_ setMarginTop:0];
1901 [output_ setAllowsRubberBanding:YES];
1903 [overlay_ addSubview:output_];
1904 [overlay_ addSubview:status_];
1906 [progress_ setStyle:0];
1908 CGColorSpaceRelease(space);
1912 - (void) setContentView:(UIView *)view {
1913 view_ = [view retain];
1916 - (void) resetView {
1917 [transition_ transition:6 toView:view_];
1920 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
1924 - (void) _retachThread {
1925 [delegate_ progressViewIsComplete:self];
1929 - (void) _detachNewThreadData:(ProgressData *)data {
1930 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1932 [[data target] performSelector:[data selector] withObject:[data object]];
1935 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
1940 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
1941 [navbar_ popNavigationItem];
1942 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:title] autorelease];
1943 [navbar_ pushNavigationItem:navitem];
1945 [status_ setText:nil];
1946 [output_ setText:@""];
1947 [progress_ setProgress:0];
1949 [transition_ transition:6 toView:overlay_];
1952 detachNewThreadSelector:@selector(_detachNewThreadData:)
1954 withObject:[[ProgressData alloc]
1955 initWithSelector:selector
1962 - (void) setError:(NSString *)error {
1964 performSelectorOnMainThread:@selector(_setError:)
1970 - (void) _setError:(NSString *)error {
1971 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
1972 initWithTitle:@"Package Error"
1973 buttons:[NSArray arrayWithObjects:@"Okay", nil]
1974 defaultButtonIndex:0
1979 [sheet setBodyText:error];
1980 [sheet popupAlertAnimated:YES];
1983 - (void) setTitle:(NSString *)title {
1985 performSelectorOnMainThread:@selector(_setTitle:)
1991 - (void) _setTitle:(NSString *)title {
1992 [status_ setText:[title stringByAppendingString:@"..."]];
1995 - (void) setPercent:(float)percent {
1997 performSelectorOnMainThread:@selector(_setPercent:)
1998 withObject:[NSNumber numberWithFloat:percent]
2003 - (void) _setPercent:(NSNumber *)percent {
2004 [progress_ setProgress:[percent floatValue]];
2007 - (void) addOutput:(NSString *)output {
2009 performSelectorOnMainThread:@selector(_addOutput:)
2015 - (void) _addOutput:(NSString *)output {
2016 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2017 CGSize size = [output_ contentSize];
2018 CGRect rect = {{0, size.height}, {size.width, 0}};
2019 [output_ scrollRectToVisible:rect animated:YES];
2025 /* Package Table {{{ */
2026 @protocol PackageTableDelegate
2027 - (void) packageTable:(id)table packageSelected:(Package *)package;
2030 @interface PackageTable : UIView {
2032 UISectionList *list_;
2036 NSMutableArray *sections_;
2041 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
2042 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
2043 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
2045 - (int) numberOfRowsInTable:(UITable *)table;
2046 - (float) table:(UITable *)table heightForRow:(int)row;
2047 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2048 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2049 - (void) tableRowSelected:(NSNotification *)notification;
2051 - (id) initWithFrame:(CGRect)frame versioner:(SEL)versioner;
2053 - (void) setDelegate:(id)delegate;
2054 - (void) setPackages:(NSArray *)packages;
2056 - (void) resetViewAnimated:(BOOL)animated;
2057 - (UITable *) table;
2060 @implementation PackageTable
2064 [sections_ release];
2065 if (packages_ != nil)
2066 [packages_ release];
2070 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2071 return [sections_ count];
2074 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2075 return [[sections_ objectAtIndex:section] name];
2078 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2079 return [[sections_ objectAtIndex:section] row];
2082 - (int) numberOfRowsInTable:(UITable *)table {
2083 return [packages_ count];
2086 - (float) table:(UITable *)table heightForRow:(int)row {
2090 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2092 reusing = [[[PackageCell alloc] initWithVersioner:versioner_] autorelease];
2093 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2097 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2101 - (void) tableRowSelected:(NSNotification *)notification {
2102 int row = [[notification object] selectedRow];
2103 [delegate_ packageTable:self packageSelected:(row == INT_MAX ? nil : [packages_ objectAtIndex:row])];
2106 - (id) initWithFrame:(CGRect)frame versioner:(SEL)versioner {
2107 if ((self = [super initWithFrame:frame]) != nil) {
2108 versioner_ = versioner;
2109 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
2111 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
2112 [list_ setDataSource:self];
2114 UITableColumn *column = [[[UITableColumn alloc]
2115 initWithTitle:@"Name"
2117 width:frame.size.width
2120 UITable *table = [list_ table];
2121 [table setSeparatorStyle:1];
2122 [table addTableColumn:column];
2123 [table setDelegate:self];
2124 [table setReusesTableCells:YES];
2126 [self addSubview:list_];
2130 - (void) setDelegate:(id)delegate {
2131 delegate_ = delegate;
2134 - (void) setPackages:(NSArray *)packages {
2135 if (packages_ != nil)
2136 [packages_ autorelease];
2137 _assert(packages != nil);
2138 packages_ = [packages retain];
2140 [sections_ removeAllObjects];
2142 Section *section = nil;
2144 for (size_t offset(0); offset != [packages_ count]; ++offset) {
2145 Package *package = [packages_ objectAtIndex:offset];
2146 NSString *name = [package index];
2148 if (section == nil || ![[section name] isEqual:name]) {
2149 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2150 [sections_ addObject:section];
2153 [section addPackage:package];
2159 - (void) resetViewAnimated:(BOOL)animated {
2160 [[list_ table] selectRow:-1 byExtendingSelection:NO withFade:animated];
2163 - (UITable *) table {
2164 return [list_ table];
2170 /* Section Cell {{{ */
2171 @interface SectionCell : UITableCell {
2173 UITextLabel *count_;
2179 - (void) setSection:(Section *)section;
2181 - (void) _setSelected:(float)fraction;
2182 - (void) setSelected:(BOOL)selected;
2183 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2184 - (void) _setSelectionFadeFraction:(float)fraction;
2188 @implementation SectionCell
2197 if ((self = [super init]) != nil) {
2198 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2199 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 12);
2201 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2202 CGColor clear(space, 0, 0, 0, 0);
2203 CGColor white(space, 1, 1, 1, 1);
2205 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(47, 9, 250, 25)];
2206 [name_ setBackgroundColor:clear];
2207 [name_ setFont:bold];
2209 count_ = [[UITextLabel alloc] initWithFrame:CGRectMake(11, 7, 29, 32)];
2210 [count_ setCentersHorizontally:YES];
2211 [count_ setBackgroundColor:clear];
2212 [count_ setFont:small];
2213 [count_ setColor:white];
2215 UIImageView *folder = [[[UIImageView alloc] initWithFrame:CGRectMake(8, 7, 32, 32)] autorelease];
2216 [folder setImage:[UIImage applicationImageNamed:@"folder.png"]];
2218 [self addSubview:folder];
2219 [self addSubview:name_];
2220 [self addSubview:count_];
2222 [self _setSelected:0];
2224 CGColorSpaceRelease(space);
2231 - (void) setSection:(Section *)section {
2232 if (section == nil) {
2233 [name_ setText:@"All Packages"];
2234 [count_ setText:nil];
2236 [name_ setText:[section name]];
2237 [count_ setText:[NSString stringWithFormat:@"%d", [section count]]];
2241 - (void) _setSelected:(float)fraction {
2242 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2244 CGColor black(space,
2245 interpolate(0.0, 1.0, fraction),
2246 interpolate(0.0, 1.0, fraction),
2247 interpolate(0.0, 1.0, fraction),
2250 [name_ setColor:black];
2252 CGColorSpaceRelease(space);
2255 - (void) setSelected:(BOOL)selected {
2256 [self _setSelected:(selected ? 1.0 : 0.0)];
2257 [super setSelected:selected];
2260 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2262 [self _setSelected:(selected ? 1.0 : 0.0)];
2263 [super setSelected:selected withFade:fade];
2266 - (void) _setSelectionFadeFraction:(float)fraction {
2267 [self _setSelected:fraction];
2268 [super _setSelectionFadeFraction:fraction];
2273 /* Install View {{{ */
2274 @interface InstallView : ResetView <
2275 PackageTableDelegate
2279 PackageTable *table_;
2283 NSMutableArray *packages_;
2288 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2290 - (int) numberOfRowsInTable:(UITable *)table;
2291 - (float) table:(UITable *)table heightForRow:(int)row;
2292 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2293 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2294 - (void) tableRowSelected:(NSNotification *)notification;
2296 - (void) packageTable:(id)table packageSelected:(Package *)package;
2298 - (id) initWithFrame:(CGRect)frame;
2299 - (void) setPackages:(NSArray *)packages;
2300 - (void) setDelegate:(id)delegate;
2303 @implementation InstallView
2306 [packages_ release];
2307 if (sections_ != nil)
2308 [sections_ release];
2315 if (section_ != nil)
2317 if (package_ != nil)
2322 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2324 [[view_ package] install];
2325 [delegate_ resolve];
2326 [delegate_ perform];
2330 - (int) numberOfRowsInTable:(UITable *)table {
2331 return [sections_ count] + 1;
2334 - (float) table:(UITable *)table heightForRow:(int)row {
2338 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2340 reusing = [[[SectionCell alloc] init] autorelease];
2342 [(SectionCell *)reusing setSection:nil];
2344 [(SectionCell *)reusing setSection:[sections_ objectAtIndex:(row - 1)]];
2348 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2352 - (void) tableRowSelected:(NSNotification *)notification {
2353 int row = [[notification object] selectedRow];
2355 if (row == INT_MAX) {
2362 _assert(section_ == nil);
2363 _assert(table_ == nil);
2371 name = @"All Packages";
2373 section = [sections_ objectAtIndex:(row - 1)];
2374 name = [section name];
2375 section_ = [name retain];
2378 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
2379 [table_ setDelegate:self];
2380 [table_ setPackages:(section == nil ? packages_ : [section packages])];
2382 [self pushView:table_ withTitle:name backButtonTitle:@"Packages" rightButton:nil];
2386 - (void) packageTable:(id)table packageSelected:(Package *)package {
2387 if (package == nil) {
2394 _assert(package_ == nil);
2395 _assert(view_ == nil);
2397 package_ = [[package name] retain];
2399 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2400 [view_ setDelegate:delegate_];
2402 [view_ setPackage:package];
2404 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:@"Install"];
2408 - (id) initWithFrame:(CGRect)frame {
2409 if ((self = [super initWithFrame:frame]) != nil) {
2410 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2412 list_ = [[UITable alloc] initWithFrame:[transition_ bounds]];
2413 [self pushView:list_ withTitle:@"Install" backButtonTitle:@"Sections" rightButton:nil];
2415 UITableColumn *column = [[[UITableColumn alloc]
2416 initWithTitle:@"Name"
2418 width:frame.size.width
2421 [list_ setDataSource:self];
2422 [list_ setSeparatorStyle:1];
2423 [list_ addTableColumn:column];
2424 [list_ setDelegate:self];
2425 [list_ setReusesTableCells:YES];
2427 [transition_ transition:0 toView:list_];
2431 - (void) setPackages:(NSArray *)packages {
2432 [packages_ removeAllObjects];
2434 for (size_t i(0); i != [packages count]; ++i) {
2435 Package *package([packages objectAtIndex:i]);
2436 if ([package installed] == nil)
2437 [packages_ addObject:package];
2440 [packages_ sortUsingSelector:@selector(compareBySectionAndName:)];
2441 NSMutableArray *sections = [NSMutableArray arrayWithCapacity:16];
2443 Section *nsection = nil;
2444 Package *npackage = nil;
2446 Section *section = nil;
2447 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
2448 Package *package = [packages_ objectAtIndex:offset];
2449 NSString *name = [package section];
2451 if (section == nil || ![[section name] isEqual:name]) {
2452 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2454 if ([name isEqualToString:section_])
2456 [sections addObject:section];
2459 if ([[package name] isEqualToString:package_])
2461 [section addPackage:package];
2464 if (sections_ != nil)
2465 [sections_ release];
2466 sections_ = [sections retain];
2468 [packages_ sortUsingSelector:@selector(compareByName:)];
2474 if (npackage != nil)
2475 [view_ setPackage:npackage];
2476 else if (package_ != nil)
2479 if (nsection != nil)
2480 [table_ setPackages:[nsection packages]];
2481 else if (section_ != nil)
2484 [self popViews:views];
2488 - (void) setDelegate:(id)delegate {
2490 [view_ setDelegate:delegate];
2491 [super setDelegate:delegate];
2496 /* Changes View {{{ */
2497 @interface ChangesView : ResetView <
2498 PackageTableDelegate
2500 UISectionList *list_;
2501 NSMutableArray *packages_;
2502 NSMutableArray *sections_;
2510 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2512 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
2513 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
2514 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
2516 - (int) numberOfRowsInTable:(UITable *)table;
2517 - (float) table:(UITable *)table heightForRow:(int)row;
2518 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2519 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2520 - (void) tableRowSelected:(NSNotification *)notification;
2522 - (id) initWithFrame:(CGRect)frame;
2523 - (void) setPackages:(NSArray *)packages;
2524 - (void) _resetView;
2527 - (void) setDelegate:(id)delegate;
2530 @implementation ChangesView
2534 [packages_ release];
2535 [sections_ release];
2538 if (package_ != nil)
2543 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2544 return [sections_ count];
2547 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2548 return [[sections_ objectAtIndex:section] name];
2551 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2552 return [[sections_ objectAtIndex:section] row];
2555 - (int) numberOfRowsInTable:(UITable *)table {
2556 return [packages_ count];
2559 - (float) table:(UITable *)table heightForRow:(int)row {
2563 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2565 reusing = [[[PackageCell alloc] initWithVersioner:NULL] autorelease];
2566 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2570 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2574 - (void) tableRowSelected:(NSNotification *)notification {
2575 int row = [[notification object] selectedRow];
2576 [self packageTable:self packageSelected:(row == INT_MAX ? nil : [packages_ objectAtIndex:row])];
2579 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2582 [[view_ package] install];
2583 [delegate_ resolve];
2584 [delegate_ perform];
2588 [delegate_ upgrade];
2593 - (void) packageTable:(id)table packageSelected:(Package *)package {
2594 if (package == nil) {
2601 _assert(package_ == nil);
2602 _assert(view_ == nil);
2604 package_ = [[package name] retain];
2606 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2607 [view_ setDelegate:delegate_];
2609 [view_ setPackage:package];
2611 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:(
2612 [package upgradable] ? @"Upgrade" : @"Install"
2617 - (id) initWithFrame:(CGRect)frame {
2618 if ((self = [super initWithFrame:frame]) != nil) {
2619 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2620 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
2622 list_ = [[UISectionList alloc] initWithFrame:[transition_ bounds] showSectionIndex:NO];
2623 [list_ setShouldHideHeaderInShortLists:NO];
2624 [list_ setDataSource:self];
2625 //[list_ setSectionListStyle:1];
2627 UITableColumn *column = [[[UITableColumn alloc]
2628 initWithTitle:@"Name"
2630 width:frame.size.width
2633 UITable *table = [list_ table];
2634 [table setSeparatorStyle:1];
2635 [table addTableColumn:column];
2636 [table setDelegate:self];
2637 [table setReusesTableCells:YES];
2639 [self pushView:list_ withTitle:@"Changes" backButtonTitle:nil rightButton:nil];
2643 - (void) setPackages:(NSArray *)packages {
2644 [packages_ removeAllObjects];
2645 for (size_t i(0); i != [packages count]; ++i) {
2646 Package *package([packages objectAtIndex:i]);
2647 if ([package installed] == nil || [package upgradable])
2648 [packages_ addObject:package];
2651 [packages_ sortUsingSelector:@selector(compareForChanges:)];
2653 [sections_ removeAllObjects];
2655 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades" row:0] autorelease];
2656 Section *section = nil;
2659 Package *npackage = nil;
2660 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
2661 Package *package = [packages_ objectAtIndex:offset];
2662 if ([[package name] isEqualToString:package_])
2665 if ([package upgradable])
2666 [upgradable addPackage:package];
2668 NSDate *seen = [package seen];
2670 CFLocaleRef locale = CFLocaleCopyCurrent();
2671 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
2672 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
2674 NSString *name = (NSString *) formatted;
2676 if (section == nil || ![[section name] isEqual:name]) {
2677 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2678 [sections_ addObject:section];
2681 [section addPackage:package];
2683 CFRelease(formatter);
2684 CFRelease(formatted);
2689 count_ = [[upgradable packages] count];
2691 [sections_ insertObject:upgradable atIndex:0];
2695 if (npackage != nil)
2696 [view_ setPackage:npackage];
2697 else if (package_ != nil)
2699 if ([views_ count] == 1)
2705 - (void) _resetView {
2706 [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]);