X-Git-Url: https://git.saurik.com/cydia.git/blobdiff_plain/fae8ee564d1871cd8850b16437294d07f77dc2da..83682c75c396c79b21db66ab32bb2891810acc59:/MobileCydia.mm diff --git a/MobileCydia.mm b/MobileCydia.mm index ccec42b8..0a47412b 100644 --- a/MobileCydia.mm +++ b/MobileCydia.mm @@ -1,5 +1,5 @@ /* Cydia - iPhone UIKit Front-End for Debian APT - * Copyright (C) 2008-2010 Jay Freeman (saurik) + * Copyright (C) 2008-2011 Jay Freeman (saurik) */ /* Modified BSD License {{{ */ @@ -217,14 +217,6 @@ union SplitHash { static const NSUInteger UIViewAutoresizingFlexibleBoth(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); -void NSLogPoint(const char *fix, const CGPoint &point) { - NSLog(@"%s(%g,%g)", fix, point.x, point.y); -} - -void NSLogRect(const char *fix, const CGRect &rect) { - NSLog(@"%s(%g,%g)+(%g,%g)", fix, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); -} - static _finline NSString *CydiaURL(NSString *path) { char page[25]; page[0] = 'h'; page[1] = 't'; page[2] = 't'; page[3] = 'p'; page[4] = ':'; @@ -309,18 +301,19 @@ static _finline void UpdateExternalStatus(uint64_t newStatus) { @end /* }}} */ -/* Cydia Action Sheet {{{ */ -@interface CYActionSheet : UIAlertView { +/* Cydia Alert View {{{ */ +@interface CYAlertView : UIAlertView { unsigned button_; } - (int) yieldToPopupAlertAnimated:(BOOL)animated; + @end -@implementation CYActionSheet +@implementation CYAlertView - (id) initWithTitle:(NSString *)title buttons:(NSArray *)buttons defaultButtonIndex:(int)index { - if ((self = [super init])) { + if ((self = [super init]) != nil) { [self setTitle:title]; [self setDelegate:self]; for (NSString *button in buttons) [self addButtonWithTitle:button]; @@ -363,32 +356,6 @@ static const NSStringCompareOptions MatchCompareOptions_ = NSLiteralSearch | NSC static const NSStringCompareOptions LaxCompareOptions_ = NSNumericSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch | NSCaseInsensitiveSearch; static const CFStringCompareFlags LaxCompareFlags_ = kCFCompareCaseInsensitive | kCFCompareNonliteral | kCFCompareLocalized | kCFCompareNumerically | kCFCompareWidthInsensitive | kCFCompareForcedOrdering; -/* Information Dictionaries {{{ */ -@interface NSMutableArray (Cydia) -- (void) addInfoDictionary:(NSDictionary *)info; -@end - -@implementation NSMutableArray (Cydia) - -- (void) addInfoDictionary:(NSDictionary *)info { - [self addObject:info]; -} - -@end - -@interface NSMutableDictionary (Cydia) -- (void) addInfoDictionary:(NSDictionary *)info; -@end - -@implementation NSMutableDictionary (Cydia) - -- (void) addInfoDictionary:(NSDictionary *)info { - [self setObject:info forKey:[info objectForKey:@"CFBundleIdentifier"]]; -} - -@end -/* }}} */ - #define lprintf(args...) fprintf(stderr, args) #define ForRelease 1 @@ -400,8 +367,8 @@ static const CFStringCompareFlags LaxCompareFlags_ = kCFCompareCaseInsensitive | #define TrackResize (0 && !ForRelease) #define ManualRefresh (1 && !ForRelease) #define ShowInternals (0 && !ForRelease) -#define IgnoreInstall (0 && !ForRelease) #define AlwaysReload (0 && !ForRelease) +#define TryIndexedCollation (0 && !ForRelease) #if !TraceLogging #undef _trace @@ -905,6 +872,7 @@ class Pcre { + (Address *) addressWithString:(NSString *)string; - (Address *) initWithString:(NSString *)string; + @end @implementation Address @@ -938,7 +906,10 @@ class Pcre { } + (NSArray *) _attributeKeys { - return [NSArray arrayWithObjects:@"address", @"name", nil]; + return [NSArray arrayWithObjects: + @"address", + @"name", + nil]; } - (NSArray *) attributeKeys { @@ -1013,6 +984,8 @@ class CYColor { /* Random Global Variables {{{ */ static const int PulseInterval_ = 50000; +static const NSString *UI_; + static int Finish_; static NSArray *Finishes_; @@ -1071,7 +1044,8 @@ static _transient NSMutableDictionary *Sources_; static bool Changed_; static time_t now_; -static bool IsWildcat_; +bool IsWildcat_; +static CGFloat ScreenScale_; /* }}} */ /* Display Helpers {{{ */ @@ -1079,23 +1053,6 @@ inline float Interpolate(float begin, float end, float fraction) { return (end - begin) * fraction + begin; } -/* XXX: localize this! */ -NSString *SizeString(double size) { - bool negative = size < 0; - if (negative) - size = -size; - - unsigned power = 0; - while (size > 1024) { - size /= 1024; - ++power; - } - - static const char *powers_[] = {"B", "kB", "MB", "GB"}; - - return [NSString stringWithFormat:@"%s%.1f %s", (negative ? "-" : ""), size, powers_[power]]; -} - static _finline const char *StripVersion_(const char *version) { const char *colon(strchr(version, ':')); return colon == NULL ? version : colon + 1; @@ -1184,7 +1141,6 @@ bool isSectionVisible(NSString *section) { @protocol CydiaDelegate - (void) retainNetworkActivityIndicator; - (void) releaseNetworkActivityIndicator; -- (void) setPackageController:(CYPackageController *)view; - (void) clearPackage:(Package *)package; - (void) installPackage:(Package *)package; - (void) installPackages:(NSArray *)packages; @@ -1378,6 +1334,7 @@ typedef std::map< unsigned long, _H > SourceMap; - (pkgSourceList &) list; - (NSArray *) packages; - (NSArray *) sources; +- (Source *) sourceWithKey:(NSString *)key; - (void) reloadData; - (void) configure; @@ -1461,7 +1418,7 @@ struct MetaValue : static Cytore::File MetaFile_; // }}} // Cytore Helper Functions {{{ -static PackageValue *PackageFind(const char *name, size_t length) { +static PackageValue *PackageFind(const char *name, size_t length, bool *fail = NULL) { SplitHash nhash = { hashlittle(name, length) }; PackageValue *metadata; @@ -1471,6 +1428,14 @@ static PackageValue *PackageFind(const char *name, size_t length) { *offset = MetaFile_.New(length + 1); metadata = &MetaFile_.Get(*offset); + if (metadata == NULL) { + if (fail != NULL) + *fail = true; + + metadata = new PackageValue(); + memset(metadata, 0, sizeof(*metadata)); + } + memcpy(metadata->name_, name, length + 1); metadata->nhash_ = nhash.u16[1]; } else { @@ -1486,13 +1451,15 @@ static PackageValue *PackageFind(const char *name, size_t length) { } static void PackageImport(const void *key, const void *value, void *context) { + bool &fail(*reinterpret_cast(context)); + char buffer[1024]; if (!CFStringGetCString((CFStringRef) key, buffer, sizeof(buffer), kCFStringEncodingUTF8)) { NSLog(@"failed to import package %@", key); return; } - PackageValue *metadata(PackageFind(buffer, strlen(buffer))); + PackageValue *metadata(PackageFind(buffer, strlen(buffer), &fail)); NSDictionary *package((NSDictionary *) value); if (NSNumber *subscribed = [package objectForKey:@"IsSubscribed"]) @@ -1613,7 +1580,19 @@ static void PackageImport(const void *key, const void *value, void *context) { } + (NSArray *) _attributeKeys { - return [NSArray arrayWithObjects:@"description", @"distribution", @"host", @"key", @"label", @"name", @"origin", @"trusted", @"type", @"uri", @"version", nil]; + return [NSArray arrayWithObjects: + @"description", + @"distribution", + @"host", + @"key", + @"label", + @"name", + @"origin", + @"trusted", + @"type", + @"uri", + @"version", + nil]; } - (NSArray *) attributeKeys { @@ -1778,37 +1757,117 @@ static void PackageImport(const void *key, const void *value, void *context) { @end /* }}} */ -/* Relationship Class {{{ */ -@interface Relationship : NSObject { - NSString *type_; - NSString *id_; +/* CydiaOperation Class {{{ */ +@interface CydiaOperation : NSObject { + NSString *operator_; + NSString *value_; } -- (NSString *) type; -- (NSString *) id; -- (NSString *) name; +- (NSString *) operator; +- (NSString *) value; @end -@implementation Relationship +@implementation CydiaOperation - (void) dealloc { - [type_ release]; - [id_ release]; + [operator_ release]; + [value_ release]; [super dealloc]; } -- (NSString *) type { - return type_; +- (id) initWithOperator:(const char *)_operator value:(const char *)value { + if ((self = [super init]) != nil) { + operator_ = [[NSString alloc] initWithUTF8String:_operator]; + value_ = [[NSString alloc] initWithUTF8String:value]; + } return self; } -- (NSString *) id { - return id_; ++ (NSArray *) _attributeKeys { + return [NSArray arrayWithObjects: + @"operator", + @"value", + nil]; } -- (NSString *) name { - _assert(false); - return nil; +- (NSArray *) attributeKeys { + return [[self class] _attributeKeys]; +} + ++ (BOOL) isKeyExcludedFromWebScript:(const char *)name { + return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name]; +} + +- (NSString *) operator { + return operator_; +} + +- (NSString *) value { + return value_; +} + +@end +/* }}} */ +/* CydiaRelation Class {{{ */ +@interface CydiaRelation : NSObject { + NSString *relationship_; + NSString *package_; + CydiaOperation *version_; +} + +- (NSString *) relationship; +- (NSString *) package; +- (CydiaOperation *) version; + +@end + +@implementation CydiaRelation + +- (void) dealloc { + [relationship_ release]; + [package_ release]; + [version_ release]; + [super dealloc]; +} + +- (id) initWithIterator:(pkgCache::DepIterator &)dep { + if ((self = [super init]) != nil) { + relationship_ = [[NSString alloc] initWithUTF8String:dep.DepType()]; + package_ = [[NSString alloc] initWithUTF8String:dep.TargetPkg().Name()]; + + if (const char *version = dep.TargetVer()) + version_ = [[CydiaOperation alloc] initWithOperator:dep.CompType() value:version]; + else + version_ = [[NSNull null] retain]; + } return self; +} + ++ (NSArray *) _attributeKeys { + return [NSArray arrayWithObjects: + @"package", + @"relationship", + @"version", + nil]; +} + +- (NSArray *) attributeKeys { + return [[self class] _attributeKeys]; +} + ++ (BOOL) isKeyExcludedFromWebScript:(const char *)name { + return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name]; +} + +- (NSString *) relationship { + return relationship_; +} + +- (NSString *) package { + return package_; +} + +- (CydiaOperation *) version { + return version_; } @end @@ -2088,8 +2147,15 @@ struct PackageNameOrdering : } + (NSString *) webScriptNameForSelector:(SEL)selector { - if (selector == @selector(hasTag:)) + if (false); + else if (selector == @selector(clear)) + return @"clear"; + else if (selector == @selector(hasTag:)) return @"hasTag"; + else if (selector == @selector(install)) + return @"install"; + else if (selector == @selector(remove)) + return @"remove"; else return nil; } @@ -2099,7 +2165,33 @@ struct PackageNameOrdering : } + (NSArray *) _attributeKeys { - return [NSArray arrayWithObjects:@"applications", @"author", @"depiction", @"longDescription", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"longSection", @"maintainer", @"mode", @"name", @"purposes", @"section", @"shortDescription", @"shortSection", @"simpleSection", @"size", @"source", @"sponsor", @"support", @"warnings", nil]; + return [NSArray arrayWithObjects: + @"applications", + @"author", + @"depiction", + @"essential", + @"homepage", + @"icon", + @"id", + @"installed", + @"latest", + @"longDescription", + @"longSection", + @"maintainer", + @"mode", + @"name", + @"purposes", + @"relations", + @"section", + @"shortDescription", + @"shortSection", + @"simpleSection", + @"size", + @"source", + @"sponsor", + @"support", + @"warnings", + nil]; } - (NSArray *) attributeKeys { @@ -2110,6 +2202,31 @@ struct PackageNameOrdering : return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name]; } +- (NSArray *) relations { +@synchronized (database_) { + NSMutableArray *relations([NSMutableArray arrayWithCapacity:16]); + + for (pkgCache::DepIterator dep(version_.DependsList()); !dep.end(); ++dep) { + pkgCache::DepIterator start; + pkgCache::DepIterator end; + dep.GlobOr(start, end); // ++dep + + NSMutableArray *ors([NSMutableArray arrayWithCapacity:2]); + [relations addObject:ors]; + + _forever { + [ors addObject:[[[CydiaRelation alloc] initWithIterator:start] autorelease]]; + + // yes, seriously. (wtf?) + if (start == end) + break; + ++start; + } + } + + return relations; +} } + - (void) parse { if (parsed_ != NULL) return; @@ -2735,6 +2852,8 @@ struct PackageNameOrdering : if (range.location != NSNotFound) return YES; + [self parse]; + range = [[self shortDescription] rangeOfString:text options:MatchCompareOptions_]; if (range.location != NSNotFound) return YES; @@ -3041,7 +3160,7 @@ static NSString *Warning_; // XXX: actually implement this thing _assert(false); if (deadSources_) - CFRelease(deadSources_); + CFRelease(deadSources_); [self releasePackages]; apr_pool_destroy(pool_); NSRecycleZone(zone_); @@ -3238,70 +3357,11 @@ static NSString *Warning_; return sources; } -- (NSArray *) issues { - if (cache_->BrokenCount() == 0) - return nil; - - NSMutableArray *issues([NSMutableArray arrayWithCapacity:4]); - - for (Package *package in [self packages]) { - if (![package broken]) - continue; - pkgCache::PkgIterator pkg([package iterator]); - - NSMutableArray *entry([NSMutableArray arrayWithCapacity:4]); - [entry addObject:[package name]]; - [issues addObject:entry]; - - pkgCache::VerIterator ver(cache_[pkg].InstVerIter(cache_)); - if (ver.end()) - continue; - - for (pkgCache::DepIterator dep(ver.DependsList()); !dep.end(); ) { - pkgCache::DepIterator start; - pkgCache::DepIterator end; - dep.GlobOr(start, end); // ++dep - - if (!cache_->IsImportantDep(end)) - continue; - if ((cache_[end] & pkgDepCache::DepGInstall) != 0) - continue; - - NSMutableArray *failure([NSMutableArray arrayWithCapacity:4]); - [entry addObject:failure]; - [failure addObject:[NSString stringWithUTF8String:start.DepType()]]; - - NSString *name([NSString stringWithUTF8String:start.TargetPkg().Name()]); - if (Package *package = [self packageWithName:name]) - name = [package name]; - [failure addObject:name]; - - pkgCache::PkgIterator target(start.TargetPkg()); - if (target->ProvidesList != 0) - [failure addObject:@"?"]; - else { - pkgCache::VerIterator ver(cache_[target].InstVerIter(cache_)); - if (!ver.end()) - [failure addObject:[NSString stringWithUTF8String:ver.VerStr()]]; - else if (!cache_[target].CandidateVerIter(cache_).end()) - [failure addObject:@"-"]; - else if (target->ProvidesList == 0) - [failure addObject:@"!"]; - else - [failure addObject:@"%"]; - } - - _forever { - if (start.TargetVer() != 0) - [failure addObject:[NSString stringWithFormat:@"%s %s", start.CompType(), start.TargetVer()]]; - if (start == end) - break; - ++start; - } - } - } - - return issues; +- (Source *) sourceWithKey:(NSString *)key { + for (Source *source in [self sources]) { + if ([[source key] isEqualToString:key]) + return source; + } return nil; } - (bool) popErrorWithTitle:(NSString *)title { @@ -3375,7 +3435,7 @@ static NSString *Warning_; NSString *title(UCLocalize("DATABASE")); _trace(); - if (!cache_.Open(progress_, true)) { pop: + while (!cache_.Open(progress_, true)) { pop: std::string error; bool warning(!_error->PopMessage(error)); lprintf("cache_.Open():[%s]\n", error.c_str()); @@ -3385,15 +3445,17 @@ static NSString *Warning_; else if (error == "The package lists or status file could not be parsed or opened.") [delegate_ repairWithSelector:@selector(update)]; // else if (error == "Could not open lock file /var/lib/dpkg/lock - open (13 Permission denied)") - // else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)") + else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)") + [delegate_ _setProgressError:[NSString stringWithUTF8String:error.c_str()] withTitle:[NSString stringWithFormat:Colon_, Error_, title]]; // else if (error == "The list of sources could not be read.") - else + else { [delegate_ _setProgressError:[NSString stringWithUTF8String:error.c_str()] withTitle:[NSString stringWithFormat:Colon_, warning ? Warning_ : Error_, title]]; + return; + } if (warning) goto pop; _error->Discard(); - return; } _trace(); @@ -3506,12 +3568,11 @@ static NSString *Warning_; delete resolver_; resolver_ = new pkgProblemResolver(cache_); - for (pkgCache::PkgIterator iterator(cache_->PkgBegin()); !iterator.end(); ++iterator) { - if (!cache_[iterator].Keep()) { + for (pkgCache::PkgIterator iterator(cache_->PkgBegin()); !iterator.end(); ++iterator) + if (!cache_[iterator].Keep()) cache_->MarkKeep(iterator, false); + else if ((cache_[iterator].iFlags & pkgDepCache::ReInstall) != 0) cache_->SetReInstall(iterator, false); - } - } } } - (void) configure { @@ -3736,6 +3797,7 @@ static NSString *Warning_; } - (id) initWithDelegate:(IndirectDelegate *)indirect; + @end @implementation CydiaObject @@ -3756,7 +3818,13 @@ static NSString *Warning_; } + (NSArray *) _attributeKeys { - return [NSArray arrayWithObjects:@"device", @"firewire", @"imei", @"mac", @"serial", nil]; + return [NSArray arrayWithObjects: + @"device", + @"firewire", + @"imei", + @"mac", + @"serial", + nil]; } - (NSArray *) attributeKeys { @@ -3794,14 +3862,21 @@ static NSString *Warning_; #endif + (NSString *) webScriptNameForSelector:(SEL)selector { - if (selector == @selector(close)) + if (false); + else if (selector == @selector(close)) return @"close"; + else if (selector == @selector(du:)) + return @"du"; + else if (selector == @selector(stringWithFormat:arguments:)) + return @"format"; else if (selector == @selector(getInstalledPackages)) return @"getInstalledPackages"; else if (selector == @selector(getPackageById:)) return @"getPackageById"; else if (selector == @selector(installPackages:)) return @"installPackages"; + else if (selector == @selector(localizedStringForKey:value:table:)) + return @"localize"; else if (selector == @selector(setButtonImage:withStyle:toFunction:)) return @"setButtonImage"; else if (selector == @selector(setButtonTitle:withStyle:toFunction:)) @@ -3814,16 +3889,10 @@ static NSString *Warning_; return @"setToken"; else if (selector == @selector(setViewportWidth:)) return @"setViewportWidth"; - else if (selector == @selector(supports:)) - return @"supports"; - else if (selector == @selector(stringWithFormat:arguments:)) - return @"format"; - else if (selector == @selector(localizedStringForKey:value:table:)) - return @"localize"; - else if (selector == @selector(du:)) - return @"du"; else if (selector == @selector(statfs:)) return @"statfs"; + else if (selector == @selector(supports:)) + return @"supports"; else return nil; } @@ -3951,7 +4020,7 @@ static NSString *Warning_; id values[count]; for (unsigned i(0); i != count; ++i) values[i] = [arguments objectAtIndex:i]; - return [[[NSString alloc] initWithFormat:format arguments:*(reinterpret_cast(&values))] autorelease]; + return [[[NSString alloc] initWithFormat:format arguments:reinterpret_cast(values)] autorelease]; } - (NSString *) localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)table { @@ -3979,8 +4048,8 @@ static NSString *Warning_; @implementation CYLoadingIndicator -- (id)initWithFrame:(CGRect)frame { - if ((self = [super initWithFrame:frame])) { +- (id) initWithFrame:(CGRect)frame { + if ((self = [super initWithFrame:frame]) != nil) { container_ = [[[UIView alloc] init] autorelease]; [container_ setAutoresizingMask:UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin]; @@ -4019,32 +4088,74 @@ static NSString *Warning_; [spinner_ setFrame:spinrect]; [label_ setFrame:textrect]; [self addSubview:container_]; - } + } return self; +} - return self; +- (UILabel *) label { + return label_; } -- (UILabel *)label { return label_; } -- (UIActivityIndicatorView *)activityIndicatorView { return spinner_; } +- (UIActivityIndicatorView *) activityIndicatorView { + return spinner_; +} @end /* }}} */ /* Emulated Loading Controller {{{ */ -@interface CYEmulatedLoadingController : CYViewController { +@interface CYEmulatedLoadingController : CYViewController < + ProgressDelegate, + ConfigurationDelegate +> { + _transient Database *database_; CYLoadingIndicator *indicator_; UITabBar *tabbar_; UINavigationBar *navbar_; } + @end @implementation CYEmulatedLoadingController - (void) dealloc { [self releaseSubviews]; + [database_ setDelegate:nil]; [super dealloc]; } +- (void) setProgressError:(NSString *)error withTitle:(NSString *)title { + CYAlertView *sheet([[[CYAlertView alloc] + initWithTitle:title + buttons:[NSArray arrayWithObjects:UCLocalize("OKAY"), nil] + defaultButtonIndex:0 + ] autorelease]); + + [sheet setMessage:error]; + [sheet yieldToPopupAlertAnimated:YES]; + [sheet dismiss]; +} + +- (void) setProgressTitle:(NSString *)title { } +- (void) setProgressPercent:(float)percent { } +- (void) startProgress { } +- (void) addProgressOutput:(NSString *)output { } +- (bool) isCancelling:(size_t)received { return NO; } +- (void) setConfigurationData:(NSString *)data { } + +- (void) repairWithSelector:(SEL)selector { + [[indicator_ label] performSelectorOnMainThread:@selector(setText:) withObject:[NSString stringWithFormat:Elision_, UCLocalize("REPAIRING"), nil] waitUntilDone:YES]; + [database_ performSelector:selector]; + sleep(10); + [[indicator_ label] performSelectorOnMainThread:@selector(setText:) withObject:[NSString stringWithFormat:Elision_, UCLocalize("LOADING"), nil] waitUntilDone:YES]; +} + +- (id) initWithDatabase:(Database *)database { + if ((self = [super init]) != nil) { + database_ = database; + [database_ setDelegate:self]; + } return self; +} + - (void) loadView { [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]]; [[self view] setBackgroundColor:[UIColor pinStripeColor]]; @@ -4104,18 +4215,16 @@ static NSString *Warning_; WebDataSource *source([frame dataSource]); NSURLResponse *response([source response]); + NSURL *url([response URL]); NSString *scheme([url scheme]); - - NSHTTPURLResponse *http; - if (scheme != nil && ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"])) - http = (NSHTTPURLResponse *) response; - else - http = nil; - - NSDictionary *headers([http allHeaderFields]); NSString *host([url host]); - [self setHeaders:headers forHost:host]; + + if ([response isKindOfClass:[NSHTTPURLResponse class]]) { + NSHTTPURLResponse *http((NSHTTPURLResponse *) response); + NSDictionary *headers([http allHeaderFields]); + [self setHeaders:headers forHost:host]; + } if ( [host isEqualToString:@"cydia.saurik.com"] || @@ -4174,6 +4283,42 @@ static NSString *Warning_; @end /* }}} */ +// CydiaScript {{{ +@interface NSObject (CydiaScript) +- (id) Cydia$webScriptObjectInContext:(WebScriptObject *)context; +@end + +@implementation NSObject (CydiaScript) + +- (id) Cydia$webScriptObjectInContext:(WebScriptObject *)context { + return self; +} + +@end + +@implementation NSArray (CydiaScript) + +- (id) Cydia$webScriptObjectInContext:(WebScriptObject *)context { + WebScriptObject *object([context evaluateWebScript:@"[]"]); + for (size_t i(0), e([self count]); i != e; ++i) + [object setWebScriptValueAtIndex:i value:[[self objectAtIndex:i] Cydia$webScriptObjectInContext:context]]; + return object; +} + +@end + +@implementation NSDictionary (CydiaScript) + +- (id) Cydia$webScriptObjectInContext:(WebScriptObject *)context { + WebScriptObject *object([context evaluateWebScript:@"({})"]); + for (id i in self) + [object setValue:[[self objectForKey:i] Cydia$webScriptObjectInContext:context] forKey:i]; + return object; +} + +@end +// }}} + /* Confirmation Controller {{{ */ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if (!iterator.end()) @@ -4198,10 +4343,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @interface ConfirmationController : CYBrowserController { _transient Database *database_; + UIAlertView *essential_; - NSArray *changes_; - NSArray *issues_; - NSArray *sizes_; + + NSDictionary *changes_; + NSMutableArray *issues_; + NSDictionary *sizes_; + BOOL substrate_; } @@ -4213,11 +4361,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) dealloc { [changes_ release]; - if (issues_ != nil) - [issues_ release]; + [issues_ release]; [sizes_ release]; + if (essential_ != nil) [essential_ release]; + [super dealloc]; } @@ -4254,9 +4403,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) webView:(WebView *)view didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame { [super webView:view didClearWindowObject:window forFrame:frame]; - [window setValue:changes_ forKey:@"changes"]; - [window setValue:issues_ forKey:@"issues"]; - [window setValue:sizes_ forKey:@"sizes"]; + + [window setValue:[changes_ Cydia$webScriptObjectInContext:window] forKey:@"changes"]; + [window setValue:[issues_ Cydia$webScriptObjectInContext:window] forKey:@"issues"]; + [window setValue:[sizes_ Cydia$webScriptObjectInContext:window] forKey:@"sizes"]; + [window setValue:self forKey:@"queue"]; } @@ -4264,39 +4415,117 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if ((self = [super init]) != nil) { database_ = database; - [[self navigationItem] setTitle:UCLocalize("CONFIRM")]; - - NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16]; - NSMutableArray *reinstalling = [NSMutableArray arrayWithCapacity:16]; - NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16]; - NSMutableArray *downgrading = [NSMutableArray arrayWithCapacity:16]; - NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16]; + NSMutableArray *installs([NSMutableArray arrayWithCapacity:16]); + NSMutableArray *reinstalls([NSMutableArray arrayWithCapacity:16]); + NSMutableArray *upgrades([NSMutableArray arrayWithCapacity:16]); + NSMutableArray *downgrades([NSMutableArray arrayWithCapacity:16]); + NSMutableArray *removes([NSMutableArray arrayWithCapacity:16]); bool remove(false); + pkgCacheFile &cache([database_ cache]); + NSArray *packages([database_ packages]); pkgDepCache::Policy *policy([database_ policy]); - pkgCacheFile &cache([database_ cache]); - NSArray *packages = [database_ packages]; + issues_ = [[NSMutableArray arrayWithCapacity:4] retain]; + for (Package *package in packages) { - pkgCache::PkgIterator iterator = [package iterator]; + pkgCache::PkgIterator iterator([package iterator]); + NSString *name([package id]); + + if ([package broken]) { + NSMutableArray *reasons([NSMutableArray arrayWithCapacity:4]); + + [issues_ addObject:[NSDictionary dictionaryWithObjectsAndKeys: + name, @"package", + reasons, @"reasons", + nil]]; + + pkgCache::VerIterator ver(cache[iterator].InstVerIter(cache)); + if (ver.end()) + continue; + + for (pkgCache::DepIterator dep(ver.DependsList()); !dep.end(); ) { + pkgCache::DepIterator start; + pkgCache::DepIterator end; + dep.GlobOr(start, end); // ++dep + + if (!cache->IsImportantDep(end)) + continue; + if ((cache[end] & pkgDepCache::DepGInstall) != 0) + continue; + + _forever { + NSString *reason, *installed((NSString *) [WebUndefined undefined]); + + pkgCache::PkgIterator target(start.TargetPkg()); + if (target->ProvidesList != 0) + reason = @"missing"; + else { + pkgCache::VerIterator ver(cache[target].InstVerIter(cache)); + if (!ver.end()) { + reason = @"installed"; + installed = [NSString stringWithUTF8String:ver.VerStr()]; + } else if (!cache[target].CandidateVerIter(cache).end()) + reason = @"uninstalled"; + else if (target->ProvidesList == 0) + reason = @"uninstallable"; + else + reason = @"virtual"; + } + + NSDictionary *version(start.TargetVer() == 0 ? [NSNull null] : [NSDictionary dictionaryWithObjectsAndKeys: + [NSString stringWithUTF8String:start.CompType()], @"operator", + [NSString stringWithUTF8String:start.TargetVer()], @"value", + nil]); + + [reasons addObject:[NSDictionary dictionaryWithObjectsAndKeys: + [NSString stringWithUTF8String:start.DepType()], @"relation", + [NSString stringWithUTF8String:start.TargetPkg().Name()], @"package", + version, @"version", + reason, @"reason", + installed, @"installed", + nil]]; + + // yes, seriously. (wtf?) + if (start == end) + break; + ++start; + } + } + } + pkgDepCache::StateCache &state(cache[iterator]); - NSString *name([package name]); + static Pcre special_r("^(firmware$|gsc\\.|cy\\+)"); if (state.NewInstall()) - [installing addObject:name]; + [installs addObject:name]; else if (!state.Delete() && (state.iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall) - [reinstalling addObject:name]; + [reinstalls addObject:name]; else if (state.Upgrade()) - [upgrading addObject:name]; + [upgrades addObject:name]; else if (state.Downgrade()) - [downgrading addObject:name]; - else if (state.Delete()) { + [downgrades addObject:name]; + else if (!state.Delete()) + continue; + else if (special_r(name)) + [issues_ addObject:[NSDictionary dictionaryWithObjectsAndKeys: + [NSNull null], @"package", + [NSArray arrayWithObjects: + [NSDictionary dictionaryWithObjectsAndKeys: + @"Conflicts", @"relation", + name, @"package", + [NSNull null], @"version", + @"installed", @"reason", + nil], + nil], @"reasons", + nil]]; + else { if ([package essential]) remove = true; - [removing addObject:name]; - } else continue; + [removes addObject:name]; + } substrate_ |= DepSubstrate(policy->GetCandidateVer(iterator)); substrate_ |= DepSubstrate(iterator.CurrentVer()); @@ -4312,7 +4541,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { message:UCLocalize("REMOVING_ESSENTIALS_EX") delegate:self cancelButtonTitle:[NSString stringWithFormat:parenthetical, UCLocalize("CANCEL_OPERATION"), UCLocalize("SAFE")] - otherButtonTitles:[NSString stringWithFormat:parenthetical, UCLocalize("FORCE_REMOVAL"), UCLocalize("UNSAFE")], nil + otherButtonTitles: + [NSString stringWithFormat:parenthetical, UCLocalize("FORCE_REMOVAL"), UCLocalize("UNSAFE")], + nil ]; [essential_ setContext:@"remove"]; @@ -4328,28 +4559,23 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [essential_ setContext:@"unable"]; } - changes_ = [[NSArray alloc] initWithObjects: - installing, - reinstalling, - upgrading, - downgrading, - removing, + changes_ = [[NSDictionary alloc] initWithObjectsAndKeys: + installs, @"installs", + reinstalls, @"reinstalls", + upgrades, @"upgrades", + downgrades, @"downgrades", + removes, @"removes", nil]; - issues_ = [database_ issues]; - if (issues_ != nil) - issues_ = [issues_ retain]; - - sizes_ = [[NSArray alloc] initWithObjects: - SizeString([database_ fetcher].FetchNeeded()), - SizeString([database_ fetcher].PartialPresent()), + sizes_ = [[NSDictionary alloc] initWithObjectsAndKeys: + [NSNumber numberWithInteger:[database_ fetcher].FetchNeeded()], @"downloading", + [NSNumber numberWithInteger:[database_ fetcher].PartialPresent()], @"resuming", nil]; - [self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"confirm" ofType:@"html"]]]; + [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/confirm/", UI_]]]; [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:UCLocalize("CANCEL") - // OLD: [NSString stringWithFormat:UCLocalize("SLASH_DELIMITED"), UCLocalize("CANCEL"), UCLocalize("QUEUE")] style:UIBarButtonItemStylePlain target:self action:@selector(cancelButtonClicked) @@ -4357,21 +4583,19 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } return self; } +#if !AlwaysReload - (void) applyRightButton { -#if !AlwaysReload && !IgnoreInstall - if (issues_ == nil && ![self isLoading]) + if ([issues_ count] == 0 && ![self isLoading]) [[self navigationItem] setRightBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:UCLocalize("CONFIRM") - style:UIBarButtonItemStylePlain + style:UIBarButtonItemStyleDone target:self action:@selector(confirmButtonClicked) ] autorelease]]; else - [super applyRightButton]; -#else - [[self navigationItem] setRightBarButtonItem:nil]; -#endif + [[self navigationItem] setRightBarButtonItem:nil]; } +#endif - (void) cancelButtonClicked { [self dismissModalViewControllerAnimated:YES]; @@ -4380,9 +4604,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { #if !AlwaysReload - (void) confirmButtonClicked { -#if IgnoreInstall - return; -#endif if (essential_ != nil) [essential_ show]; else { @@ -4409,6 +4630,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (SEL) selector; - (id) target; - (id) object; + @end @implementation ProgressData @@ -4498,7 +4720,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { //[status_ setFont:font]; output_ = [[UITextView alloc] init]; - [output_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; //[output_ setTextFont:@"Courier New"]; [output_ setFont:[[output_ font] fontWithSize:12]]; @@ -4544,7 +4765,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { 10, 20, bounds.size.width - 20, - bounds.size.height - 62 + bounds.size.height - 96 )]; [close_ setFrame:CGRectMake( (bounds.size.width - closewidth) / 2, @@ -4562,7 +4783,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [self positionViews]; } -- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { +- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { [self positionViews]; } @@ -4754,7 +4975,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) setProgressError:(NSString *)error withTitle:(NSString *)title { - CYActionSheet *sheet([[[CYActionSheet alloc] + CYAlertView *sheet([[[CYAlertView alloc] initWithTitle:title buttons:[NSArray arrayWithObjects:UCLocalize("OKAY"), nil] defaultButtonIndex:0 @@ -4812,8 +5033,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { message:[NSString stringWithFormat:@"%@\n\n%@", UCLocalize("CONFIGURATION_UPGRADE_EX"), ofile] delegate:self cancelButtonTitle:UCLocalize("KEEP_OLD_COPY") - otherButtonTitles:UCLocalize("ACCEPT_NEW_COPY"), - // XXX: UCLocalize("SEE_WHAT_CHANGED"), + otherButtonTitles: + UCLocalize("ACCEPT_NEW_COPY"), + // XXX: UCLocalize("SEE_WHAT_CHANGED"), nil ] autorelease]; @@ -4998,18 +5220,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } return self; } -- (void) _setBackgroundColor { - UIColor *color; - if (NSString *mode = [package_ mode]) { - bool remove([mode isEqualToString:@"REMOVE"] || [mode isEqualToString:@"PURGE"]); - color = remove ? RemovingColor_ : InstallingColor_; - } else - color = [UIColor whiteColor]; - - [content_ setBackgroundColor:color]; - [self setNeedsDisplay]; -} - - (NSString *) accessibilityLabel { return [NSString stringWithFormat:UCLocalize("COLON_DELIMITED"), name_, description_]; } @@ -5060,11 +5270,36 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if ((badge_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/Purposes/%@.png", App_, purpose]]) != nil) badge_ = [badge_ retain]; - if ([package installed] != nil) - if ((placard_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/installed.png", App_]]) != nil) + UIColor *color; + NSString *placard; + + if (NSString *mode = [package_ mode]) { + if ([mode isEqualToString:@"REMOVE"] || [mode isEqualToString:@"PURGE"]) { + color = RemovingColor_; + //placard = @"removing"; + } else { + color = InstallingColor_; + //placard = @"installing"; + } + + // XXX: the removing/installing placards are not @2x + placard = nil; + } else { + color = [UIColor whiteColor]; + + if ([package installed] != nil) + placard = @"installed"; + else + placard = nil; + } + + [content_ setBackgroundColor:color]; + + if (placard != nil) + if ((placard_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/%@.png", App_, placard]]) != nil) placard_ = [placard_ retain]; - [self _setBackgroundColor]; + [self setNeedsDisplay]; [content_ setNeedsDisplay]; } @@ -5420,8 +5655,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { UIBarButtonItem *button_; } -- (id) initWithDatabase:(Database *)database; -- (void) setPackage:(Package *)package; +- (id) initWithDatabase:(Database *)database forPackage:(NSString *)name; @end @@ -5441,14 +5675,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [super dealloc]; } -- (void) release { - if ([self retainCount] == 1) - [delegate_ setPackageController:self]; - [super release]; -} - - (NSURL *) navigationURL { - return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://package/%@", [package_ id]]]; + return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://package/%@", name_]]; } /* XXX: this is not safe at all... localization of /fail/ */ @@ -5479,11 +5707,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } } -- (void) webView:(WebView *)view didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame { - [super webView:view didClearWindowObject:window forFrame:frame]; - [window setValue:package_ forKey:@"package"]; -} - - (bool) _allowJavaScriptPanel { return commercial_; } @@ -5544,33 +5767,28 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } #endif -- (id) initWithDatabase:(Database *)database { +- (id) initWithDatabase:(Database *)database forPackage:(NSString *)name { if ((self = [super init]) != nil) { database_ = database; buttons_ = [[NSMutableArray alloc] initWithCapacity:4]; - [self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"package" ofType:@"html"]]]; + name_ = [[NSString alloc] initWithString:name]; } return self; } -- (void) setPackage:(Package *)package { - if (package_ != nil) { - [package_ autorelease]; - package_ = nil; - } +- (void) reloadData { + [super reloadData]; - if (name_ != nil) { - [name_ release]; - name_ = nil; - } + if (package_ != nil) + [package_ autorelease]; + package_ = [database_ packageWithName:name_]; [buttons_ removeAllObjects]; - if (package != nil) { - [package parse]; + if (package_ != nil) { + [package_ parse]; - package_ = [package retain]; - name_ = [[package id] retain]; - commercial_ = [package isCommercial]; + package_ = [package_ retain]; + commercial_ = [package_ isCommercial]; if ([package_ mode] != nil) [buttons_ addObject:UCLocalize("CLEAR")]; @@ -5602,22 +5820,18 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { action:@selector(customButtonClicked) ]; - [self reloadURL]; + [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/package/#!/%@", UI_, name_]]]; } - (bool) isLoading { return commercial_ ? [super isLoading] : false; } -- (void) reloadData { - [self setPackage:[database_ packageWithName:name_]]; -} - @end /* }}} */ -/* Package Table {{{ */ -@interface PackageTable : UIView < +/* Package List Controller {{{ */ +@interface PackageListController : CYViewController < UITableViewDataSource, UITableViewDelegate > { @@ -5628,29 +5842,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { UITableView *list_; NSMutableArray *index_; NSMutableDictionary *indices_; - // XXX: this target_ seems to be delegate_. :( - _transient id target_; - SEL action_; - // XXX: why do we even have this delegate_? - _transient id delegate_; + NSString *title_; } -- (id) initWithFrame:(CGRect)frame database:(Database *)database target:(id)target action:(SEL)action; - +- (id) initWithDatabase:(Database *)database title:(NSString *)title; - (void) setDelegate:(id)delegate; - -- (void) reloadData; - (void) resetCursor; -- (UITableView *) list; - -- (void) setShouldHideHeaderInShortLists:(BOOL)hide; - -- (void) deselectWithAnimation:(BOOL)animated; - @end -@implementation PackageTable +@implementation PackageListController - (void) dealloc { [packages_ release]; @@ -5658,13 +5859,97 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [list_ release]; [index_ release]; [indices_ release]; + [title_ release]; [super dealloc]; } +- (void) deselectWithAnimation:(BOOL)animated { + [list_ deselectRowAtIndexPath:[list_ indexPathForSelectedRow] animated:animated]; +} + +- (void) resizeForKeyboardBounds:(CGRect)bounds duration:(NSTimeInterval)duration curve:(UIViewAnimationCurve)curve { + CGRect base = [[self view] bounds]; + base.size.height -= bounds.size.height; + base.origin = [list_ frame].origin; + + [UIView beginAnimations:nil context:NULL]; + [UIView setAnimationBeginsFromCurrentState:YES]; + [UIView setAnimationCurve:curve]; + [UIView setAnimationDuration:duration]; + [list_ setFrame:base]; + [UIView commitAnimations]; +} + +- (void) resizeForKeyboardBounds:(CGRect)bounds duration:(NSTimeInterval)duration { + [self resizeForKeyboardBounds:bounds duration:duration curve:UIViewAnimationCurveLinear]; +} + +- (void) resizeForKeyboardBounds:(CGRect)bounds { + [self resizeForKeyboardBounds:bounds duration:0]; +} + +- (void) keyboardWillShow:(NSNotification *)notification { + CGRect bounds; + CGPoint center; + NSTimeInterval duration; + UIViewAnimationCurve curve; + [[[notification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey] getValue:&bounds]; + [[[notification userInfo] objectForKey:UIKeyboardCenterEndUserInfoKey] getValue:¢er]; + [[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&curve]; + [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&duration]; + + CGRect kbframe = CGRectMake(round(center.x - bounds.size.width / 2.0), round(center.y - bounds.size.height / 2.0), bounds.size.width, bounds.size.height); + UIViewController *base = self; + while ([base parentViewController] != nil) + base = [base parentViewController]; + CGRect viewframe = [[base view] convertRect:[list_ frame] fromView:[list_ superview]]; + CGRect intersection = CGRectIntersection(viewframe, kbframe); + + [self resizeForKeyboardBounds:intersection duration:duration curve:curve]; +} + +- (void) keyboardWillHide:(NSNotification *)notification { + NSTimeInterval duration; + UIViewAnimationCurve curve; + [[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&curve]; + [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&duration]; + + [self resizeForKeyboardBounds:CGRectZero duration:duration curve:curve]; +} + +- (void) viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + [self resizeForKeyboardBounds:CGRectZero]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; +} + +- (void) viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + + [self resizeForKeyboardBounds:CGRectZero]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; +} + +- (void) viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + [self deselectWithAnimation:animated]; +} + +- (void) didSelectPackage:(Package *)package { + CYPackageController *view([[[CYPackageController alloc] initWithDatabase:database_ forPackage:[package id]] autorelease]); + [view setDelegate:delegate_]; + [[self navigationController] pushViewController:view animated:YES]; +} + +#if TryIndexedCollation + (BOOL) hasIndexedCollation { return NO; // XXX: objc_getClass("UILocalizedIndexedCollation") != nil; } +#endif - (NSInteger) numberOfSectionsInTableView:(UITableView *)list { NSInteger count([sections_ count]); @@ -5702,15 +5987,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return cell; } -- (void) deselectWithAnimation:(BOOL)animated { - [list_ deselectRowAtIndexPath:[list_ indexPathForSelectedRow] animated:animated]; -} - -- (NSIndexPath *) tableView:(UITableView *)table willSelectRowAtIndexPath:(NSIndexPath *)path { +- (void) tableView:(UITableView *)table didSelectRowAtIndexPath:(NSIndexPath *)path { Package *package([self packageAtIndexPath:path]); package = [database_ packageWithName:[package id]]; - [target_ performSelector:action_ withObject:package]; - return path; + [self didSelectPackage:package]; } - (NSArray *) sectionIndexTitlesForTableView:(UITableView *)tableView { @@ -5719,32 +5999,37 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (NSInteger) tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index { +#if TryIndexedCollation if ([[self class] hasIndexedCollation]) { return [[objc_getClass("UILocalizedIndexedCollation") currentCollation] sectionForSectionIndexTitleAtIndex:index]; } +#endif return index; } -- (id) initWithFrame:(CGRect)frame database:(Database *)database target:(id)target action:(SEL)action { - if ((self = [super initWithFrame:frame]) != nil) { +- (id) initWithDatabase:(Database *)database title:(NSString *)title { + if ((self = [super init]) != nil) { database_ = database; + title_ = [title copy]; + [[self navigationItem] setTitle:title_]; - target_ = target; - action_ = action; +#if TryIndexedCollation + if ([[self class] hasIndexedCollation]) + index_ = [[[objc_getClass("UILocalizedIndexedCollation") currentCollation] sectionIndexTitles] retain] + else +#endif + index_ = [[NSMutableArray alloc] initWithCapacity:32]; - index_ = [[self class] hasIndexedCollation] - ? [[[objc_getClass("UILocalizedIndexedCollation") currentCollation] sectionIndexTitles] retain] - : [[NSMutableArray alloc] initWithCapacity:32]; indices_ = [[NSMutableDictionary alloc] initWithCapacity:32]; packages_ = [[NSMutableArray arrayWithCapacity:16] retain]; sections_ = [[NSMutableArray arrayWithCapacity:16] retain]; - list_ = [[UITableView alloc] initWithFrame:[self bounds] style:UITableViewStylePlain]; + list_ = [[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStylePlain]; [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; [list_ setRowHeight:73]; - [self addSubview:list_]; + [[self view] addSubview:list_]; [list_ setDataSource:self]; [list_ setDelegate:self]; @@ -5760,6 +6045,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) reloadData { + [super reloadData]; + era_ = [database_ era]; NSArray *packages = [database_ packages]; @@ -5776,6 +6063,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { Section *section = nil; +#if TryIndexedCollation if ([[self class] hasIndexedCollation]) { id collation = [objc_getClass("UILocalizedIndexedCollation") currentCollation]; NSArray *titles = [collation sectionIndexTitles]; @@ -5806,7 +6094,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [section addToCount]; } _end - } else { + } else +#endif + { [index_ removeAllObjects]; _profile(PackageTable$reloadData$Section) @@ -5846,18 +6136,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [list_ scrollRectToVisible:CGRectMake(0, 0, 0, 0) animated:NO]; } -- (UITableView *) list { - return list_; -} - -- (void) setShouldHideHeaderInShortLists:(BOOL)hide { - //XXX:[list_ setShouldHideHeaderInShortLists:hide]; -} - @end /* }}} */ -/* Filtered Package Table {{{ */ -@interface FilteredPackageTable : PackageTable { +/* Filtered Package List Controller {{{ */ +@interface FilteredPackageListController : PackageListController { SEL filter_; IMP imp_; id object_; @@ -5866,11 +6148,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) setObject:(id)object; - (void) setObject:(id)object forFilter:(SEL)filter; -- (id) initWithFrame:(CGRect)frame database:(Database *)database target:(id)target action:(SEL)action filter:(SEL)filter with:(id)object; +- (id) initWithDatabase:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object; @end -@implementation FilteredPackageTable +@implementation FilteredPackageListController - (void) dealloc { if (object_ != nil) @@ -5908,104 +6190,26 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { _end } -- (id) initWithFrame:(CGRect)frame database:(Database *)database target:(id)target action:(SEL)action filter:(SEL)filter with:(id)object { - if ((self = [super initWithFrame:frame database:database target:target action:action]) != nil) { +- (id) initWithDatabase:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object { + if ((self = [super initWithDatabase:database title:title]) != nil) { [self setFilter:filter]; - object_ = [object retain]; + [self setObject:object]; [self reloadData]; } return self; } @end -/* }}} */ -/* Filtered Package Controller {{{ */ -@interface FilteredPackageController : CYViewController { - _transient Database *database_; - FilteredPackageTable *packages_; - NSString *title_; - SEL filter_; - id object_; -} - -- (id) initWithDatabase:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object; - -@end - -@implementation FilteredPackageController - -- (void) dealloc { - [self releaseSubviews]; - [title_ release]; - - [super dealloc]; -} - -- (void) viewDidAppear:(BOOL)animated { - [super viewDidAppear:animated]; - [packages_ deselectWithAnimation:animated]; -} - -- (void) didSelectPackage:(Package *)package { - CYPackageController *view([[[CYPackageController alloc] initWithDatabase:database_] autorelease]); - [view setPackage:package]; - [view setDelegate:delegate_]; - [[self navigationController] pushViewController:view animated:YES]; -} - -- (void) loadView { - [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]]; - - packages_ = [[FilteredPackageTable alloc] - initWithFrame:[[self view] bounds] - database:database_ - target:self - action:@selector(didSelectPackage:) - filter:filter_ - with:object_ - ]; - [packages_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; - [[self view] addSubview:packages_]; -} - -- (void) viewDidLoad { - [[self navigationItem] setTitle:title_]; -} - -- (void) releaseSubviews { - [packages_ release]; -} - -- (id) initWithDatabase:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object { - if ((self = [super init]) != nil) { - database_ = database; - title_ = [title copy]; - filter_ = filter; - object_ = object; - } return self; -} - -- (void) reloadData { - [super reloadData]; - [packages_ reloadData]; -} - -- (void) setDelegate:(id)delegate { - [super setDelegate:delegate]; - [packages_ setDelegate:delegate]; -} - -@end - /* }}} */ /* Home Controller {{{ */ @interface HomeController : CYBrowserController { } + @end @implementation HomeController -+ (BOOL)shouldHideNavigationBar { ++ (BOOL) shouldHideNavigationBar { return NO; } @@ -6032,7 +6236,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [alert setCancelButtonIndex:0]; [alert setMessage: - @"Copyright (C) 2008-2010\n" + @"Copyright (C) 2008-2011\n" "Jay Freeman (saurik)\n" "saurik@saurik.com\n" "http://www.saurik.com/" @@ -6041,13 +6245,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [alert show]; } -- (void) viewWillAppear:(BOOL)animated { - [super viewWillAppear:animated]; - - if ([[self class] shouldHideNavigationBar]) - [[self navigationController] setNavigationBarHidden:YES animated:animated]; -} - - (void) viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; @@ -6055,17 +6252,23 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [[self navigationController] setNavigationBarHidden:NO animated:animated]; } -- (id) init { - if ((self = [super init]) != nil) { - [self loadURL:[NSURL URLWithString:CydiaURL(@"")]]; +- (void) viewWillAppear:(BOOL)animated { + if (![self hasLoaded]) + [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/home/", UI_]]]; - [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc] - initWithTitle:UCLocalize("ABOUT") - style:UIBarButtonItemStylePlain - target:self - action:@selector(aboutButtonClicked) - ] autorelease]]; - } return self; + [super viewWillAppear:animated]; + + if ([[self class] shouldHideNavigationBar]) + [[self navigationController] setNavigationBarHidden:YES animated:animated]; +} + +- (void) viewDidLoad { + [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc] + initWithTitle:UCLocalize("ABOUT") + style:UIBarButtonItemStylePlain + target:self + action:@selector(aboutButtonClicked) + ] autorelease]]; } @end @@ -6075,6 +6278,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) queueStatusDidChange; + @end @implementation ManageController @@ -6083,21 +6287,22 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return [NSURL URLWithString:@"cydia://manage"]; } -- (id) init { - if ((self = [super init]) != nil) { - [[self navigationItem] setTitle:UCLocalize("MANAGE")]; +- (void) viewWillAppear:(BOOL)animated { + if (![self hasLoaded]) + [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/manage/", UI_]]]; - [self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"manage" ofType:@"html"]]]; + [super viewWillAppear:animated]; +} - [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc] - initWithTitle:UCLocalize("SETTINGS") - style:UIBarButtonItemStylePlain - target:self - action:@selector(settingsButtonClicked) - ] autorelease]]; +- (void) viewDidLoad { + [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc] + initWithTitle:UCLocalize("SETTINGS") + style:UIBarButtonItemStylePlain + target:self + action:@selector(settingsButtonClicked) + ] autorelease]]; - [self queueStatusDidChange]; - } return self; + [self queueStatusDidChange]; } - (void) settingsButtonClicked { @@ -6110,11 +6315,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) applyLoadingTitle { - // No "Loading" title. + // Disable "Loading" title. } - (void) applyRightButton { - // No right button. + // Disable right button. } #endif @@ -6134,6 +6339,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (bool) isLoading { + // Never show as loading. return false; } @@ -6187,14 +6393,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [prompt_ setFrame:prmrect]; } -- (void)setFrame:(CGRect)frame { +- (void) setFrame:(CGRect)frame { [super setFrame:frame]; - [self positionViews]; } - (id) initWithFrame:(CGRect)frame delegate:(id)delegate { - if ((self = [super initWithFrame:frame])) { + if ((self = [super initWithFrame:frame]) != nil) { [self setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; [self setBarStyle:UIBarStyleBlack]; @@ -6260,6 +6465,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { /* Cydia Tab Bar Controller {{{ */ @interface CYTabBarController : UITabBarController < + UITabBarControllerDelegate, ProgressDelegate > { _transient Database *database_; @@ -6271,9 +6477,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { _transient NSObject *updatedelegate_; id root_; + UIViewController *remembered_; + _transient UIViewController *transient_; } -- (NSArray *) navigationURLItems; +- (NSArray *) navigationURLCollection; - (void) dropBar:(BOOL)animated; - (void) beginUpdate; - (void) raiseBar:(BOOL)animated; @@ -6283,12 +6491,43 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @implementation CYTabBarController -- (NSArray *) navigationURLItems { +- (void) setUnselectedViewController:(UIViewController *)transient { + NSMutableArray *controllers = [[self viewControllers] mutableCopy]; + if (transient != nil) { + if (transient_ == nil) + remembered_ = [[controllers objectAtIndex:0] retain]; + transient_ = transient; + [transient_ setTabBarItem:[remembered_ tabBarItem]]; + [controllers replaceObjectAtIndex:0 withObject:transient_]; + [self setSelectedIndex:0]; + [self setViewControllers:controllers]; + [self concealTabBarSelection]; + } else if (remembered_ != nil) { + [remembered_ setTabBarItem:[transient_ tabBarItem]]; + transient_ = transient; + [controllers replaceObjectAtIndex:0 withObject:remembered_]; + [remembered_ release]; + remembered_ = nil; + [self setViewControllers:controllers]; + [self revealTabBarSelection]; + } +} + +- (UIViewController *) unselectedViewController { + return transient_; +} + +- (void) tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController { + if ([self unselectedViewController]) + [self setUnselectedViewController:nil]; +} + +- (NSArray *) navigationURLCollection { NSMutableArray *items([NSMutableArray array]); - // XXX:Deal with transient view controllers. + // XXX: Should this deal with transient view controllers? for (id navigation in [self viewControllers]) { - NSArray *stack = [navigation performSelector:@selector(navigationURLStack)]; + NSArray *stack = [navigation performSelector:@selector(navigationURLCollection)]; if (stack != nil) [items addObject:stack]; } @@ -6297,18 +6536,23 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) reloadData { - size_t count([[self viewControllers] count]); - for (size_t i(0); i != count; ++i) { - CYNavigationController *page([[self viewControllers] objectAtIndex:(count - i - 1)]); - [page reloadData]; - } + for (CYViewController *controller in [self viewControllers]) + [controller reloadData]; + + [(CYNavigationController *)[self unselectedViewController] reloadData]; +} + +- (void) dealloc { + [refreshbar_ release]; + [[NSNotificationCenter defaultCenter] removeObserver:self]; - [(CYNavigationController *)[self transientViewController] reloadData]; + [super dealloc]; } - (id) initWithDatabase:(Database *)database { if ((self = [super init]) != nil) { database_ = database; + [self setDelegate:self]; [[self view] setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarFrameChanged:) name:UIApplicationDidChangeStatusBarFrameNotification object:nil]; @@ -6530,12 +6774,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } } -- (void) dealloc { - [refreshbar_ release]; - [[NSNotificationCenter defaultCenter] removeObserver:self]; - [super dealloc]; -} - @end /* }}} */ /* Cydia Navigation Controller {{{ */ @@ -6544,7 +6782,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { _transient id delegate_; } -- (NSArray *) navigationURLStack; +- (NSArray *) navigationURLCollection; - (id) initWithDatabase:(Database *)database; - (void) reloadData; @@ -6553,11 +6791,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @implementation CYNavigationController -- (void) dealloc { - [super dealloc]; -} - -- (NSArray *) navigationURLStack { +- (NSArray *) navigationURLCollection { NSMutableArray *stack([NSMutableArray array]); for (CYViewController *controller in [self viewControllers]) { @@ -6570,10 +6804,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) reloadData { - size_t count([[self viewControllers] count]); - for (size_t i(0); i != count; ++i) { - CYViewController *page([[self viewControllers] objectAtIndex:(count - i - 1)]); - [page reloadData]; + for (CYViewController *page in [self viewControllers]) { + // Only reload controllers that have already loaded. + // This prevents a page from accidentally loading too + // early if it hasn't been shown on the screen yet. + if ([page hasLoaded]) + [page reloadData]; } } @@ -6692,7 +6928,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { /* }}} */ /* Section Controller {{{ */ -@interface SectionController : FilteredPackageController { +@interface SectionController : FilteredPackageListController { NSString *section_; } @@ -6712,18 +6948,15 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (id) initWithDatabase:(Database *)database section:(NSString *)name { NSString *title; - - if (name == nil) { + if (name == nil) title = UCLocalize("ALL_PACKAGES"); - } else if (![name isEqual:@""]) { + else if (![name isEqual:@""]) title = [[NSBundle mainBundle] localizedStringForKey:Simplify(name) value:nil table:@"Sections"]; - } else { + else title = UCLocalize("NO_SECTION"); - } - - section_ = name; if ((self = [super initWithDatabase:database title:title filter:@selector(isVisibleInSection:) with:name]) != nil) { + section_ = name; } return self; } @@ -6773,6 +7006,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } } +- (BOOL) isEditing { + return editing_; +} + - (void) setEditing:(BOOL)editing { if ((editing_ = editing)) [list_ reloadData]; @@ -6808,7 +7045,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *reuseIdentifier = @"SectionCell"; - SectionCell *cell = (SectionCell *) [tableView dequeueReusableCellWithIdentifier:reuseIdentifier]; + SectionCell *cell = (SectionCell *)[tableView dequeueReusableCellWithIdentifier:reuseIdentifier]; if (cell == nil) cell = [[[SectionCell alloc] initWithFrame:CGRectZero reuseIdentifier:reuseIdentifier] autorelease]; @@ -6882,7 +7119,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { section = [sections objectForKey:key]; if (section == nil) { _profile(SectionsView$reloadData$Section$Allocate) - section = [[[Section alloc] initWithName:name localize:YES] autorelease]; + section = [[[Section alloc] initWithName:key localize:YES] autorelease]; [sections setObject:section forKey:key]; _end } @@ -6918,8 +7155,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { _trace(); } -- (void)editButtonClicked { - [self setEditing:!editing_]; +- (void) editButtonClicked { + [self setEditing:(!editing_)]; } @end @@ -6957,6 +7194,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return [NSURL URLWithString:@"cydia://changes"]; } +- (void) viewWillAppear:(BOOL)animated { + // Loads after it appears, so don't load beforehand. + loaded_ = YES; + [super viewWillAppear:animated]; +} + - (void) viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; @@ -7012,9 +7255,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (NSIndexPath *) tableView:(UITableView *)table willSelectRowAtIndexPath:(NSIndexPath *)path { Package *package([self packageAtIndexPath:path]); - CYPackageController *view([[[CYPackageController alloc] initWithDatabase:database_] autorelease]); + CYPackageController *view([[[CYPackageController alloc] initWithDatabase:database_ forPackage:[package id]] autorelease]); [view setDelegate:delegate_]; - [view setPackage:package]; [[self navigationController] pushViewController:view animated:YES]; return path; } @@ -7052,9 +7294,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if ((self = [super init]) != nil) { database_ = database; - // We load after the view is visible, so don't "magically" load beforehand. - loaded_ = YES; - packages_ = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); sections_ = [[NSMutableArray arrayWithCapacity:16] retain]; } return self; @@ -7178,7 +7417,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @end /* }}} */ /* Search Controller {{{ */ -@interface SearchController : FilteredPackageController < +@interface SearchController : FilteredPackageListController < UISearchBarDelegate > { UISearchBar *search_; @@ -7199,7 +7438,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (NSURL *) navigationURL { - return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://search/%@", [search_ text]]]; + if ([search_ text] == nil || [[search_ text] isEqualToString:@""]) + return [NSURL URLWithString:@"cydia://search"]; + else + return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://search/%@", [search_ text]]]; } - (void) setSearchTerm:(NSString *)searchTerm { @@ -7208,13 +7450,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) searchBarSearchButtonClicked:(UISearchBar *)searchBar { - [packages_ setObject:[search_ text] forFilter:@selector(isUnfilteredAndSearchedForBy:)]; + [self setObject:[search_ text] forFilter:@selector(isUnfilteredAndSearchedForBy:)]; [search_ resignFirstResponder]; [self reloadData]; } - (void) searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)text { - [packages_ setObject:[search_ text] forFilter:@selector(isUnfilteredAndSelectedForBy:)]; + [self setObject:text forFilter:@selector(isUnfilteredAndSelectedForBy:)]; [self reloadData]; } @@ -7224,7 +7466,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } return self; } -- (void)viewDidAppear:(BOOL)animated { +- (void) viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; if (!searchloaded_) { @@ -7247,9 +7489,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) reloadData { - [packages_ setObject:[search_ text]]; + [self setObject:[search_ text]]; [super reloadData]; - [packages_ resetCursor]; + [self resetCursor]; } - (void) didSelectPackage:(Package *)package { @@ -7394,7 +7636,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (id) initWithDatabase:(Database *)database package:(NSString *)package { - if ((self = [super init])) { + if ((self = [super init]) != nil) { database_ = database; name_ = [package retain]; } return self; @@ -7415,51 +7657,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [table_ reloadData]; } -@end -/* }}} */ -/* Signature Controller {{{ */ -@interface SignatureController : CYBrowserController { - _transient Database *database_; - NSString *package_; -} - -- (id) initWithDatabase:(Database *)database package:(NSString *)package; - -@end - -@implementation SignatureController - -- (void) dealloc { - [package_ release]; - [super dealloc]; -} - -- (NSURL *) navigationURL { - return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://package/%@/signature", package_]]; -} - -- (void) webView:(WebView *)view didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame { - // XXX: dude! - [super webView:view didClearWindowObject:window forFrame:frame]; -} - -- (id) initWithDatabase:(Database *)database package:(NSString *)package { - if ((self = [super init]) != nil) { - database_ = database; - package_ = [package retain]; - [self reloadData]; - } return self; -} - -- (void) reloadData { - [self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"signature" ofType:@"html"]]]; -} - @end /* }}} */ /* Installed Controller {{{ */ -@interface InstalledController : FilteredPackageController { +@interface InstalledController : FilteredPackageListController { BOOL expert_; } @@ -7510,10 +7712,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { #endif } -- (void) reloadData { - [packages_ reloadData]; -} - - (void) updateRoleButton { if (Role_ != nil && ![Role_ isEqualToString:@"Developer"]) [[self navigationItem] setRightBarButtonItem:[[[UIBarButtonItem alloc] @@ -7525,18 +7723,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) roleButtonClicked { - [packages_ setObject:[NSNumber numberWithBool:expert_]]; - [packages_ reloadData]; + [self setObject:[NSNumber numberWithBool:expert_]]; + [self reloadData]; expert_ = !expert_; [self updateRoleButton]; } -- (void) setDelegate:(id)delegate { - [super setDelegate:delegate]; - [packages_ setDelegate:delegate]; -} - @end /* }}} */ @@ -7626,8 +7819,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @end /* }}} */ /* Source Controller {{{ */ -@interface SourceController : FilteredPackageController { - Source *source_; +@interface SourceController : FilteredPackageListController { + _transient Source *source_; + NSString *key_; } - (id) initWithDatabase:(Database *)database source:(Source *)source; @@ -7641,12 +7835,22 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (id) initWithDatabase:(Database *)database source:(Source *)source { - source_ = source; - if ((self = [super initWithDatabase:database title:[source label] filter:@selector(isVisibleInSource:) with:source]) != nil) { + source_ = source; + key_ = [[source key] retain]; } return self; } +- (void) reloadData { + source_ = [database_ sourceWithKey:key_]; + [key_ release]; + key_ = [[source_ key] retain]; + [self setObject:source_]; + [[self navigationItem] setTitle:[source_ label]]; + + [super reloadData]; +} + @end /* }}} */ /* Sources Controller {{{ */ @@ -7771,12 +7975,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [[self navigationController] pushViewController:controller animated:YES]; } -- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { +- (BOOL) tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { Source *source = [self sourceAtIndexPath:indexPath]; return [source record] != nil; } -- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { +- (void) tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { Source *source = [self sourceAtIndexPath:indexPath]; [Sources_ removeObjectForKey:[source key]]; [delegate_ syncData]; @@ -7841,7 +8045,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { message:warning delegate:self cancelButtonTitle:UCLocalize("CANCEL") - otherButtonTitles:UCLocalize("ADD_ANYWAY"), nil + otherButtonTitles: + UCLocalize("ADD_ANYWAY"), + nil ] autorelease]; [alert setContext:@"warning"]; @@ -7928,7 +8134,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease]; } -- (void)alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)button { +- (void) alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)button { NSString *context([alert context]); if ([context isEqualToString:@"source"]) { @@ -8046,7 +8252,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { message:nil delegate:self cancelButtonTitle:UCLocalize("CANCEL") - otherButtonTitles:UCLocalize("ADD_SOURCE"), nil + otherButtonTitles: + UCLocalize("ADD_SOURCE"), + nil ] autorelease]; [alert setContext:@"source"]; @@ -8179,7 +8387,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (id) initWithDatabase:(Database *)database delegate:(id)delegate { - if ((self = [super init])) { + if ((self = [super init]) != nil) { database_ = database; roledelegate_ = delegate; } return self; @@ -8271,7 +8479,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return 0; // :( } -- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { +- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { return nil; // This method is required by the protocol. } @@ -8309,6 +8517,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { UILabel *status_; UILabel *caption_; } + @end @implementation StashController @@ -8427,7 +8636,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { message:UCLocalize("HALFINSTALLED_PACKAGE_EX") delegate:self cancelButtonTitle:UCLocalize("FORCIBLY_CLEAR") - otherButtonTitles:UCLocalize("TEMPORARY_IGNORE"), nil + otherButtonTitles: + UCLocalize("TEMPORARY_IGNORE"), + nil ] autorelease]; [alert setContext:@"fixhalf"]; @@ -8440,7 +8651,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { message:UCLocalize("ESSENTIAL_UPGRADE_EX") delegate:self cancelButtonTitle:UCLocalize("TEMPORARY_IGNORE") - otherButtonTitles:UCLocalize("UPGRADE_ESSENTIAL"), UCLocalize("COMPLETE_UPGRADE"), nil + otherButtonTitles: + UCLocalize("UPGRADE_ESSENTIAL"), + UCLocalize("COMPLETE_UPGRADE"), + nil ] autorelease]; [alert setContext:@"upgrade"]; @@ -8509,8 +8723,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if (recently || loaded_ || ManualRefresh) { [self performSelectorOnMainThread:@selector(_loaded) withObject:nil waitUntilDone:NO]; - // If we are cancelling due to ManualRefresh or a recent refresh - // we need to make sure it knows it's already loaded. + // If we are cancelling, we need to make sure it knows it's already loaded. loaded_ = true; return; } else { @@ -8648,6 +8861,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (bool) perform { + // XXX: this is a really crappy way of doing this. + // like, seriously: this state machine is still broken, and cancelling this here doesn't really /fix/ that. + // for one, the user can still /start/ a reloading data event while they have a queue, which is stupid + // for two, this just means there is a race condition between the refresh completing and the confirmation controller appearing. + if ([tabbar_ updating]) + [tabbar_ cancelUpdate]; + if (![database_ prepare]) return false; @@ -8763,12 +8983,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [self setNetworkActivityIndicatorVisible:NO]; } -- (void) setPackageController:(CYPackageController *)view { - WebThreadLock(); - [view setPackage:nil]; - WebThreadUnlock(); -} - - (void) cancelAndClear:(bool)clear { @synchronized (self) { if (clear) { @@ -8786,7 +9000,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { NSString *context([alert context]); if ([context isEqualToString:@"fixhalf"]) { - if (button == [alert firstOtherButtonIndex]) { + if (button == [alert cancelButtonIndex]) { @synchronized (self) { for (Package *broken in broken_) { [broken remove]; @@ -8801,7 +9015,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [self resolve]; [self perform]; } - } else if (button == [alert cancelButtonIndex]) { + } else if (button == [alert firstOtherButtonIndex]) { [broken_ removeAllObjects]; [self _loaded]; } @@ -8889,20 +9103,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (CYViewController *) pageForPackage:(NSString *)name { - if (Package *package = [database_ packageWithName:name]) { - CYPackageController *view = [[[CYPackageController alloc] initWithDatabase:database_] autorelease]; - [view setPackage:package]; - return view; - } else { - NSURL *url([NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"unknown" ofType:@"html"]]); - url = [NSURL URLWithString:[[url absoluteString] stringByAppendingString:[NSString stringWithFormat:@"?%@", name]]]; - CYBrowserController *browser = [[[CYBrowserController alloc] init] autorelease]; - [browser loadURL:url]; - return browser; - } + return [[[CYPackageController alloc] initWithDatabase:database_ forPackage:name] autorelease]; } -- (CYViewController *) pageForURL:(NSURL *)url { +- (CYViewController *) pageForURL:(NSURL *)url forExternal:(BOOL)external { NSString *scheme([[url scheme] lowercaseString]); if ([[url absoluteString] length] <= [scheme length] + 3) return nil; @@ -8922,14 +9126,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if ([base isEqualToString:@"url"]) { // This kind of URL can contain slashes in the argument, so we can't parse them below. NSString *destination = [[url absoluteString] substringFromIndex:([scheme length] + [@"://" length] + [base length] + [@"/" length])]; - controller = [[[CYBrowserController alloc] init] autorelease]; - [(CYBrowserController *)controller loadURL:[NSURL URLWithString:destination]]; - } else if ([components count] == 1) { - if ([base isEqualToString:@"storage"]) { - controller = [[[CYBrowserController alloc] init] autorelease]; - [(CYBrowserController *)controller loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"storage" ofType:@"html"]]]; - } - + controller = [[[CYBrowserController alloc] initWithURL:[NSURL URLWithString:destination]] autorelease]; + } else if (!external && [components count] == 1) { if ([base isEqualToString:@"manage"]) { controller = [[[ManageController alloc] init] autorelease]; } @@ -8964,45 +9162,38 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { controller = [self pageForPackage:argument]; } - if ([base isEqualToString:@"search"]) { + if (!external && [base isEqualToString:@"search"]) { controller = [[[SearchController alloc] initWithDatabase:database_] autorelease]; [(SearchController *)controller setSearchTerm:argument]; } - if ([base isEqualToString:@"sections"]) { + if (!external && [base isEqualToString:@"sections"]) { if ([argument isEqualToString:@"all"]) argument = nil; controller = [[[SectionController alloc] initWithDatabase:database_ section:argument] autorelease]; } - if ([base isEqualToString:@"sources"]) { + if (!external && [base isEqualToString:@"sources"]) { if ([argument isEqualToString:@"add"]) { controller = [[[SourcesController alloc] initWithDatabase:database_] autorelease]; [(SourcesController *)controller showAddSourcePrompt]; } else { - NSArray *sources = [database_ sources]; - for (Source *source in sources) { - if ([[source name] caseInsensitiveCompare:argument] == NSOrderedSame) { - controller = [[[SourceController alloc] initWithDatabase:database_ source:source] autorelease]; - break; - } - } + Source *source = [database_ sourceWithKey:argument]; + controller = [[[SourceController alloc] initWithDatabase:database_ source:source] autorelease]; } } - if ([base isEqualToString:@"launch"]) { + if (!external && [base isEqualToString:@"launch"]) { [self launchApplicationWithIdentifier:argument suspended:NO]; return nil; } - } else if ([components count] == 3) { + } else if (!external && [components count] == 3) { NSString *arg1 = [components objectAtIndex:1]; NSString *arg2 = [components objectAtIndex:2]; if ([base isEqualToString:@"package"]) { if ([arg2 isEqualToString:@"settings"]) { controller = [[[PackageSettingsController alloc] initWithDatabase:database_ package:arg1] autorelease]; - } else if ([arg2 isEqualToString:@"signature"]) { - controller = [[[SignatureController alloc] initWithDatabase:database_ package:arg1] autorelease]; } else if ([arg2 isEqualToString:@"files"]) { if (Package *package = [database_ packageWithName:arg1]) { controller = [[[FileTable alloc] initWithDatabase:database_] autorelease]; @@ -9016,13 +9207,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return controller; } -- (BOOL) openCydiaURL:(NSURL *)url { - CYViewController *page([self pageForURL:url]); +- (BOOL) openCydiaURL:(NSURL *)url forExternal:(BOOL)external { + CYViewController *page([self pageForURL:url forExternal:external]); if (page != nil) { CYNavigationController *nav = [[[CYNavigationController alloc] init] autorelease]; [nav setViewControllers:[NSArray arrayWithObject:page]]; - [tabbar_ setTransientViewController:nav]; + [tabbar_ setUnselectedViewController:nav]; } return page != nil; @@ -9032,7 +9223,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [super applicationOpenURL:url]; if (!loaded_) starturl_ = [url retain]; - else [self openCydiaURL:url]; + else [self openCydiaURL:url forExternal:YES]; } - (void) applicationWillResignActive:(UIApplication *)application { @@ -9045,7 +9236,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) applicationWillTerminate:(UIApplication *)application { - [Metadata_ setObject:[tabbar_ navigationURLItems] forKey:@"InterfaceState"]; + Changed_ = true; + [Metadata_ setObject:[tabbar_ navigationURLCollection] forKey:@"InterfaceState"]; [Metadata_ setObject:[NSDate date] forKey:@"LastClosed"]; [Metadata_ setObject:[NSNumber numberWithInt:[tabbar_ selectedIndex]] forKey:@"InterfaceIndex"]; @@ -9086,7 +9278,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) setupViewControllers { tabbar_ = [[CYTabBarController alloc] initWithDatabase:database_]; - [tabbar_ setDelegate:self]; NSMutableArray *items([NSMutableArray arrayWithObjects: [[[UITabBarItem alloc] initWithTitle:@"Cydia" image:[UIImage applicationImageNamed:@"home.png"] tag:0] autorelease], @@ -9113,12 +9304,17 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [tabbar_ setUpdateDelegate:self]; } -- (CYEmulatedLoadingController *)showEmulatedLoadingControllerInView:(UIView *)view { - static CYEmulatedLoadingController *fake = [[CYEmulatedLoadingController alloc] init]; +- (CYEmulatedLoadingController *) showEmulatedLoadingControllerInView:(UIView *)view { + static CYEmulatedLoadingController *fake = nil; + if (view != nil) { + if (fake == nil) + fake = [[CYEmulatedLoadingController alloc] initWithDatabase:database_]; [view addSubview:[fake view]]; } else { [[fake view] removeFromSuperview]; + [fake release]; + fake = nil; } return fake; @@ -9222,10 +9418,16 @@ _trace(); recently = true; } - if (recently && [Metadata_ objectForKey:@"InterfaceState"]) { - items = [[Metadata_ objectForKey:@"InterfaceState"] mutableCopy]; - selectedIndex = [[Metadata_ objectForKey:@"InterfaceIndex"] intValue]; - } else { + items = [[Metadata_ objectForKey:@"InterfaceState"] mutableCopy]; + selectedIndex = [[Metadata_ objectForKey:@"InterfaceIndex"] intValue]; + + BOOL enough = YES; + for (NSArray *entry in items) + if ([entry count] <= 0) + enough = NO; + + if (!recently || !items || !enough) { + selectedIndex = 0; items = [NSMutableArray array]; [items addObject:[NSArray arrayWithObject:@"cydia://home"]]; [items addObject:[NSArray arrayWithObject:@"cydia://sections"]]; @@ -9248,7 +9450,7 @@ _trace(); for (unsigned int nav = 0; nav < [stack count]; nav++) { NSString *addr = [stack objectAtIndex:nav]; NSURL *url = [NSURL URLWithString:addr]; - CYViewController *page = [self pageForURL:url]; + CYViewController *page = [self pageForURL:url forExternal:NO]; if (page != nil) [current addObject:page]; } @@ -9258,7 +9460,7 @@ _trace(); // (Try to) show the startup URL. if (starturl_ != nil) { - [self openCydiaURL:starturl_]; + [self openCydiaURL:starturl_ forExternal:NO]; [starturl_ release]; starturl_ = nil; } @@ -9353,6 +9555,18 @@ int main(int argc, char *argv[]) { _pooled } else IsWildcat_ = false; + UIScreen *screen([UIScreen mainScreen]); + if ([screen respondsToSelector:@selector(scale)]) + ScreenScale_ = [screen scale]; + else + ScreenScale_ = 1; + + NSMutableArray *parts([NSMutableArray arrayWithCapacity:2]); + if (ScreenScale_ > 1) + [parts addObject:@"@2x"]; + [parts addObject:(IsWildcat_ ? @"~ipad" : @"~iphone")]; + UI_ = CydiaURL([NSString stringWithFormat:@"ui/ios%@", [parts componentsJoinedByString:@""]]); + PackageName = reinterpret_cast(method_getImplementation(class_getInstanceMethod([Package class], @selector(cyname)))); /* Library Hacks {{{ */ @@ -9551,11 +9765,15 @@ int main(int argc, char *argv[]) { _pooled _trace(); if (Packages_ != nil) { - CFDictionaryApplyFunction((CFDictionaryRef) Packages_, &PackageImport, NULL); + bool fail(false); + CFDictionaryApplyFunction((CFDictionaryRef) Packages_, &PackageImport, &fail); _trace(); - [Metadata_ removeObjectForKey:@"Packages"]; - Packages_ = nil; - Changed_ = true; + + if (!fail) { + [Metadata_ removeObjectForKey:@"Packages"]; + Packages_ = nil; + Changed_ = true; + } } Finishes_ = [NSArray arrayWithObjects:@"return", @"reopen", @"restart", @"reload", @"reboot", nil];