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;
46 - (id) frameLoadDelegate;
47 - (void) setFrameLoadDelegate:(id)delegate;
50 @interface NSString (Cydia)
51 - (NSString *) stringByAddingPercentEscapes;
52 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
56 /* Reset View (UIView) {{{ */
57 @interface UIView (CYResetView)
58 - (void) resetViewAnimated:(BOOL)animated;
61 @implementation UIView (CYResetView)
63 - (void) resetViewAnimated:(BOOL)animated {
64 fprintf(stderr, "%s\n", self->isa->name);
70 /* Reset View (UITable) {{{ */
71 @interface UITable (CYResetView)
72 - (void) resetViewAnimated:(BOOL)animated;
75 @implementation UITable (CYResetView)
77 - (void) resetViewAnimated:(BOOL)animated {
78 [self selectRow:-1 byExtendingSelection:NO withFade:animated];
83 /* Reset View (UISectionList) {{{ */
84 @interface UISectionList (CYResetView)
85 - (void) resetViewAnimated:(BOOL)animated;
88 @implementation UISectionList (CYResetView)
90 - (void) resetViewAnimated:(BOOL)animated {
91 [[self table] resetViewAnimated:animated];
97 /* Perl-Compatible RegEx {{{ */
107 Pcre(const char *regex) :
112 code_ = pcre_compile(regex, 0, &error, &offset, NULL);
115 fprintf(stderr, "%d:%s\n", offset, error);
119 pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_);
120 matches_ = new int[(capture_ + 1) * 3];
128 NSString *operator [](size_t match) {
130 stringWithCString:(data_ + matches_[match * 2])
131 length:(matches_[match * 2 + 1] - matches_[match * 2])
135 bool operator ()(const char *data, size_t size) {
137 return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0;
141 /* CoreGraphicsServices Primitives {{{ */
147 CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
148 float color[] = {red, green, blue, alpha};
149 color_ = CGColorCreate(space, color);
153 CGColorRelease(color_);
156 operator CGColorRef() {
167 /* XXX: no GSFontRelease()? */
173 static const int PulseInterval_ = 50000;
174 const char *Machine_ = NULL;
175 const char *SerialNumber_ = NULL;
177 bool bootstrap_ = false;
179 static NSMutableDictionary *Metadata_;
180 static NSMutableDictionary *Packages_;
183 NSString *GetLastUpdate() {
184 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
187 return @"Never or Unknown";
189 CFLocaleRef locale = CFLocaleCopyCurrent();
190 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
191 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
193 CFRelease(formatter);
196 return [(NSString *) formatted autorelease];
199 @protocol ProgressDelegate
200 - (void) setError:(NSString *)error;
201 - (void) setTitle:(NSString *)title;
202 - (void) setPercent:(float)percent;
203 - (void) addOutput:(NSString *)output;
206 NSString *SizeString(double size) {
208 while (size > 1024) {
213 static const char *powers_[] = {"B", "kB", "MB", "GB"};
215 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
218 static const float TextViewOffset_ = 22;
220 UITextView *GetTextView(NSString *value, float left, bool html) {
221 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
222 [text setEditable:NO];
223 [text setTextSize:16];
225 [text setHTML:value];
227 [text setText:value];
228 [text setEnabled:NO];
230 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
231 CGColor clear(space, 0, 0, 0, 0);
232 [text setBackgroundColor:clear];
233 CGColorSpaceRelease(space);
235 CGRect frame = [text frame];
236 [text setFrame:frame];
237 CGRect rect = [text visibleTextRect];
238 frame.size.height = rect.size.height;
239 [text setFrame:frame];
244 /* Status Delegation {{{ */
246 public pkgAcquireStatus
257 void setDelegate(id delegate) {
258 delegate_ = delegate;
261 virtual bool MediaChange(std::string media, std::string drive) {
265 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
268 virtual void Fetch(pkgAcquire::ItemDesc &item) {
269 [delegate_ setTitle:[NSString stringWithCString:("Downloading " + item.ShortDesc).c_str()]];
272 virtual void Done(pkgAcquire::ItemDesc &item) {
275 virtual void Fail(pkgAcquire::ItemDesc &item) {
277 item.Owner->Status == pkgAcquire::Item::StatIdle ||
278 item.Owner->Status == pkgAcquire::Item::StatDone
282 [delegate_ setError:[NSString stringWithCString:item.Owner->ErrorText.c_str()]];
285 virtual bool Pulse(pkgAcquire *Owner) {
286 bool value = pkgAcquireStatus::Pulse(Owner);
289 double(CurrentBytes + CurrentItems) /
290 double(TotalBytes + TotalItems)
293 [delegate_ setPercent:percent];
297 virtual void Start() {
300 virtual void Stop() {
304 /* Progress Delegation {{{ */
312 virtual void Update() {
313 [delegate_ setTitle:[NSString stringWithCString:Op.c_str()]];
314 [delegate_ setPercent:(Percent / 100)];
323 void setDelegate(id delegate) {
324 delegate_ = delegate;
327 virtual void Done() {
328 [delegate_ setPercent:1];
333 /* External Constants {{{ */
334 extern NSString *kUIButtonBarButtonAction;
335 extern NSString *kUIButtonBarButtonInfo;
336 extern NSString *kUIButtonBarButtonInfoOffset;
337 extern NSString *kUIButtonBarButtonSelectedInfo;
338 extern NSString *kUIButtonBarButtonStyle;
339 extern NSString *kUIButtonBarButtonTag;
340 extern NSString *kUIButtonBarButtonTarget;
341 extern NSString *kUIButtonBarButtonTitle;
342 extern NSString *kUIButtonBarButtonTitleVerticalHeight;
343 extern NSString *kUIButtonBarButtonTitleWidth;
344 extern NSString *kUIButtonBarButtonType;
346 /* Mime Addresses {{{ */
347 Pcre email_r("^\"?(.*)\"? <([^>]*)>$");
349 @interface Address : NSObject {
357 - (NSString *) email;
359 + (Address *) addressWithString:(NSString *)string;
360 - (Address *) initWithString:(NSString *)string;
363 @implementation Address
372 - (NSString *) name {
376 - (NSString *) email {
380 + (Address *) addressWithString:(NSString *)string {
381 return [[[Address alloc] initWithString:string] autorelease];
384 - (Address *) initWithString:(NSString *)string {
385 if ((self = [super init]) != nil) {
386 const char *data = [string UTF8String];
387 size_t size = [string length];
389 if (email_r(data, size)) {
390 name_ = [email_r[1] retain];
391 email_ = [email_r[2] retain];
393 name_ = [[NSString stringWithCString:data length:size] retain];
402 /* Right Alignment {{{ */
403 @interface UIRightTextLabel : UITextLabel {
404 float _savedRightEdgeX;
405 BOOL _sizedtofit_flag;
408 - (void) setFrame:(CGRect)frame;
409 - (void) setText:(NSString *)text;
410 - (void) realignText;
413 @implementation UIRightTextLabel
415 - (void) setFrame:(CGRect)frame {
416 [super setFrame:frame];
417 if (_sizedtofit_flag == NO) {
418 _savedRightEdgeX = frame.origin.x;
423 - (void) setText:(NSString *)text {
424 [super setText:text];
428 - (void) realignText {
429 CGRect oldFrame = [self frame];
431 _sizedtofit_flag = YES;
432 [self sizeToFit]; // shrink down size so I can right align it
434 CGRect newFrame = [self frame];
436 oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width;
437 oldFrame.size.width = newFrame.size.width;
438 [super setFrame:oldFrame];
439 _sizedtofit_flag = NO;
444 /* Linear Algebra {{{ */
445 inline float interpolate(float begin, float end, float fraction) {
446 return (end - begin) * fraction + begin;
452 /* Database Interface {{{ */
453 @interface Database : NSObject {
455 pkgRecords *records_;
456 pkgProblemResolver *resolver_;
457 pkgAcquire *fetcher_;
459 SPtr<pkgPackageManager> manager_;
469 - (void) _readStatus:(NSNumber *)fd;
470 - (void) _readOutput:(NSNumber *)fd;
472 - (Package *) packageWithName:(NSString *)name;
475 - (pkgCacheFile &) cache;
476 - (pkgRecords *) records;
477 - (pkgProblemResolver *) resolver;
478 - (pkgAcquire &) fetcher;
486 - (void) setDelegate:(id)delegate;
491 @interface ResetView : UIView {
492 UIPushButton *configure_;
493 UIPushButton *reload_;
494 NSMutableArray *views_;
495 UINavigationBar *navbar_;
496 UITransitionView *transition_;
503 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item;
505 - (id) initWithFrame:(CGRect)frame;
506 - (void) setDelegate:(id)delegate;
508 - (void) configurePushed;
509 - (void) reloadPushed;
511 - (void) pushView:(UIView *)view withTitle:(NSString *)title backButtonTitle:(NSString *)back rightButton:(NSString *)right;
512 - (void) popViews:(unsigned)views;
513 - (void) resetView:(BOOL)clear;
518 @implementation ResetView
521 [configure_ release];
523 [transition_ release];
529 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item {
530 [views_ removeLastObject];
531 UIView *view([views_ lastObject]);
532 [view resetViewAnimated:!resetting_];
535 [transition_ transition:2 toView:view];
540 - (id) initWithFrame:(CGRect)frame {
541 if ((self = [super initWithFrame:frame]) != nil) {
542 views_ = [[NSMutableArray arrayWithCapacity:4] retain];
544 struct CGRect bounds = [self bounds];
545 CGSize navsize = [UINavigationBar defaultSizeWithPrompt];
546 CGRect navrect = {{0, 0}, navsize};
548 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
549 [self addSubview:navbar_];
551 [navbar_ setBarStyle:1];
552 [navbar_ setDelegate:self];
554 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
555 bounds.origin.x, bounds.origin.y + navsize.height, bounds.size.width, bounds.size.height - navsize.height
558 //configure_ = [[UIPushButton alloc] initWithFrame:CGRectMake(15, 9, 17, 18)];
559 configure_ = [[UIPushButton alloc] initWithFrame:CGRectMake(10, 9, 17, 18)];
560 [configure_ setShowPressFeedback:YES];
561 [configure_ setImage:[UIImage applicationImageNamed:@"configure.png"]];
562 [configure_ addTarget:self action:@selector(configurePushed) forEvents:1];
564 //reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(288, 5, 18, 22)];
565 reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(293, 5, 18, 22)];
566 [reload_ setShowPressFeedback:YES];
567 [reload_ setImage:[UIImage applicationImageNamed:@"reload.png"]];
568 [reload_ addTarget:self action:@selector(reloadPushed) forEvents:1];
570 [navbar_ addSubview:configure_];
571 [navbar_ addSubview:reload_];
573 [self addSubview:transition_];
577 - (void) setDelegate:(id)delegate {
578 delegate_ = delegate;
581 - (void) configurePushed {
584 - (void) reloadPushed {
588 - (void) pushView:(UIView *)view withTitle:(NSString *)title backButtonTitle:(NSString *)back rightButton:(NSString *)right {
589 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:title] autorelease];
590 [navbar_ pushNavigationItem:navitem];
591 [navitem setBackButtonTitle:back];
593 [navbar_ showButtonsWithLeftTitle:nil rightTitle:right];
595 [transition_ transition:([views_ count] == 0 ? 0 : 1) toView:view];
596 [views_ addObject:view];
599 - (void) popViews:(unsigned)views {
601 for (unsigned i(0); i != views; ++i)
602 [navbar_ popNavigationItem];
606 [transition_ transition:2 toView:[views_ lastObject]];
609 - (void) resetView:(BOOL)clear {
612 if ([views_ count] > 1) {
613 [navbar_ disableAnimation];
614 while ([views_ count] != (clear ? 1 : 2))
615 [navbar_ popNavigationItem];
616 [navbar_ enableAnimation];
618 [navbar_ popNavigationItem];
624 [transition_ transition:(clear ? 0 : 2) toView:[views_ lastObject]];
627 - (void) _resetView {
628 [navbar_ showButtonsWithLeftTitle:nil rightTitle:nil];
632 [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
637 /* Confirmation View {{{ */
638 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
639 if ([packages count] == 0)
642 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 110, false);
643 [fields setObject:text forKey:key];
645 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
646 CGColor blue(space, 0, 0, 0.4, 1);
647 [text setTextColor:blue];
648 CGColorSpaceRelease(space);
651 @protocol ConfirmationViewDelegate
656 @interface ConfirmationView : UIView {
659 UITransitionView *transition_;
661 UINavigationBar *navbar_;
662 UIPreferencesTable *table_;
663 NSMutableDictionary *fields_;
664 UIAlertSheet *essential_;
670 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
671 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
672 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
674 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
675 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group;
676 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed;
677 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
678 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
680 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
684 @implementation ConfirmationView
685 #include "internals.h"
688 [transition_ release];
693 if (essential_ != nil)
694 [essential_ release];
699 [transition_ transition:7 toView:nil];
703 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
704 if (from != nil && to == nil)
705 [self removeFromSuperview];
708 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
711 if (essential_ != nil)
712 [essential_ popupAlertAnimated:YES];
723 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
724 [essential_ dismiss];
728 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
732 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
734 case 0: return @"Statistics";
735 case 1: return @"Modifications";
737 default: _assert(false);
741 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
744 case 1: return [fields_ count];
746 default: _assert(false);
750 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
751 if (group != 1 || row == -1)
754 _assert(size_t(row) < [fields_ count]);
755 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
759 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
760 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
761 [cell setShowSelection:NO];
764 case 0: switch (row) {
766 [cell setTitle:@"Downloading"];
767 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
771 [cell setTitle:@"Resuming At"];
772 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
776 double size([database_ cache]->UsrSize());
779 [cell setTitle:@"Disk Freeing"];
780 [cell setValue:SizeString(-size)];
782 [cell setTitle:@"Disk Using"];
783 [cell setValue:SizeString(size)];
787 default: _assert(false);
791 _assert(size_t(row) < [fields_ count]);
792 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
793 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
796 default: _assert(false);
802 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
803 if ((self = [super initWithFrame:[view bounds]]) != nil) {
804 database_ = database;
805 delegate_ = delegate;
807 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
808 [self addSubview:transition_];
810 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
812 CGSize navsize = [UINavigationBar defaultSize];
813 CGRect navrect = {{0, 0}, navsize};
814 CGRect bounds = [overlay_ bounds];
816 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
817 [navbar_ setBarStyle:1];
818 [navbar_ setDelegate:self];
820 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
821 [navbar_ pushNavigationItem:navitem];
822 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
824 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
826 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
827 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
828 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
830 bool essential(false);
832 pkgCacheFile &cache([database_ cache]);
833 for (pkgCache::PkgIterator iterator = cache->PkgBegin(); !iterator.end(); ++iterator) {
834 NSString *name([NSString stringWithCString:iterator.Name()]);
835 if (cache[iterator].NewInstall())
836 [installing addObject:name];
837 else if (cache[iterator].Upgrade())
838 [upgrading addObject:name];
839 else if (cache[iterator].Delete()) {
840 [removing addObject:name];
841 if ((iterator->Flags & pkgCache::Flag::Essential) != 0)
849 essential_ = [[UIAlertSheet alloc]
850 initWithTitle:@"Unable to Comply"
851 buttons:[NSArray arrayWithObjects:@"Okay", nil]
857 [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."];
860 AddTextView(fields_, installing, @"Installing");
861 AddTextView(fields_, upgrading, @"Upgrading");
862 AddTextView(fields_, removing, @"Removing");
864 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
865 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
868 [table_ setReusesTableCells:YES];
869 [table_ setDataSource:self];
872 [overlay_ addSubview:navbar_];
873 [overlay_ addSubview:table_];
875 [view addSubview:self];
877 [transition_ setDelegate:self];
879 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
880 [transition_ transition:0 toView:blank];
881 [transition_ transition:3 toView:overlay_];
888 /* Package Class {{{ */
889 NSString *Scour(const char *field, const char *begin, const char *end) {
890 size_t i(0), l(strlen(field));
893 const char *name = begin + i;
894 const char *colon = name + l;
895 const char *value = colon + 1;
900 memcmp(name, field, l) == 0
902 while (value != end && value[0] == ' ')
904 const char *line = std::find(value, end, '\n');
905 while (line != value && line[-1] == ' ')
907 return [NSString stringWithCString:value length:(line - value)];
909 begin = std::find(begin, end, '\n');
917 @interface Package : NSObject {
918 pkgCache::PkgIterator iterator_;
920 pkgCache::VerIterator version_;
921 pkgCache::VerFileIterator file_;
924 NSString *installed_;
936 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file;
937 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
939 - (NSString *) section;
940 - (Address *) maintainer;
942 - (NSString *) description;
943 - (NSString *) index;
947 - (NSString *) latest;
948 - (NSString *) installed;
953 - (NSString *) tagline;
955 - (NSString *) bundle;
956 - (NSString *) website;
958 - (BOOL) matches:(NSString *)text;
960 - (NSComparisonResult) compareByName:(Package *)package;
961 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
962 - (NSComparisonResult) compareForChanges:(Package *)package;
968 @implementation Package
972 if (installed_ != nil)
973 [installed_ release];
986 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file {
987 if ((self = [super init]) != nil) {
988 iterator_ = iterator;
989 database_ = database;
994 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
996 const char *begin, *end;
997 parser->GetRec(begin, end);
999 latest_ = [[NSString stringWithCString:version_.VerStr()] retain];
1000 installed_ = iterator_.CurrentVer().end() ? nil : [[NSString stringWithCString:iterator_.CurrentVer().VerStr()] retain];
1002 id_ = [[[NSString stringWithCString:iterator_.Name()] lowercaseString] retain];
1003 name_ = Scour("Name", begin, end);
1005 name_ = [name_ retain];
1006 tagline_ = [[NSString stringWithCString:parser->ShortDesc().c_str()] retain];
1007 icon_ = Scour("Icon", begin, end);
1009 icon_ = [icon_ retain];
1010 bundle_ = Scour("Bundle", begin, end);
1012 bundle_ = [bundle_ retain];
1013 website_ = Scour("Website", begin, end);
1014 if (website_ != nil)
1015 website_ = [website_ retain];
1017 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
1018 if (metadata == nil) {
1019 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
1023 [Packages_ setObject:metadata forKey:id_];
1028 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1029 for (pkgCache::VerIterator version = iterator.VersionList(); !version.end(); ++version)
1030 for (pkgCache::VerFileIterator file = version.FileList(); !file.end(); ++file)
1031 return [[[Package alloc]
1032 initWithIterator:iterator
1040 - (NSString *) section {
1041 return [[NSString stringWithCString:iterator_.Section()] stringByReplacingCharacter:'_' withCharacter:' '];
1044 - (Address *) maintainer {
1045 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1046 return [Address addressWithString:[NSString stringWithCString:parser->Maintainer().c_str()]];
1050 return version_->InstalledSize;
1053 - (NSString *) description {
1054 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1055 NSString *description([NSString stringWithCString:parser->LongDesc().c_str()]);
1057 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1058 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1059 if ([lines count] < 2)
1062 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1063 for (size_t i(1); i != [lines count]; ++i) {
1064 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1065 [trimmed addObject:trim];
1068 return [trimmed componentsJoinedByString:@"\n"];
1071 - (NSString *) index {
1072 return [[[self name] substringToIndex:1] uppercaseString];
1076 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1079 - (NSString *) latest {
1083 - (NSString *) installed {
1087 - (BOOL) upgradable {
1088 NSString *installed = [self installed];
1089 return installed != nil && [[self latest] compare:installed] != NSOrderedSame ? YES : NO;
1096 - (NSString *) name {
1097 return name_ == nil ? id_ : name_;
1100 - (NSString *) tagline {
1104 - (NSString *) icon {
1108 - (NSString *) bundle {
1112 - (NSString *) website {
1116 - (BOOL) matches:(NSString *)text {
1122 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1123 if (range.location != NSNotFound)
1126 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1127 if (range.location != NSNotFound)
1133 - (NSComparisonResult) compareByName:(Package *)package {
1134 return [[self name] caseInsensitiveCompare:[package name]];
1137 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1138 NSComparisonResult result = [[self section] caseInsensitiveCompare:[package section]];
1139 if (result != NSOrderedSame)
1141 return [self compareByName:package];
1144 - (NSComparisonResult) compareForChanges:(Package *)package {
1145 BOOL lhs = [self upgradable];
1146 BOOL rhs = [package upgradable];
1149 return lhs ? NSOrderedAscending : NSOrderedDescending;
1151 switch ([[self seen] compare:[package seen]]) {
1152 case NSOrderedAscending:
1153 return NSOrderedDescending;
1156 case NSOrderedDescending:
1157 return NSOrderedAscending;
1163 return [self compareByName:package];
1167 pkgProblemResolver *resolver = [database_ resolver];
1168 resolver->Clear(iterator_);
1169 resolver->Protect(iterator_);
1170 [database_ cache]->MarkInstall(iterator_, false);
1174 pkgProblemResolver *resolver = [database_ resolver];
1175 resolver->Clear(iterator_);
1176 resolver->Protect(iterator_);
1177 resolver->Remove(iterator_);
1178 [database_ cache]->MarkDelete(iterator_, true);
1183 /* Section Class {{{ */
1184 @interface Section : NSObject {
1187 NSMutableArray *packages_;
1192 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1193 - (NSString *) name;
1195 - (NSArray *) packages;
1197 - (void) addPackage:(Package *)package;
1200 @implementation Section
1204 [packages_ release];
1208 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1209 if ((self = [super init]) != nil) {
1210 name_ = [name retain];
1212 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1216 - (NSString *) name {
1224 - (NSArray *) packages {
1229 return [packages_ count];
1232 - (void) addPackage:(Package *)package {
1233 [packages_ addObject:package];
1239 /* Package View {{{ */
1240 @protocol PackageViewDelegate
1241 - (void) performPackage:(Package *)package;
1244 @interface PackageView : UIView {
1245 UIPreferencesTable *table_;
1247 UITextView *description_;
1253 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
1254 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group;
1255 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed;
1256 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
1257 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
1259 - (BOOL) canSelectRow:(int)row;
1260 - (void) tableRowSelected:(NSNotification *)notification;
1262 - (Package *) package;
1264 - (id) initWithFrame:(struct CGRect)frame;
1265 - (void) setPackage:(Package *)package;
1266 - (void) setDelegate:(id)delegate;
1269 @implementation PackageView
1272 if (package_ != nil)
1274 if (description_ != nil)
1275 [description_ release];
1280 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
1284 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
1287 case 1: return @"Details";
1288 case 2: return @"Source";
1290 default: _assert(false);
1294 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
1295 if (group != 0 || row != 1)
1298 return [description_ visibleTextRect].size.height + TextViewOffset_;
1301 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
1303 case 0: return [package_ website] == nil ? 2 : 3;
1307 default: _assert(false);
1311 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
1312 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
1313 [cell setShowSelection:NO];
1316 case 0: switch (row) {
1318 [cell setTitle:[package_ name]];
1319 [cell setValue:[package_ latest]];
1323 [cell addSubview:description_];
1327 [cell setTitle:@"More Information"];
1328 [cell setShowDisclosure:YES];
1329 [cell setShowSelection:YES];
1332 default: _assert(false);
1335 case 1: switch (row) {
1337 [cell setTitle:@"Identifier"];
1338 [cell setValue:[package_ id]];
1342 [cell setTitle:@"Installed Version"];
1343 NSString *installed([package_ installed]);
1344 [cell setValue:(installed == nil ? @"n/a" : installed)];
1348 [cell setTitle:@"Section"];
1349 [cell setValue:[package_ section]];
1353 [cell setTitle:@"Expanded Size"];
1354 [cell setValue:SizeString([package_ size])];
1358 [cell setTitle:@"Maintainer"];
1359 [cell setValue:[[package_ maintainer] name]];
1360 [cell setShowDisclosure:YES];
1361 [cell setShowSelection:YES];
1364 default: _assert(false);
1367 case 2: switch (row) {
1370 default: _assert(false);
1376 - (BOOL) canSelectRow:(int)row {
1380 - (void) tableRowSelected:(NSNotification *)notification {
1381 switch ([table_ selectedRow]) {
1383 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
1384 [[package_ maintainer] email],
1385 [[NSString stringWithFormat:@"regarding apt package \"%@\"", [package_ name]] stringByAddingPercentEscapes]
1391 - (Package *) package {
1395 - (id) initWithFrame:(struct CGRect)frame {
1396 if ((self = [super initWithFrame:frame]) != nil) {
1397 table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]];
1398 [self addSubview:table_];
1400 [table_ setDataSource:self];
1401 [table_ setDelegate:self];
1405 - (void) setPackage:(Package *)package {
1406 if (package_ != nil) {
1407 [package_ autorelease];
1411 if (description_ != nil) {
1412 [description_ release];
1416 if (package != nil) {
1417 package_ = [package retain];
1419 NSString *description([package description]);
1420 if (description == nil)
1421 description = [package tagline];
1422 description_ = [GetTextView(description, 12, true) retain];
1424 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1425 CGColor black(space, 0, 0, 0, 1);
1426 [description_ setTextColor:black];
1427 CGColorSpaceRelease(space);
1429 [table_ reloadData];
1433 - (void) setDelegate:(id)delegate {
1434 delegate_ = delegate;
1439 /* Package Cell {{{ */
1440 @interface PackageCell : UITableCell {
1442 UITextLabel *version_;
1443 UITextLabel *description_;
1449 - (PackageCell *) initWithVersioner:(SEL)versioner;
1450 - (void) setPackage:(Package *)package;
1452 - (void) _setSelected:(float)fraction;
1453 - (void) setSelected:(BOOL)selected;
1454 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
1455 - (void) _setSelectionFadeFraction:(float)fraction;
1459 @implementation PackageCell
1464 [description_ release];
1468 - (PackageCell *) initWithVersioner:(SEL)versioner {
1469 if ((self = [super init]) != nil) {
1470 versioner_ = versioner;
1472 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
1473 GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
1474 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
1476 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1478 CGColor clear(space, 0, 0, 0, 0);
1480 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 7, 250, 25)];
1481 [name_ setBackgroundColor:clear];
1482 [name_ setFont:bold];
1484 version_ = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(286, 7, 70, 25)];
1485 [version_ setBackgroundColor:clear];
1486 [version_ setFont:large];
1488 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(13, 35, 315, 20)];
1489 [description_ setBackgroundColor:clear];
1490 [description_ setFont:small];
1492 [self addSubview:name_];
1493 [self addSubview:version_];
1494 [self addSubview:description_];
1496 CGColorSpaceRelease(space);
1504 - (void) setPackage:(Package *)package {
1505 [name_ setText:[package name]];
1506 [version_ setText:[package latest]];
1507 [description_ setText:[package tagline]];
1510 - (void) _setSelected:(float)fraction {
1511 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1513 CGColor black(space,
1514 interpolate(0.0, 1.0, fraction),
1515 interpolate(0.0, 1.0, fraction),
1516 interpolate(0.0, 1.0, fraction),
1520 interpolate(0.2, 1.0, fraction),
1521 interpolate(0.2, 1.0, fraction),
1522 interpolate(1.0, 1.0, fraction),
1526 interpolate(0.4, 1.0, fraction),
1527 interpolate(0.4, 1.0, fraction),
1528 interpolate(0.4, 1.0, fraction),
1531 [name_ setColor:black];
1532 [version_ setColor:blue];
1533 [description_ setColor:gray];
1535 CGColorSpaceRelease(space);
1538 - (void) setSelected:(BOOL)selected {
1539 [self _setSelected:(selected ? 1.0 : 0.0)];
1540 [super setSelected:selected];
1543 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
1545 [self _setSelected:(selected ? 1.0 : 0.0)];
1546 [super setSelected:selected withFade:fade];
1549 - (void) _setSelectionFadeFraction:(float)fraction {
1550 [self _setSelected:fraction];
1551 [super _setSelectionFadeFraction:fraction];
1557 /* Database Implementation {{{ */
1558 @implementation Database
1565 - (void) _readStatus:(NSNumber *)fd {
1566 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1568 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1569 std::istream is(&ib);
1574 pcre *code = pcre_compile("^([^:]*):([^:]*):([^:]*):(.*)$", 0, &error, &offset, NULL);
1576 pcre_extra *study = NULL;
1578 pcre_fullinfo(code, study, PCRE_INFO_CAPTURECOUNT, &capture);
1579 int matches[(capture + 1) * 3];
1581 while (std::getline(is, line)) {
1582 const char *data(line.c_str());
1584 _assert(pcre_exec(code, study, data, line.size(), 0, 0, matches, sizeof(matches) / sizeof(matches[0])) >= 0);
1586 std::istringstream buffer(line.substr(matches[6], matches[7] - matches[6]));
1589 [delegate_ setPercent:(percent / 100)];
1591 NSString *string = [NSString stringWithCString:(data + matches[8]) length:(matches[9] - matches[8])];
1592 std::string type(line.substr(matches[2], matches[3] - matches[2]));
1594 if (type == "pmerror")
1595 [delegate_ setError:string];
1596 else if (type == "pmstatus")
1597 [delegate_ setTitle:string];
1598 else if (type == "pmconffile")
1600 else _assert(false);
1607 - (void) _readOutput:(NSNumber *)fd {
1608 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1610 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1611 std::istream is(&ib);
1614 while (std::getline(is, line))
1615 [delegate_ addOutput:[NSString stringWithCString:line.c_str()]];
1621 - (Package *) packageWithName:(NSString *)name {
1622 pkgCache::PkgIterator iterator(cache_->FindPkg([name cString]));
1623 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1626 - (Database *) init {
1627 if ((self = [super init]) != nil) {
1635 _assert(pipe(fds) != -1);
1639 detachNewThreadSelector:@selector(_readStatus:)
1641 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1644 _assert(pipe(fds) != -1);
1645 _assert(dup2(fds[1], 1) != -1);
1646 _assert(close(fds[1]) != -1);
1649 detachNewThreadSelector:@selector(_readOutput:)
1651 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1656 - (pkgCacheFile &) cache {
1660 - (pkgRecords *) records {
1664 - (pkgProblemResolver *) resolver {
1668 - (pkgAcquire &) fetcher {
1672 - (void) reloadData {
1680 _assert(cache_.Open(progress_, true));
1681 records_ = new pkgRecords(cache_);
1682 resolver_ = new pkgProblemResolver(cache_);
1683 fetcher_ = new pkgAcquire(&status_);
1688 pkgRecords records(cache_);
1690 lock_ = new FileFd();
1691 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1692 _assert(!_error->PendingError());
1695 _assert(list.ReadMainList());
1697 manager_ = (_system->CreatePM(cache_));
1698 _assert(manager_->GetArchives(fetcher_, &list, &records));
1699 _assert(!_error->PendingError());
1703 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue)
1707 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
1709 if (result == pkgPackageManager::Failed)
1711 if (_error->PendingError())
1713 if (result != pkgPackageManager::Completed)
1719 _assert(list.ReadMainList());
1722 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
1723 _assert(!_error->PendingError());
1725 pkgAcquire fetcher(&status_);
1726 _assert(list.GetIndexes(&fetcher));
1727 _assert(fetcher.Run(PulseInterval_) != pkgAcquire::Failed);
1729 bool failed = false;
1730 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
1731 if ((*item)->Status != pkgAcquire::Item::StatDone) {
1732 (*item)->Finished();
1736 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
1737 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
1738 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
1741 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
1745 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1746 _assert(pkgApplyStatus(cache_));
1748 if (cache_->BrokenCount() != 0) {
1749 _assert(pkgFixBroken(cache_));
1750 _assert(cache_->BrokenCount() == 0);
1751 _assert(pkgMinimizeUpgrade(cache_));
1754 _assert(pkgDistUpgrade(cache_));
1757 - (void) setDelegate:(id)delegate {
1758 delegate_ = delegate;
1759 status_.setDelegate(delegate);
1760 progress_.setDelegate(delegate);
1766 /* Progress Data {{{ */
1767 @interface ProgressData : NSObject {
1773 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
1780 @implementation ProgressData
1782 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
1783 if ((self = [super init]) != nil) {
1784 selector_ = selector;
1804 /* Progress View {{{ */
1805 @interface ProgressView : UIView <
1809 UIView *background_;
1810 UITransitionView *transition_;
1812 UINavigationBar *navbar_;
1813 UIProgressBar *progress_;
1814 UITextView *output_;
1815 UITextLabel *status_;
1821 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
1823 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate;
1824 - (void) setContentView:(UIView *)view;
1827 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
1829 - (void) _retachThread;
1830 - (void) _detachNewThreadData:(ProgressData *)data;
1831 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
1833 - (void) setError:(NSString *)error;
1834 - (void) _setError:(NSString *)error;
1836 - (void) setTitle:(NSString *)title;
1837 - (void) _setTitle:(NSString *)title;
1839 - (void) setPercent:(float)percent;
1840 - (void) _setPercent:(NSNumber *)percent;
1842 - (void) addOutput:(NSString *)output;
1843 - (void) _addOutput:(NSString *)output;
1846 @protocol ProgressViewDelegate
1847 - (void) progressViewIsComplete:(ProgressView *)sender;
1850 @implementation ProgressView
1854 if (background_ != nil)
1855 [background_ release];
1856 [transition_ release];
1859 [progress_ release];
1865 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
1866 if (bootstrap_ && from == overlay_ && to == view_)
1870 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate {
1871 if ((self = [super initWithFrame:frame]) != nil) {
1872 delegate_ = delegate;
1874 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1876 CGColor black(space, 0.0, 0.0, 0.0, 1.0);
1877 CGColor white(space, 1.0, 1.0, 1.0, 1.0);
1878 CGColor clear(space, 0.0, 0.0, 0.0, 0.0);
1880 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
1881 [transition_ setDelegate:self];
1883 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
1886 [overlay_ setBackgroundColor:black];
1888 background_ = [[UIView alloc] initWithFrame:[self bounds]];
1889 [background_ setBackgroundColor:black];
1890 [self addSubview:background_];
1893 [self addSubview:transition_];
1895 CGSize navsize = [UINavigationBar defaultSize];
1896 CGRect navrect = {{0, 0}, navsize};
1898 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
1899 [overlay_ addSubview:navbar_];
1901 [navbar_ setBarStyle:1];
1902 [navbar_ setDelegate:self];
1904 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
1905 [navbar_ pushNavigationItem:navitem];
1907 CGRect bounds = [overlay_ bounds];
1908 CGSize prgsize = [UIProgressBar defaultSize];
1911 (bounds.size.width - prgsize.width) / 2,
1912 bounds.size.height - prgsize.height - 20
1915 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
1916 [overlay_ addSubview:progress_];
1918 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
1920 bounds.size.height - prgsize.height - 50,
1921 bounds.size.width - 20,
1925 [status_ setColor:white];
1926 [status_ setBackgroundColor:clear];
1928 [status_ setCentersHorizontally:YES];
1929 //[status_ setFont:font];
1931 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
1933 navrect.size.height + 20,
1934 bounds.size.width - 20,
1935 bounds.size.height - navsize.height - 62 - navrect.size.height
1938 //[output_ setTextFont:@"Courier New"];
1939 [output_ setTextSize:12];
1941 [output_ setTextColor:white];
1942 [output_ setBackgroundColor:clear];
1944 [output_ setMarginTop:0];
1945 [output_ setAllowsRubberBanding:YES];
1947 [overlay_ addSubview:output_];
1948 [overlay_ addSubview:status_];
1950 [progress_ setStyle:0];
1952 CGColorSpaceRelease(space);
1956 - (void) setContentView:(UIView *)view {
1957 view_ = [view retain];
1960 - (void) resetView {
1961 [transition_ transition:6 toView:view_];
1964 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
1968 - (void) _retachThread {
1969 [delegate_ progressViewIsComplete:self];
1973 - (void) _detachNewThreadData:(ProgressData *)data {
1974 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1976 [[data target] performSelector:[data selector] withObject:[data object]];
1979 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
1984 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
1985 [navbar_ popNavigationItem];
1986 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:title] autorelease];
1987 [navbar_ pushNavigationItem:navitem];
1989 [status_ setText:nil];
1990 [output_ setText:@""];
1991 [progress_ setProgress:0];
1993 [transition_ transition:6 toView:overlay_];
1996 detachNewThreadSelector:@selector(_detachNewThreadData:)
1998 withObject:[[ProgressData alloc]
1999 initWithSelector:selector
2006 - (void) setError:(NSString *)error {
2008 performSelectorOnMainThread:@selector(_setError:)
2014 - (void) _setError:(NSString *)error {
2015 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2016 initWithTitle:@"Package Error"
2017 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2018 defaultButtonIndex:0
2023 [sheet setBodyText:error];
2024 [sheet popupAlertAnimated:YES];
2027 - (void) setTitle:(NSString *)title {
2029 performSelectorOnMainThread:@selector(_setTitle:)
2035 - (void) _setTitle:(NSString *)title {
2036 [status_ setText:[title stringByAppendingString:@"..."]];
2039 - (void) setPercent:(float)percent {
2041 performSelectorOnMainThread:@selector(_setPercent:)
2042 withObject:[NSNumber numberWithFloat:percent]
2047 - (void) _setPercent:(NSNumber *)percent {
2048 [progress_ setProgress:[percent floatValue]];
2051 - (void) addOutput:(NSString *)output {
2053 performSelectorOnMainThread:@selector(_addOutput:)
2059 - (void) _addOutput:(NSString *)output {
2060 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2061 CGSize size = [output_ contentSize];
2062 CGRect rect = {{0, size.height}, {size.width, 0}};
2063 [output_ scrollRectToVisible:rect animated:YES];
2069 /* Package Table {{{ */
2070 @protocol PackageTableDelegate
2071 - (void) packageTable:(id)table packageSelected:(Package *)package;
2074 @interface PackageTable : UIView {
2076 UISectionList *list_;
2080 NSMutableArray *sections_;
2085 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
2086 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
2087 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
2089 - (int) numberOfRowsInTable:(UITable *)table;
2090 - (float) table:(UITable *)table heightForRow:(int)row;
2091 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2092 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2093 - (void) tableRowSelected:(NSNotification *)notification;
2095 - (id) initWithFrame:(CGRect)frame versioner:(SEL)versioner;
2097 - (void) setDelegate:(id)delegate;
2098 - (void) setPackages:(NSArray *)packages;
2100 - (void) resetViewAnimated:(BOOL)animated;
2101 - (UITable *) table;
2104 @implementation PackageTable
2108 [sections_ release];
2109 if (packages_ != nil)
2110 [packages_ release];
2114 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2115 return [sections_ count];
2118 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2119 return [[sections_ objectAtIndex:section] name];
2122 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2123 return [[sections_ objectAtIndex:section] row];
2126 - (int) numberOfRowsInTable:(UITable *)table {
2127 return [packages_ count];
2130 - (float) table:(UITable *)table heightForRow:(int)row {
2134 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2136 reusing = [[[PackageCell alloc] initWithVersioner:versioner_] autorelease];
2137 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2141 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2145 - (void) tableRowSelected:(NSNotification *)notification {
2146 int row = [[notification object] selectedRow];
2147 [delegate_ packageTable:self packageSelected:(row == INT_MAX ? nil : [packages_ objectAtIndex:row])];
2150 - (id) initWithFrame:(CGRect)frame versioner:(SEL)versioner {
2151 if ((self = [super initWithFrame:frame]) != nil) {
2152 versioner_ = versioner;
2153 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
2155 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
2156 [list_ setDataSource:self];
2158 UITableColumn *column = [[[UITableColumn alloc]
2159 initWithTitle:@"Name"
2161 width:frame.size.width
2164 UITable *table = [list_ table];
2165 [table setSeparatorStyle:1];
2166 [table addTableColumn:column];
2167 [table setDelegate:self];
2168 [table setReusesTableCells:YES];
2170 [self addSubview:list_];
2174 - (void) setDelegate:(id)delegate {
2175 delegate_ = delegate;
2178 - (void) setPackages:(NSArray *)packages {
2179 if (packages_ != nil)
2180 [packages_ autorelease];
2181 _assert(packages != nil);
2182 packages_ = [packages retain];
2184 [sections_ removeAllObjects];
2186 Section *section = nil;
2188 for (size_t offset(0); offset != [packages_ count]; ++offset) {
2189 Package *package = [packages_ objectAtIndex:offset];
2190 NSString *name = [package index];
2192 if (section == nil || ![[section name] isEqual:name]) {
2193 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2194 [sections_ addObject:section];
2197 [section addPackage:package];
2203 - (void) resetViewAnimated:(BOOL)animated {
2204 [[list_ table] selectRow:-1 byExtendingSelection:NO withFade:animated];
2207 - (UITable *) table {
2208 return [list_ table];
2214 /* Section Cell {{{ */
2215 @interface SectionCell : UITableCell {
2217 UITextLabel *count_;
2223 - (void) setSection:(Section *)section;
2225 - (void) _setSelected:(float)fraction;
2226 - (void) setSelected:(BOOL)selected;
2227 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2228 - (void) _setSelectionFadeFraction:(float)fraction;
2232 @implementation SectionCell
2241 if ((self = [super init]) != nil) {
2242 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2243 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 12);
2245 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2246 CGColor clear(space, 0, 0, 0, 0);
2247 CGColor white(space, 1, 1, 1, 1);
2249 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(47, 9, 250, 25)];
2250 [name_ setBackgroundColor:clear];
2251 [name_ setFont:bold];
2253 count_ = [[UITextLabel alloc] initWithFrame:CGRectMake(11, 7, 29, 32)];
2254 [count_ setCentersHorizontally:YES];
2255 [count_ setBackgroundColor:clear];
2256 [count_ setFont:small];
2257 [count_ setColor:white];
2259 UIImageView *folder = [[[UIImageView alloc] initWithFrame:CGRectMake(8, 7, 32, 32)] autorelease];
2260 [folder setImage:[UIImage applicationImageNamed:@"folder.png"]];
2262 [self addSubview:folder];
2263 [self addSubview:name_];
2264 [self addSubview:count_];
2266 [self _setSelected:0];
2268 CGColorSpaceRelease(space);
2275 - (void) setSection:(Section *)section {
2276 if (section == nil) {
2277 [name_ setText:@"All Packages"];
2278 [count_ setText:nil];
2280 [name_ setText:[section name]];
2281 [count_ setText:[NSString stringWithFormat:@"%d", [section count]]];
2285 - (void) _setSelected:(float)fraction {
2286 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2288 CGColor black(space,
2289 interpolate(0.0, 1.0, fraction),
2290 interpolate(0.0, 1.0, fraction),
2291 interpolate(0.0, 1.0, fraction),
2294 [name_ setColor:black];
2296 CGColorSpaceRelease(space);
2299 - (void) setSelected:(BOOL)selected {
2300 [self _setSelected:(selected ? 1.0 : 0.0)];
2301 [super setSelected:selected];
2304 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2306 [self _setSelected:(selected ? 1.0 : 0.0)];
2307 [super setSelected:selected withFade:fade];
2310 - (void) _setSelectionFadeFraction:(float)fraction {
2311 [self _setSelected:fraction];
2312 [super _setSelectionFadeFraction:fraction];
2317 /* Install View {{{ */
2318 @interface InstallView : ResetView <
2319 PackageTableDelegate
2323 PackageTable *table_;
2327 NSMutableArray *packages_;
2332 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2334 - (int) numberOfRowsInTable:(UITable *)table;
2335 - (float) table:(UITable *)table heightForRow:(int)row;
2336 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2337 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2338 - (void) tableRowSelected:(NSNotification *)notification;
2340 - (void) packageTable:(id)table packageSelected:(Package *)package;
2342 - (id) initWithFrame:(CGRect)frame;
2343 - (void) setPackages:(NSArray *)packages;
2344 - (void) setDelegate:(id)delegate;
2347 @implementation InstallView
2350 [packages_ release];
2351 if (sections_ != nil)
2352 [sections_ release];
2359 if (section_ != nil)
2361 if (package_ != nil)
2366 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2368 [[view_ package] install];
2369 [delegate_ resolve];
2370 [delegate_ perform];
2374 - (int) numberOfRowsInTable:(UITable *)table {
2375 return [sections_ count] + 1;
2378 - (float) table:(UITable *)table heightForRow:(int)row {
2382 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2384 reusing = [[[SectionCell alloc] init] autorelease];
2386 [(SectionCell *)reusing setSection:nil];
2388 [(SectionCell *)reusing setSection:[sections_ objectAtIndex:(row - 1)]];
2392 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2396 - (void) tableRowSelected:(NSNotification *)notification {
2397 int row = [[notification object] selectedRow];
2399 if (row == INT_MAX) {
2406 _assert(section_ == nil);
2407 _assert(table_ == nil);
2415 name = @"All Packages";
2417 section = [sections_ objectAtIndex:(row - 1)];
2418 name = [section name];
2419 section_ = [name retain];
2422 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
2423 [table_ setDelegate:self];
2424 [table_ setPackages:(section == nil ? packages_ : [section packages])];
2426 [self pushView:table_ withTitle:name backButtonTitle:@"Packages" rightButton:nil];
2430 - (void) packageTable:(id)table packageSelected:(Package *)package {
2431 if (package == nil) {
2438 _assert(package_ == nil);
2439 _assert(view_ == nil);
2441 package_ = [[package name] retain];
2443 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2444 [view_ setDelegate:delegate_];
2446 [view_ setPackage:package];
2448 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:@"Install"];
2452 - (id) initWithFrame:(CGRect)frame {
2453 if ((self = [super initWithFrame:frame]) != nil) {
2454 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2456 list_ = [[UITable alloc] initWithFrame:[transition_ bounds]];
2457 [self pushView:list_ withTitle:@"Install" backButtonTitle:@"Sections" rightButton:nil];
2459 UITableColumn *column = [[[UITableColumn alloc]
2460 initWithTitle:@"Name"
2462 width:frame.size.width
2465 [list_ setDataSource:self];
2466 [list_ setSeparatorStyle:1];
2467 [list_ addTableColumn:column];
2468 [list_ setDelegate:self];
2469 [list_ setReusesTableCells:YES];
2471 [transition_ transition:0 toView:list_];
2475 - (void) setPackages:(NSArray *)packages {
2476 [packages_ removeAllObjects];
2478 for (size_t i(0); i != [packages count]; ++i) {
2479 Package *package([packages objectAtIndex:i]);
2480 if ([package installed] == nil)
2481 [packages_ addObject:package];
2484 [packages_ sortUsingSelector:@selector(compareBySectionAndName:)];
2485 NSMutableArray *sections = [NSMutableArray arrayWithCapacity:16];
2487 Section *nsection = nil;
2488 Package *npackage = nil;
2490 Section *section = nil;
2491 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
2492 Package *package = [packages_ objectAtIndex:offset];
2493 NSString *name = [package section];
2495 if (section == nil || ![[section name] isEqual:name]) {
2496 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2498 if ([name isEqualToString:section_])
2500 [sections addObject:section];
2503 if ([[package name] isEqualToString:package_])
2505 [section addPackage:package];
2508 if (sections_ != nil)
2509 [sections_ release];
2510 sections_ = [sections retain];
2512 [packages_ sortUsingSelector:@selector(compareByName:)];
2518 if (npackage != nil)
2519 [view_ setPackage:npackage];
2520 else if (package_ != nil)
2523 if (nsection != nil)
2524 [table_ setPackages:[nsection packages]];
2525 else if (section_ != nil)
2528 [self popViews:views];
2532 - (void) setDelegate:(id)delegate {
2534 [view_ setDelegate:delegate];
2535 [super setDelegate:delegate];
2540 /* Changes View {{{ */
2541 @interface ChangesView : ResetView <
2542 PackageTableDelegate
2544 UISectionList *list_;
2545 NSMutableArray *packages_;
2546 NSMutableArray *sections_;
2554 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2556 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
2557 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
2558 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
2560 - (int) numberOfRowsInTable:(UITable *)table;
2561 - (float) table:(UITable *)table heightForRow:(int)row;
2562 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2563 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2564 - (void) tableRowSelected:(NSNotification *)notification;
2566 - (id) initWithFrame:(CGRect)frame;
2567 - (void) setPackages:(NSArray *)packages;
2568 - (void) _resetView;
2571 - (void) setDelegate:(id)delegate;
2574 @implementation ChangesView
2578 [packages_ release];
2579 [sections_ release];
2582 if (package_ != nil)
2587 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2588 return [sections_ count];
2591 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2592 return [[sections_ objectAtIndex:section] name];
2595 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2596 return [[sections_ objectAtIndex:section] row];
2599 - (int) numberOfRowsInTable:(UITable *)table {
2600 return [packages_ count];
2603 - (float) table:(UITable *)table heightForRow:(int)row {
2607 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2609 reusing = [[[PackageCell alloc] initWithVersioner:NULL] autorelease];
2610 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2614 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2618 - (void) tableRowSelected:(NSNotification *)notification {
2619 int row = [[notification object] selectedRow];
2620 [self packageTable:self packageSelected:(row == INT_MAX ? nil : [packages_ objectAtIndex:row])];
2623 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2626 [[view_ package] install];
2627 [delegate_ resolve];
2628 [delegate_ perform];
2632 [delegate_ upgrade];
2637 - (void) packageTable:(id)table packageSelected:(Package *)package {
2638 if (package == nil) {
2645 _assert(package_ == nil);
2646 _assert(view_ == nil);
2648 package_ = [[package name] retain];
2650 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2651 [view_ setDelegate:delegate_];
2653 [view_ setPackage:package];
2655 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:(
2656 [package upgradable] ? @"Upgrade" : @"Install"
2661 - (id) initWithFrame:(CGRect)frame {
2662 if ((self = [super initWithFrame:frame]) != nil) {
2663 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2664 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
2666 list_ = [[UISectionList alloc] initWithFrame:[transition_ bounds] showSectionIndex:NO];
2667 [list_ setShouldHideHeaderInShortLists:NO];
2668 [list_ setDataSource:self];
2669 //[list_ setSectionListStyle:1];
2671 UITableColumn *column = [[[UITableColumn alloc]
2672 initWithTitle:@"Name"
2674 width:frame.size.width
2677 UITable *table = [list_ table];
2678 [table setSeparatorStyle:1];
2679 [table addTableColumn:column];
2680 [table setDelegate:self];
2681 [table setReusesTableCells:YES];
2683 [self pushView:list_ withTitle:@"Changes" backButtonTitle:nil rightButton:nil];
2687 - (void) setPackages:(NSArray *)packages {
2688 [packages_ removeAllObjects];
2689 for (size_t i(0); i != [packages count]; ++i) {
2690 Package *package([packages objectAtIndex:i]);
2691 if ([package installed] == nil || [package upgradable])
2692 [packages_ addObject:package];
2695 [packages_ sortUsingSelector:@selector(compareForChanges:)];
2697 [sections_ removeAllObjects];
2699 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades" row:0] autorelease];
2700 Section *section = nil;
2703 Package *npackage = nil;
2704 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
2705 Package *package = [packages_ objectAtIndex:offset];
2706 if ([[package name] isEqualToString:package_])
2709 if ([package upgradable])
2710 [upgradable addPackage:package];
2712 NSDate *seen = [package seen];
2714 CFLocaleRef locale = CFLocaleCopyCurrent();
2715 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
2716 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
2718 NSString *name = (NSString *) formatted;
2720 if (section == nil || ![[section name] isEqual:name]) {
2721 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2722 [sections_ addObject:section];
2725 [section addPackage:package];
2727 CFRelease(formatter);
2728 CFRelease(formatted);
2733 count_ = [[upgradable packages] count];
2735 [sections_ insertObject:upgradable atIndex:0];
2739 if (npackage != nil)
2740 [view_ setPackage:npackage];
2741 else if (package_ != nil)
2748 - (void) _resetView {
2749 if ([views_ count] == 1)
2750 [navbar_ showButtonsWithLeftTitle:(count_ == 0 ? nil : @"Upgrade All") rightTitle:nil];
2757 - (void) setDelegate:(id)delegate {
2759 [view_ setDelegate:delegate];
2760 [super setDelegate:delegate];
2765 /* Manage View {{{ */
2766 @interface ManageView : ResetView <
2767 PackageTableDelegate
2769 PackageTable *table_;
2776 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2778 - (void) packageTable:(id)table packageSelected:(Package *)package;
2780 - (id) initWithFrame:(CGRect)frame;
2781 - (void) setPackages:(NSArray *)packages;
2783 - (void) setDelegate:(id)delegate;
2786 @implementation ManageView
2792 if (package_ != nil)
2797 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2799 [[view_ package] remove];
2800 [delegate_ resolve];
2801 [delegate_ perform];
2805 - (void) packageTable:(id)table packageSelected:(Package *)package {
2806 if (package == nil) {
2813 _assert(package_ == nil);
2814 _assert(view_ == nil);
2816 package_ = [[package name] retain];
2818 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2819 [view_ setDelegate:delegate_];
2821 [view_ setPackage:package];
2823 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:@"Uninstall"];
2827 - (id) initWithFrame:(CGRect)frame {
2828 if ((self = [super initWithFrame:frame]) != nil) {
2829 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
2830 [table_ setDelegate:self];
2832 [self pushView:table_ withTitle:@"Uninstall" backButtonTitle:@"Packages" rightButton:nil];
2836 - (void) setPackages:(NSArray *)packages {
2837 NSMutableArray *local = [NSMutableArray arrayWithCapacity:16];
2838 for (size_t i(0); i != [packages count]; ++i) {
2839 Package *package([packages objectAtIndex:i]);
2840 if ([package installed] != nil)
2841 [local addObject:package];
2844 [local sortUsingSelector:@selector(compareByName:)];
2846 Package *npackage = nil;
2847 for (size_t offset = 0, count = [local count]; offset != count; ++offset) {
2848 Package *package = [local objectAtIndex:offset];
2849 if ([[package name] isEqualToString:package_])
2853 [table_ setPackages:local];
2855 if (npackage != nil)
2856 [view_ setPackage:npackage];
2857 else if (package_ != nil)
2863 - (void) setDelegate:(id)delegate {
2865 [view_ setDelegate:delegate];
2866 [super setDelegate:delegate];
2871 /* Search View {{{ */
2872 @protocol SearchViewDelegate
2873 - (void) showKeyboard:(BOOL)show;
2876 @interface SearchView : ResetView <
2877 PackageTableDelegate
2879 NSMutableArray *packages_;
2881 UISearchField *field_;
2882 PackageTable *table_;
2889 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2890 - (void) packageTable:(id)table packageSelected:(Package *)package;
2892 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field;
2893 - (void) textFieldDidResignFirstResponder:(UITextField *)field;
2895 - (void) keyboardInputChanged:(UIFieldEditor *)editor;
2896 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked;
2898 - (id) initWithFrame:(CGRect)frame;
2899 - (void) setPackages:(NSArray *)packages;
2901 - (void) setDelegate:(id)delegate;
2902 - (void) resetPackage:(Package *)package;
2903 - (void) searchPackages;
2907 @implementation SearchView
2910 [packages_ release];
2911 [accessory_ release];
2916 if (package_ != nil)
2921 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2923 Package *package = [view_ package];
2924 if ([package installed] == nil)
2928 [delegate_ resolve];
2929 [delegate_ perform];
2933 - (void) packageTable:(id)table packageSelected:(Package *)package {
2934 if (package == nil) {
2935 [navbar_ setAccessoryView:accessory_ animate:(resetting_ ? NO : YES) goingBack:YES];
2943 [navbar_ setAccessoryView:nil animate:YES goingBack:NO];
2945 _assert(package_ == nil);
2946 _assert(view_ == nil);
2948 package_ = [[package name] retain];
2950 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2951 [view_ setDelegate:delegate_];
2953 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:nil];
2954 [self resetPackage:package];
2958 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
2959 [delegate_ showKeyboard:YES];
2960 [table_ setEnabled:NO];
2962 /*CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2963 CGColor dimmed(alpha, 0, 0, 0, 0.5);
2964 [editor_ setBackgroundColor:dimmed];
2965 CGColorSpaceRelease(space);*/
2968 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
2969 [table_ setEnabled:YES];
2970 [delegate_ showKeyboard:NO];
2973 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
2974 NSString *text([field_ text]);
2975 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
2978 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
2979 if ([text length] != 1 || [text characterAtIndex:0] != '\n')
2982 [self searchPackages];
2983 [field_ resignFirstResponder];
2987 - (id) initWithFrame:(CGRect)frame {
2988 if ((self = [super initWithFrame:frame]) != nil) {
2989 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2991 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
2992 [table_ setDelegate:self];
2994 CGRect area = [self bounds];
2997 area.size.width -= 12;
2998 area.size.height = [UISearchField defaultHeight];
3000 field_ = [[UISearchField alloc] initWithFrame:area];
3002 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
3003 [field_ setFont:font];
3006 [field_ setPlaceholder:@"Package Names & Descriptions"];
3007 [field_ setPaddingTop:5];
3008 [field_ setDelegate:self];
3010 UITextTraits *traits = [field_ textTraits];
3011 [traits setEditingDelegate:self];
3012 [traits setReturnKeyType:6];
3014 accessory_ = [[UIView alloc] initWithFrame:CGRectMake(6, 6, area.size.width, area.size.height + 30)];
3015 [accessory_ addSubview:field_];
3017 [navbar_ setAccessoryView:accessory_];
3018 [self pushView:table_ withTitle:nil backButtonTitle:@"Search" rightButton:nil];
3020 /* XXX: for the love of god just fix this */
3021 [navbar_ removeFromSuperview];
3022 [reload_ removeFromSuperview];
3023 [configure_ removeFromSuperview];
3024 [self addSubview:navbar_];
3025 [self addSubview:reload_];
3026 [self addSubview:configure_];
3030 - (void) setPackages:(NSArray *)packages {
3031 [packages_ removeAllObjects];
3032 [packages_ addObjectsFromArray:packages];
3033 [packages_ sortUsingSelector:@selector(compareByName:)];
3035 Package *npackage = nil;
3036 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
3037 Package *package = [packages_ objectAtIndex:offset];
3038 if ([[package name] isEqualToString:package_])
3042 [self searchPackages];
3044 if (npackage != nil)
3045 [self resetPackage:npackage];
3046 else if (package_ != nil)
3052 - (void) setDelegate:(id)delegate {
3054 [view_ setDelegate:delegate];
3055 [super setDelegate:delegate];
3058 - (void) resetPackage:(Package *)package {
3059 [view_ setPackage:package];
3060 NSString *right = [package installed] == nil ? @"Install" : @"Uninstall";
3061 [navbar_ showButtonsWithLeftTitle:nil rightTitle:right];
3064 - (void) searchPackages {
3065 NSString *text([field_ text]);
3067 NSMutableArray *packages([NSMutableArray arrayWithCapacity:16]);
3069 for (size_t offset(0), count([packages_ count]); offset != count; ++offset) {
3070 Package *package = [packages_ objectAtIndex:offset];
3071 if ([package matches:text])
3072 [packages addObject:package];
3075 [table_ setPackages:packages];
3076 [[table_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3082 @interface Cydia : UIApplication <
3083 ConfirmationViewDelegate,
3084 ProgressViewDelegate,
3090 UITransitionView *transition_;
3091 UIButtonBar *buttonbar_;
3093 ConfirmationView *confirm_;
3095 Database *database_;
3096 ProgressView *progress_;
3099 UINavigationBar *navbar_;
3100 UIScroller *scroller_;
3101 UIWebView *webview_;
3103 UIProgressIndicator *indicator_;
3105 InstallView *install_;
3106 ChangesView *changes_;
3107 ManageView *manage_;
3108 SearchView *search_;
3113 UIKeyboard *keyboard_;
3117 - (void) reloadData:(BOOL)reset;
3128 - (void) progressViewIsComplete:(ProgressView *)progress;
3130 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
3131 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
3132 - (void) buttonBarItemTapped:(id)sender;
3134 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old;
3136 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame;
3138 - (void) applicationWillSuspend;
3139 - (void) applicationDidFinishLaunching:(id)unused;
3142 @implementation Cydia
3143 #include "internals.h"
3146 NSMutableURLRequest *request = [NSMutableURLRequest
3148 cachePolicy:NSURLRequestReloadIgnoringCacheData
3149 timeoutInterval:30.0
3152 [request addValue:[NSString stringWithCString:Machine_] forHTTPHeaderField:@"X-Machine"];
3153 [request addValue:[NSString stringWithCString:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
3155 [webview_ loadRequest:request];
3158 - (void) reloadData:(BOOL)reset {
3159 [database_ reloadData];
3163 if (Packages_ == nil) {
3164 Packages_ = [[NSMutableDictionary alloc] initWithCapacity:count];
3165 [Metadata_ setObject:Packages_ forKey:@"Packages"];
3168 now_ = [NSDate date];
3170 NSMutableArray *packages = [NSMutableArray arrayWithCapacity:count];
3171 for (pkgCache::PkgIterator iterator = [database_ cache]->PkgBegin(); !iterator.end(); ++iterator)
3172 if (Package *package = [Package packageWithIterator:iterator database:database_])
3173 [packages addObject:package];
3175 [install_ setPackages:packages];
3176 [changes_ setPackages:packages];
3177 [manage_ setPackages:packages];
3178 [search_ setPackages:packages];
3180 if (size_t count = [changes_ count]) {
3181 NSString *badge([[NSNumber numberWithInt:count] stringValue]);
3182 [buttonbar_ setBadgeValue:badge forButton:3];
3183 [buttonbar_ setBadgeAnimated:YES forButton:3];
3184 [self setApplicationBadge:badge];
3186 [buttonbar_ setBadgeValue:nil forButton:3];
3187 [buttonbar_ setBadgeAnimated:NO forButton:3];
3188 [self removeApplicationBadge];
3191 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
3194 - (void) setPrompt {
3195 [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
3199 pkgProblemResolver *resolver = [database_ resolver];
3201 resolver->InstallProtect();
3202 if (!resolver->Resolve(true))
3207 [database_ prepare];
3208 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
3212 [database_ upgrade];
3217 [self reloadData:NO];
3223 [overlay_ removeFromSuperview];
3227 detachNewThreadSelector:@selector(perform)
3234 - (void) bootstrap_ {
3236 [database_ upgrade];
3237 [database_ prepare];
3238 [database_ perform];
3241 - (void) bootstrap {
3243 detachNewThreadSelector:@selector(bootstrap_)
3246 title:@"Bootstrap Install..."
3252 detachNewThreadSelector:@selector(update)
3255 title:@"Refreshing Sources..."
3259 - (void) progressViewIsComplete:(ProgressView *)progress {
3260 [self reloadData:YES];
3262 if (confirm_ != nil) {
3263 [underlay_ addSubview:overlay_];
3264 [confirm_ removeFromSuperview];
3270 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
3277 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3278 initWithTitle:@"About Cydia Packager"
3279 buttons:[NSArray arrayWithObjects:@"Close", nil]
3280 defaultButtonIndex:0
3286 @"Copyright (C) 2008\n"
3287 "Jay Freeman (saurik)\n"
3288 "saurik@saurik.com\n"
3289 "http://www.saurik.com/\n"
3292 "http://www.theokorigroup.com/\n"
3294 "College of Creative Studies,\n"
3295 "University of California,\n"
3297 "http://www.ccs.ucsb.edu/\n"
3300 "bad_, BHSPitMonkey, cash, Cobra,\n"
3301 "core, Corona, crashx, cromas,\n"
3302 "Darken, dtzWill, Erica, francis,\n"
3303 "Godores, jerry, Kingstone, lounger,\n"
3304 "mbranes, rockabilly, tman, Wbiggs"
3307 [sheet presentSheetFromButtonBar:buttonbar_];
3312 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3316 - (void) buttonBarItemTapped:(id)sender {
3318 unsigned tag = [sender tag];
3321 case 1: view = featured_; break;
3322 case 2: view = install_; break;
3323 case 3: view = changes_; break;
3324 case 4: view = manage_; break;
3325 case 5: view = search_; break;
3331 if ([view respondsToSelector:@selector(resetView:)])
3332 [(id) view resetView:(tag == tag_ ? NO : YES)];
3334 [transition_ transition:0 toView:view];
3337 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
3338 [scroller_ setContentSize:frame.size];
3339 [indicator_ stopAnimation];
3342 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
3343 [navbar_ setPrompt:title];
3346 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
3347 [navbar_ setPrompt:@"Loading..."];
3348 [indicator_ startAnimation];
3351 - (void) applicationWillSuspend {
3353 system("launchctl stop com.apple.SpringBoard");
3354 [super applicationWillSuspend];
3357 - (void) applicationDidFinishLaunching:(id)unused {
3358 _assert(pkgInitConfig(*_config));
3359 _assert(pkgInitSystem(*_config, _system));
3365 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
3366 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
3368 [window_ orderFront: self];
3369 [window_ makeKey: self];
3370 [window_ _setHidden: NO];
3372 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] delegate:self];
3373 [window_ setContentView:progress_];
3375 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
3376 [progress_ setContentView:underlay_];
3378 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
3381 [underlay_ addSubview:overlay_];
3383 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
3384 0, 0, screenrect.size.width, screenrect.size.height - 48
3387 [overlay_ addSubview:transition_];
3389 featured_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
3391 CGSize navsize = [UINavigationBar defaultSizeWithPrompt];
3392 CGRect navrect = {{0, 0}, navsize};
3394 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
3395 [featured_ addSubview:navbar_];
3397 [navbar_ setBarStyle:1];
3398 [navbar_ setDelegate:self];
3400 [navbar_ showButtonsWithLeftTitle:@"About" rightTitle:@"Reload"];
3402 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Featured"] autorelease];
3403 [navbar_ pushNavigationItem:navitem];
3405 struct CGRect subbounds = [featured_ bounds];
3406 subbounds.origin.y += navsize.height;
3407 subbounds.size.height -= navsize.height;
3409 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:subbounds] autorelease];
3410 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
3411 [featured_ addSubview:pinstripe];
3413 scroller_ = [[UIScroller alloc] initWithFrame:subbounds];
3414 [featured_ addSubview:scroller_];
3416 [scroller_ setScrollingEnabled:YES];
3417 [scroller_ setAdjustForContentSizeChange:YES];
3418 [scroller_ setClipsSubviews:YES];
3419 [scroller_ setAllowsRubberBanding:YES];
3420 [scroller_ setScrollDecelerationFactor:0.99];
3421 [scroller_ setDelegate:self];
3423 CGRect webrect = [scroller_ bounds];
3424 webrect.size.height = 0;
3426 webview_ = [[UIWebView alloc] initWithFrame:webrect];
3427 [scroller_ addSubview:webview_];
3429 [webview_ setTilingEnabled:YES];
3430 [webview_ setTileSize:CGSizeMake(screenrect.size.width, 500)];
3431 [webview_ setAutoresizes:YES];
3432 [webview_ setDelegate:self];
3434 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:2];
3435 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(87, 45, indsize.width, indsize.height)];
3436 [indicator_ setStyle:2];
3437 [featured_ addSubview:indicator_];
3439 NSArray *buttonitems = [NSArray arrayWithObjects:
3440 [NSDictionary dictionaryWithObjectsAndKeys:
3441 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3442 @"featured-up.png", kUIButtonBarButtonInfo,
3443 @"featured-dn.png", kUIButtonBarButtonSelectedInfo,
3444 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
3445 self, kUIButtonBarButtonTarget,
3446 @"Featured", kUIButtonBarButtonTitle,
3447 @"0", kUIButtonBarButtonType,
3450 [NSDictionary dictionaryWithObjectsAndKeys:
3451 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3452 @"install-up.png", kUIButtonBarButtonInfo,
3453 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
3454 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
3455 self, kUIButtonBarButtonTarget,
3456 @"Install", kUIButtonBarButtonTitle,
3457 @"0", kUIButtonBarButtonType,
3460 [NSDictionary dictionaryWithObjectsAndKeys:
3461 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3462 @"changes-up.png", kUIButtonBarButtonInfo,
3463 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
3464 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
3465 self, kUIButtonBarButtonTarget,
3466 @"Changes", kUIButtonBarButtonTitle,
3467 @"0", kUIButtonBarButtonType,
3470 [NSDictionary dictionaryWithObjectsAndKeys:
3471 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3472 @"manage-up.png", kUIButtonBarButtonInfo,
3473 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
3474 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
3475 self, kUIButtonBarButtonTarget,
3476 @"Uninstall", kUIButtonBarButtonTitle,
3477 @"0", kUIButtonBarButtonType,
3480 [NSDictionary dictionaryWithObjectsAndKeys:
3481 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3482 @"search-up.png", kUIButtonBarButtonInfo,
3483 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
3484 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
3485 self, kUIButtonBarButtonTarget,
3486 @"Search", kUIButtonBarButtonTitle,
3487 @"0", kUIButtonBarButtonType,
3491 buttonbar_ = [[UIButtonBar alloc]
3493 withFrame:CGRectMake(
3494 0, screenrect.size.height - 48,
3495 screenrect.size.width, 48
3497 withItemList:buttonitems
3500 [buttonbar_ setDelegate:self];
3501 [buttonbar_ setBarStyle:1];
3502 [buttonbar_ setButtonBarTrackingMode:2];
3504 int buttons[5] = {1, 2, 3, 4, 5};
3505 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
3506 [buttonbar_ showButtonGroup:0 withDuration:0];
3508 for (int i = 0; i != 5; ++i)
3509 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
3510 i * 64 + 2, 1, 60, 48
3513 [buttonbar_ showSelectionForButton:1];
3514 [transition_ transition:0 toView:featured_];
3516 [overlay_ addSubview:buttonbar_];
3518 [UIKeyboard initImplementationNow];
3520 CGRect edtrect = [overlay_ bounds];
3521 edtrect.origin.y += navsize.height;
3522 edtrect.size.height -= navsize.height;
3524 CGSize keysize = [UIKeyboard defaultSize];
3525 CGRect keyrect = {{0, [overlay_ bounds].size.height - keysize.height}, keysize};
3526 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
3528 database_ = [[Database alloc] init];
3529 [database_ setDelegate:progress_];
3531 install_ = [[InstallView alloc] initWithFrame:[transition_ bounds]];
3532 [install_ setDelegate:self];
3534 changes_ = [[ChangesView alloc] initWithFrame:[transition_ bounds]];
3535 [changes_ setDelegate:self];
3537 manage_ = [[ManageView alloc] initWithFrame:[transition_ bounds]];
3538 [manage_ setDelegate:self];
3540 search_ = [[SearchView alloc] initWithFrame:[transition_ bounds]];
3541 [search_ setDelegate:self];
3543 [self reloadData:NO];
3545 Package *package([database_ packageWithName:@"cydia"]);
3546 NSString *application = package == nil ? @"Cydia" : [NSString stringWithFormat:@"Cydia/%@", [package installed]];
3548 WebView *webview = [webview_ webView];
3549 [webview setApplicationNameForUserAgent:application];
3550 [webview setFrameLoadDelegate:self];
3552 url_ = [NSURL URLWithString:@"http://cydia.saurik.com/"];
3555 [progress_ resetView];
3561 - (void) showKeyboard:(BOOL)show {
3563 [overlay_ addSubview:keyboard_];
3565 [keyboard_ removeFromSuperview];
3570 void AddPreferences(NSString *plist) {
3571 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
3573 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
3574 _assert(settings != NULL);
3575 NSMutableArray *items = [settings objectForKey:@"items"];
3579 for (size_t i(0); i != [items count]; ++i) {
3580 NSMutableDictionary *item([items objectAtIndex:i]);
3581 NSString *label = [item objectForKey:@"label"];
3582 if (label != nil && [label isEqualToString:@"Cydia"]) {
3589 for (size_t i(0); i != [items count]; ++i) {
3590 NSDictionary *item([items objectAtIndex:i]);
3591 NSString *label = [item objectForKey:@"label"];
3592 if (label != nil && [label isEqualToString:@"General"]) {
3593 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
3594 @"CydiaSettings", @"bundle",
3595 @"PSLinkCell", @"cell",
3596 [NSNumber numberWithBool:YES], @"hasIcon",
3597 [NSNumber numberWithBool:YES], @"isController",
3599 nil] atIndex:(i + 1)];
3605 _assert([settings writeToFile:plist atomically:YES] == YES);
3612 id Alloc_(id self, SEL selector) {
3613 id object = alloc_(self, selector);
3614 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
3618 int main(int argc, char *argv[]) {
3620 memset(nl, 0, sizeof(nl));
3621 nl[0].n_un.n_name = "_useMDNSResponder";
3622 nlist("/usr/lib/libc.dylib", nl);
3623 if (nl[0].n_type != N_UNDF)
3624 *(int *) nl[0].n_value = 0;
3626 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
3631 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
3632 alloc_ = alloc->method_imp;
3633 alloc->method_imp = (IMP) &Alloc_;*/
3635 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
3638 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
3639 char *machine = new char[size];
3640 sysctlbyname("hw.machine", machine, &size, NULL, 0);
3643 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
3644 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
3645 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
3646 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
3650 IOObjectRelease(service);
3653 AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
3654 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");
3656 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
3657 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
3659 Packages_ = [Metadata_ objectForKey:@"Packages"];
3661 UIApplicationMain(argc, argv, [Cydia class]);