aboutsummaryrefslogtreecommitdiff
path: root/AppKit
diff options
context:
space:
mode:
authorGravatar gtm.daemon <gtm.daemon@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3>2010-06-02 17:36:03 +0000
committerGravatar gtm.daemon <gtm.daemon@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3>2010-06-02 17:36:03 +0000
commit0608b15caa35831a16aa7e5fd1490df24dd01784 (patch)
treed36c1f14713752cc077b6afe320c0e9123618293 /AppKit
parenta470905a1dffcc61761dc49be13c2d1c8761d0d1 (diff)
[Author: dmaclach]
Cleans up builds of GTM on Snow Leopard with gcc 4.2. Cleans up iPhone configs Adds libgcov for Snow Leopard Fixes up some small bugs. R=thomasvl DELTA=2028 (972 added, 990 deleted, 66 changed)
Diffstat (limited to 'AppKit')
-rw-r--r--AppKit/GTMCarbonEvent.m1
-rw-r--r--AppKit/GTMGetURLHandlerTest.m2
-rw-r--r--AppKit/GTMGoogleSearch.h144
-rw-r--r--AppKit/GTMGoogleSearch.m536
-rw-r--r--AppKit/GTMGoogleSearchTest.m208
-rw-r--r--AppKit/GTMHotKeyTextFieldTest.m8
-rw-r--r--AppKit/GTMNSImage+Scaling.h6
-rw-r--r--AppKit/GTMNSImage+ScalingTest.m20
-rw-r--r--AppKit/GTMNSImage+SearchCache.h2
-rw-r--r--AppKit/TestData/GTMUILocalizerAndLayoutTweakerTest4-0.10_4_SDK.10.6.tiffbin0 -> 30128 bytes
-rw-r--r--AppKit/TestData/GTMUILocalizerAndLayoutTweakerTest4-1.10_4_SDK.10.6.tiffbin0 -> 42058 bytes
-rw-r--r--AppKit/TestData/GTMUILocalizerAndLayoutTweakerTest4-2.10_4_SDK.10.6.tiffbin0 -> 28444 bytes
12 files changed, 919 insertions, 8 deletions
diff --git a/AppKit/GTMCarbonEvent.m b/AppKit/GTMCarbonEvent.m
index 479e49e..28bfdb9 100644
--- a/AppKit/GTMCarbonEvent.m
+++ b/AppKit/GTMCarbonEvent.m
@@ -17,6 +17,7 @@
//
#import "GTMCarbonEvent.h"
+#import <AppKit/AppKit.h>
#import "GTMObjectSingleton.h"
#import "GTMDebugSelectorValidation.h"
#import "GTMTypeCasting.h"
diff --git a/AppKit/GTMGetURLHandlerTest.m b/AppKit/GTMGetURLHandlerTest.m
index 940d90f..a639176 100644
--- a/AppKit/GTMGetURLHandlerTest.m
+++ b/AppKit/GTMGetURLHandlerTest.m
@@ -51,7 +51,7 @@ static BOOL sURLHandlerWasHit;
+ (BOOL)gtm_openURL:(NSURL*)url {
sURLHandlerWasHit = !sURLHandlerWasHit;
- return sURLHandlerWasHit;
+ return YES;
}
- (void)testURLCall {
diff --git a/AppKit/GTMGoogleSearch.h b/AppKit/GTMGoogleSearch.h
new file mode 100644
index 0000000..06b8d51
--- /dev/null
+++ b/AppKit/GTMGoogleSearch.h
@@ -0,0 +1,144 @@
+//
+// GTMGoogleSearch.h
+//
+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy
+// of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+//
+
+#import <Foundation/Foundation.h>
+
+// Key for Info.plist for default global search args
+#define GTMGoogleSearchClientAppArgsKey @"GTMGoogleSearchClientAppArgs"
+
+// Types to pass in to searchForURL:ofType:arguments
+// and performQuery:ofType:arguments
+#define GTMGoogleSearchFroogle @"products"
+#define GTMGoogleSearchGroups @"groups"
+#define GTMGoogleSearchImages @"images"
+#define GTMGoogleSearchLocal @"local"
+#define GTMGoogleSearchNews @"news"
+#define GTMGoogleSearchFinance @"finance"
+#define GTMGoogleSearchBooks @"books"
+#define GTMGoogleSearchWeb @"search"
+
+// iPhone doesn't support distributed notifications, so this controls whether
+// or not we enable them in this class.
+#define GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS GTM_MACOS_SDK
+
+// Composes URLs and searches for google properties in the correct language
+// and domain.
+@interface GTMGoogleSearch : NSObject {
+ // the cached values
+ NSString *allAppsCachedDomain_;
+ NSString *allAppsCachedLanguage_;
+ NSString *curAppCachedDomain_;
+ NSString *curAppCachedLanguage_;
+ NSDictionary *globalSearchArguments_;
+}
+
+//
+// +sharedInstance
+//
+// fetches the common shared object for accessing this users preference
+//
++ (GTMGoogleSearch*)sharedInstance;
+
+//
+// searchURLFor:ofType:arguments:
+//
+// creates a search url of type |type| for |queryText| using the user's
+// preferred domain and language settings. |args| is a set of arguments
+// that will be added into your query, and you can use it to complement
+// or override settings stored in globalSearchArguments.
+// example dictionary to do an I'm feeling lucky search would be:
+// [NSDictionary dictionaryWithObject:@"1" key:@"btnI"];
+// If queryText is nil, no query will be put in.
+// Arguments passed in in args must be properly URL escaped.
+// If you want to remove one of the arguments that will be included in the
+// global search arguments, set the object for the key you want to remove to
+// [NSNull null].
+- (NSString*)searchURLFor:(NSString *)queryText
+ ofType:(NSString *)type
+ arguments:(NSDictionary *)args;
+
+//
+// performQuery:ofType:arguments:
+//
+// Asks NSWorkspace to open up a query for an url created by passing
+// the args to searchURLFor:ofType:arguments: above.
+//
+- (BOOL)performQuery:(NSString *)queryText
+ ofType:(NSString *)type
+ arguments:(NSDictionary *)localArgs;
+
+// Global search arguments are initially picked up from your main bundle
+// info.plist if there is a dictionary entry at the top level with the key
+// "GTMGoogleSearchClientAppArgs". This dictionary should be a map of strings
+// to strings where they are the args you want passed to all Google searches.
+// You can override these with your localArgs when you actually perform the
+// search if you wish.
+// This arguments will affect all searches. Arguments must be properly URL
+// escaped.
+- (void)setGlobalSearchArguments:(NSDictionary *)args;
+
+// Returns the global search arguments.
+- (NSDictionary *)globalSearchArguments;
+
+//
+// -preferredDomainAndLanguage:areCurrentAppOnly
+//
+// fetches the user's preferred domain and language, and whether the values
+// that were grabbed were from the anyapplication domain, or from the current
+// application domain. You may pass in nil for |language| if you don't want
+// a language back, and you may pass in NULL for |currentAppOnly| if you don't
+// care about where it came from.
+//
+- (void)preferredDomain:(NSString **)domain
+ language:(NSString **)language
+ areCurrentAppOnly:(BOOL*)currentAppOnly;
+
+//
+// -updatePreferredDomain:language:currentApplicationOnly:
+//
+// updated the users preferred domain and language to copies of |domain| and
+// |language| respectively. |domain| can't be nil or an empty string, but
+// |language| can't be nil, but can be an empty string to signify no language
+// pref. If |currentAppOnly| is YES, only updates the preferred settings for the
+// current app, otherwise updates them for all apps.
+//
+- (void)updatePreferredDomain:(NSString *)domain
+ language:(NSString *)language
+ currentApplicationOnly:(BOOL)currentAppOnly;
+
+//
+// -clearPreferredDomainAndLanguageForCurrentApplication
+//
+// clears the setting for the current applications preferred domain and
+// language so future fetches will get the system level ones.
+//
+- (void)clearPreferredDomainAndLanguageForCurrentApplication;
+
+//
+// -clearPreferredDomainAndLanguageForAllApps
+//
+// clears the "AllApps" setting for preferred domain and language so future
+// fetches end up having to use the default. Odds are this is only
+// used by the unittests.
+// NOTE: this doesn't do anything to any setting that's set in an individual
+// apps preferences, so those settings will still override inplace of the
+// "all apps" value (or default).
+//
+- (void)clearPreferredDomainAndLanguageForAllApps;
+
+@end
diff --git a/AppKit/GTMGoogleSearch.m b/AppKit/GTMGoogleSearch.m
new file mode 100644
index 0000000..9eb095f
--- /dev/null
+++ b/AppKit/GTMGoogleSearch.m
@@ -0,0 +1,536 @@
+//
+// GTMGoogleSearch.m
+//
+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy
+// of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+//
+
+#import "GTMGoogleSearch.h"
+#import "GTMObjectSingleton.h"
+#import "GTMGarbageCollection.h"
+
+#if GTM_IPHONE_SDK
+#import <UIKit/UIKit.h>
+#else
+#import <AppKit/AppKit.h>
+#endif // GTM_IPHONE_SDK
+
+typedef struct {
+ NSString *language;
+ NSString *country;
+ // we don't include a language, we'll use what we get from the OS
+ NSString *defaultDomain;
+} LanguageDefaultInfo;
+
+//
+// this is a seed mapping from languages to domains for google search.
+// this doesn't have to be complete, as it is just a seed.
+//
+//
+static LanguageDefaultInfo kLanguageListDefaultMappingTable[] = {
+ // order is important, first match is taken
+ // if country is |nil|, then only language has to match
+ { @"en", @"US", @"com" }, // english - united states
+ { @"en", @"GB", @"co.uk" }, // english - united kingdom
+ { @"en", @"CA", @"ca" }, // english - canada
+ { @"en", @"AU", @"com.au" }, // english - australia
+ { @"en", @"NZ", @"com" }, // english - new zealand
+ { @"en", @"IE", @"ie" }, // english - ireland
+ { @"en", @"IN", @"co.in" }, // english - india
+ { @"en", @"PH", @"com.ph" }, // english - philippines
+ { @"en", @"SG", @"com.sg" }, // english - singapore
+ { @"en", @"ZA", @"co.za" }, // english - south africa
+ { @"en", @"IL", @"co.il" }, // english - israel
+ { @"en", nil , @"com" }, // english (catch all)
+ { @"fr", @"CA", @"ca" }, // french - canada
+ { @"fr", @"CH", @"ch" }, // french - switzerland
+ { @"fr", nil , @"fr" }, // france
+ { @"it", nil , @"it" }, // italy
+ { @"de", @"AT", @"at" }, // german - austria
+ { @"de", nil , @"de" }, // germany
+ { @"es", @"MX", @"com.mx" }, // spanish - mexico
+ { @"es", @"AR", @"com.ar" }, // spanish - argentina
+ { @"es", @"CL", @"cl" }, // spanish - chile
+ { @"es", @"CO", @"com.co" }, // spanish - colombia
+ { @"es", @"PE", @"com.pe" }, // spanish - peru
+ { @"es", @"VE", @"co.ve" }, // venezuela
+ { @"es", nil , @"es" }, // spain
+ { @"zh", @"TW", @"com.tw" }, // taiwan
+ { @"zh", @"HK", @"com.hk" }, // hong kong
+ { @"zh", nil , @"cn" }, // chinese (catch all)
+ { @"ja", nil , @"co.jp" }, // japan
+ { @"ko", nil , @"co.kr" }, // korea
+ { @"nl", @"BE", @"be" }, // dutch - belgium
+ { @"nl", nil , @"nl" }, // (dutch) netherlands
+ { @"ru", nil , @"ru" }, // russia
+ { @"pt", @"BZ", @"com.br"}, // portuguese - brazil
+ { @"pt", nil , @"pt" }, // portugal
+ { @"sv", nil , @"se" }, // sweden
+ { @"nn", nil , @"no" }, // norway (two variants)
+ { @"nb", nil , @"no" }, // norway (two variants)
+ { @"da", nil , @"dk" }, // denmark
+ { @"fi", nil , @"fi" }, // finland
+ { @"bg", nil , @"bg" }, // bulgaria
+ { @"hr", nil , @"hr" }, // croatia
+ { @"cx", nil , @"cz" }, // czech republic
+ { @"el", nil , @"gr" }, // greece
+ { @"hu", nil , @"co.hu" }, // hungary
+ { @"ro", nil , @"ro" }, // romania
+ { @"sk", nil , @"sk" }, // slovakia
+ { @"sl", nil , @"si" }, // slovenia
+ { @"tr", nil , @"com.tr" }, // turkey
+ { @"my", nil , @"com.my" }, // malaysia
+ { @"th", nil , @"co.th" }, // thailand
+ { @"uk", nil , @"com.ua" }, // ukraine
+ { @"vi", nil , @"com.vn" }, // vietnam
+ { @"af", nil , @"com.za" }, // south africa (afrikaans)
+ { @"hi", nil , @"co.in" }, // india (hindi)
+ { @"id", nil , @"co.id" }, // indonesia
+ { @"pl", nil , @"pl" }, // poland
+};
+
+// the notification we use for syncing up instances in different processes
+static NSString *const kNotificationName
+ = @"com.google.GoogleSearchAllApps.prefsWritten";
+
+// this is the bundle id we use for the pref file used for all apps
+static CFStringRef const kAllAppsBuildIdentifier
+ = CFSTR("com.google.GoogleSearchAllApps");
+
+static CFStringRef const kPreferredDomainPrefKey
+ = CFSTR("com.google.PreferredDomain");
+static CFStringRef const kPreferredLanguagePrefKey
+ = CFSTR("com.google.PreferredLanguage");
+
+static NSString *const kDefaultDomain = @"com";
+static NSString *const kDefaultLanguage = @"en";
+
+#define SEARCH_URL_TEMPLATE @"http://www.google.%@/%@?%@"
+
+@interface GTMGoogleSearch (PrivateMethods)
+- (void)defaultDomain:(NSString**)preferedDomain
+ language:(NSString**)preferredLanguage;
+- (void)reloadAllAppCachedValues:(NSNotification*)notification;
+- (void)updateAllAppsDomain:(NSString*)domain language:(NSString*)language;
+@end
+
+
+@implementation GTMGoogleSearch
+
+GTMOBJECT_SINGLETON_BOILERPLATE(GTMGoogleSearch, sharedInstance);
+
+- (id)init {
+ self = [super init];
+ if (self != nil) {
+#if GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS
+ // register for the notification
+ NSDistributedNotificationCenter *distCenter =
+ [NSDistributedNotificationCenter defaultCenter];
+ [distCenter addObserver:self
+ selector:@selector(reloadAllAppCachedValues:)
+ name:kNotificationName
+ object:nil];
+#endif // GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS
+ // load the allApps value
+ [self reloadAllAppCachedValues:nil];
+
+ // load the cur app value
+ CFStringRef domain
+ = CFPreferencesCopyValue(kPreferredDomainPrefKey,
+ kCFPreferencesCurrentApplication,
+ kCFPreferencesCurrentUser,
+ kCFPreferencesAnyHost);
+ CFStringRef lang = CFPreferencesCopyValue(kPreferredLanguagePrefKey,
+ kCFPreferencesCurrentApplication,
+ kCFPreferencesCurrentUser,
+ kCFPreferencesAnyHost);
+
+ // make sure we got values for both and domain is not empty
+ if (domain && CFStringGetLength(domain) == 0) {
+ CFRelease(domain);
+ domain = nil;
+ if (lang) {
+ CFRelease(lang);
+ lang = nil;
+ }
+ }
+
+ curAppCachedDomain_ = GTMNSMakeCollectable(domain);
+ curAppCachedLanguage_ = GTMNSMakeCollectable(lang);
+
+ NSBundle *bundle = [NSBundle mainBundle];
+
+ NSDictionary *appArgs
+ = [bundle objectForInfoDictionaryKey:GTMGoogleSearchClientAppArgsKey];
+ globalSearchArguments_ = [appArgs retain];
+ }
+ return self;
+}
+
+#if GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS
+- (void)finalize {
+ [[NSDistributedNotificationCenter defaultCenter] removeObject:self];
+ [super finalize];
+}
+#endif // GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS
+
+- (void)dealloc {
+#if GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS
+ [[NSDistributedNotificationCenter defaultCenter] removeObject:self];
+#endif // GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS
+ [allAppsCachedDomain_ release];
+ [allAppsCachedLanguage_ release];
+ [curAppCachedDomain_ release];
+ [curAppCachedLanguage_ release];
+ [globalSearchArguments_ release];
+ [super dealloc];
+}
+
+- (void)preferredDomain:(NSString **)domain
+ language:(NSString**)language
+ areCurrentAppOnly:(BOOL*)currentAppOnly {
+ BOOL localCurrentAppOnly = YES;
+ NSString *localDomain = curAppCachedDomain_;
+ NSString *localLanguage = curAppCachedLanguage_;
+
+ // if either one wasn't there, drop both, and use any app if we can
+ if (!localDomain || !localLanguage) {
+ localCurrentAppOnly = NO;
+ localDomain = allAppsCachedDomain_;
+ localLanguage = allAppsCachedLanguage_;
+
+ // if we didn't get anything from the prefs, go with the defaults
+ if (!localDomain || !localLanguage) {
+ // if either one wasn't there, drop both, and use defaults
+ [self defaultDomain:&localDomain language:&localLanguage];
+ }
+ }
+ if (!localDomain || !localLanguage) {
+ _GTMDevLog(@"GTMGoogleSearch: Failed to get the preferred domain/language "
+ @"from prefs or defaults");
+ }
+ if (language) {
+ *language = [[localLanguage retain] autorelease];
+ }
+ if (domain) {
+ *domain = [[localDomain retain] autorelease];
+ }
+ if (currentAppOnly) {
+ *currentAppOnly = localCurrentAppOnly;
+ }
+}
+
+- (void)updatePreferredDomain:(NSString*)domain
+ language:(NSString*)language
+ currentApplicationOnly:(BOOL)currentAppOnly {
+ // valid inputs?
+ if (!domain || ![domain length] || !language) {
+ return;
+ }
+
+ if (currentAppOnly) {
+ // if they are the same, don't do anything
+ if ((domain == nil && curAppCachedDomain_ == nil &&
+ language == nil && curAppCachedLanguage_ == nil) ||
+ ([domain isEqualToString:curAppCachedDomain_] &&
+ [language isEqualToString:curAppCachedLanguage_])) {
+ return;
+ }
+
+ // save them out
+ CFPreferencesSetValue(kPreferredDomainPrefKey,
+ (CFStringRef)domain,
+ kCFPreferencesCurrentApplication,
+ kCFPreferencesCurrentUser,
+ kCFPreferencesAnyHost);
+ CFPreferencesSetValue(kPreferredLanguagePrefKey,
+ (CFStringRef)language,
+ kCFPreferencesCurrentApplication,
+ kCFPreferencesCurrentUser,
+ kCFPreferencesAnyHost);
+ CFPreferencesSynchronize(kCFPreferencesCurrentApplication,
+ kCFPreferencesCurrentUser,
+ kCFPreferencesAnyHost);
+ // update our locals
+ [curAppCachedDomain_ release];
+ [curAppCachedLanguage_ release];
+ curAppCachedDomain_ = [domain copy];
+ curAppCachedLanguage_ = [language copy];
+ } else {
+ // Set the "any application" values
+ [self updateAllAppsDomain:domain language:language];
+
+ // Clear the current application values (if there were any)
+ [self clearPreferredDomainAndLanguageForCurrentApplication];
+ }
+}
+
+- (void)clearPreferredDomainAndLanguageForCurrentApplication {
+ // flush what's in the file
+ CFPreferencesSetValue(kPreferredDomainPrefKey,
+ NULL,
+ kCFPreferencesCurrentApplication,
+ kCFPreferencesCurrentUser,
+ kCFPreferencesAnyHost);
+ CFPreferencesSetValue(kPreferredLanguagePrefKey,
+ NULL,
+ kCFPreferencesCurrentApplication,
+ kCFPreferencesCurrentUser,
+ kCFPreferencesAnyHost);
+ CFPreferencesSynchronize(kCFPreferencesCurrentApplication,
+ kCFPreferencesCurrentUser,
+ kCFPreferencesAnyHost);
+ // clear our locals
+ [curAppCachedDomain_ release];
+ [curAppCachedLanguage_ release];
+ curAppCachedDomain_ = nil;
+ curAppCachedLanguage_ = nil;
+}
+
+- (void)clearPreferredDomainAndLanguageForAllApps {
+ // nil/nil to clear things out, this will also update our cached values.
+ [self updateAllAppsDomain:nil language:nil];
+}
+
+- (NSDictionary *)globalSearchArguments {
+ return globalSearchArguments_;
+}
+
+- (void)setGlobalSearchArguments:(NSDictionary *)args {
+ [globalSearchArguments_ autorelease];
+ globalSearchArguments_ = [args copy];
+}
+
+- (NSString*)searchURLFor:(NSString*)queryText
+ ofType:(NSString*)type
+ arguments:(NSDictionary *)localArgs {
+ if (!type) {
+ return nil;
+ }
+
+ NSString *language;
+ NSString *domain;
+ [self preferredDomain:&domain
+ language:&language
+ areCurrentAppOnly:NULL];
+
+ NSMutableDictionary *args
+ = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ @"UTF-8", @"ie",
+ @"UTF-8", @"oe",
+ language, @"hl",
+ nil];
+ if (queryText) {
+ [args setObject:queryText forKey:@"q"];
+ }
+
+ NSDictionary *globalSearchArgs = [self globalSearchArguments];
+ if (globalSearchArgs) {
+ [args addEntriesFromDictionary:globalSearchArgs];
+ }
+ if (localArgs) {
+ [args addEntriesFromDictionary:localArgs];
+ }
+
+ NSMutableArray *clientArgs = [NSMutableArray array];
+ NSString *key;
+ NSNull *nsNull = [NSNull null];
+ GTM_FOREACH_KEY(key, args) {
+ NSString *object = [args objectForKey:key];
+ if (![object isEqual:nsNull]) {
+#if DEBUG
+ // In debug we check key and object for things that should be escaped.
+ // Note that percent is not in there because escaped strings will have
+ // percents in them
+ NSCharacterSet *cs = [NSCharacterSet characterSetWithCharactersInString:
+ @"!*'();:@&=+$,/?#[] "];
+ NSRange range = [key rangeOfCharacterFromSet:cs];
+ if (range.location != NSNotFound) {
+ _GTMDevLog(@"Unescaped string %@ in argument pair {%@, %@} in -[%@ %@]",
+ key, key, object, [self class], NSStringFromSelector(_cmd));
+ }
+ range = [object rangeOfCharacterFromSet:cs];
+ if (range.location != NSNotFound) {
+ _GTMDevLog(@"Unescaped string %@ in argument pair {%@,%@ } in -[%@ %@]",
+ object, key, object, [self class],
+ NSStringFromSelector(_cmd));
+ }
+#endif // DEBUG
+ NSString *arg = [NSString stringWithFormat:@"%@=%@", key, object];
+ [clientArgs addObject:arg];
+ }
+ }
+ NSString *clientArg = [clientArgs componentsJoinedByString:@"&"];
+ NSString *url = [NSString stringWithFormat:SEARCH_URL_TEMPLATE,
+ domain, type, clientArg];
+ return url;
+}
+
+- (BOOL)performQuery:(NSString*)queryText
+ ofType:(NSString *)type
+ arguments:(NSDictionary *)localArgs {
+ BOOL success = NO;
+ NSString *urlString = [self searchURLFor:queryText
+ ofType:type
+ arguments:localArgs];
+ if (urlString) {
+ NSURL *url = [NSURL URLWithString:urlString];
+ if (url) {
+#if GTM_IPHONE_SDK
+ success = [[UIApplication sharedApplication] openURL:url];
+#else // GTM_IPHONE_SDK
+ success = [[NSWorkspace sharedWorkspace] openURL:url];
+#endif // GTM_IPHONE_SDK
+ }
+ }
+ return success;
+}
+
+@end
+
+
+@implementation GTMGoogleSearch (PrivateMethods)
+
+- (void)defaultDomain:(NSString**)preferredDomain
+ language:(NSString**)preferredLanguage {
+ // must have both
+ if (!preferredDomain || !preferredLanguage) {
+ return;
+ }
+
+ // make sure they are clear to start
+ *preferredDomain = nil;
+ *preferredLanguage = nil;
+
+ // loop over their language list trying to find something we have in
+ // out default table.
+
+ NSUserDefaults* defs = [NSUserDefaults standardUserDefaults];
+ NSArray* languages = [defs objectForKey:@"AppleLanguages"];
+ // the current locale is only based on what languages the running apps is
+ // localized to, so we stick that at the end in case we weren't able to
+ // find anything else as a match, we'll match that.
+ languages =
+ [languages arrayByAddingObject:[[NSLocale currentLocale] localeIdentifier]];
+
+ NSEnumerator *enumerator = [languages objectEnumerator];
+ NSString *localeIdentifier;
+ while ((localeIdentifier = [enumerator nextObject])) {
+ NSDictionary *localeParts
+ = [NSLocale componentsFromLocaleIdentifier:localeIdentifier];
+ NSString *localeLanguage = [localeParts objectForKey:NSLocaleLanguageCode];
+ // we don't use NSLocaleScriptCode for now
+ NSString *localeCountry = [localeParts objectForKey:NSLocaleCountryCode];
+
+ LanguageDefaultInfo *scan = kLanguageListDefaultMappingTable;
+ LanguageDefaultInfo *end = (scan + (sizeof(kLanguageListDefaultMappingTable)
+ / sizeof(LanguageDefaultInfo)));
+ // find a match
+ // check language, and if country is not nil, check that
+ for ( ; scan < end ; ++scan) {
+ if ([localeLanguage isEqualToString:scan->language] &&
+ (!(scan->country) || [localeCountry isEqualToString:scan->country])) {
+ *preferredDomain = scan->defaultDomain;
+ *preferredLanguage = localeLanguage;
+ return; // out of here
+ }
+ }
+ }
+
+ *preferredDomain = kDefaultDomain;
+ *preferredLanguage = kDefaultLanguage;
+}
+
+// -reloadAllAppCachedValues:
+//
+- (void)reloadAllAppCachedValues:(NSNotification*)notification {
+ // drop the old...
+ [allAppsCachedDomain_ release];
+ [allAppsCachedLanguage_ release];
+ allAppsCachedDomain_ = nil;
+ allAppsCachedLanguage_ = nil;
+
+ // load the new
+ CFPreferencesSynchronize(kAllAppsBuildIdentifier,
+ kCFPreferencesCurrentUser,
+ kCFPreferencesAnyHost);
+ CFStringRef domain = CFPreferencesCopyValue(kPreferredDomainPrefKey,
+ kAllAppsBuildIdentifier,
+ kCFPreferencesCurrentUser,
+ kCFPreferencesAnyHost);
+ CFStringRef lang = CFPreferencesCopyValue(kPreferredLanguagePrefKey,
+ kAllAppsBuildIdentifier,
+ kCFPreferencesCurrentUser,
+ kCFPreferencesAnyHost);
+
+ // make sure we got values for both and domain is not empty
+ if (domain && CFStringGetLength(domain) == 0) {
+ CFRelease(domain);
+ domain = nil;
+ if (lang) {
+ CFRelease(lang);
+ lang = nil;
+ }
+ }
+
+ allAppsCachedDomain_ = GTMNSMakeCollectable(domain);
+ allAppsCachedLanguage_ = GTMNSMakeCollectable(lang);
+}
+
+// -updateAllAppsDomain:language:
+//
+- (void)updateAllAppsDomain:(NSString*)domain language:(NSString*)language {
+ // domain and language can be nil to clear the values
+
+ // if they are the same, don't do anything
+ if ((domain == nil && allAppsCachedDomain_ == nil &&
+ language == nil && allAppsCachedLanguage_ == nil) ||
+ ([domain isEqualToString:allAppsCachedDomain_] &&
+ [language isEqualToString:allAppsCachedLanguage_])) {
+ return;
+ }
+
+ // write it to the file
+ CFPreferencesSetValue(kPreferredDomainPrefKey,
+ (CFStringRef)domain,
+ kAllAppsBuildIdentifier,
+ kCFPreferencesCurrentUser,
+ kCFPreferencesAnyHost);
+ CFPreferencesSetValue(kPreferredLanguagePrefKey,
+ (CFStringRef)language,
+ kAllAppsBuildIdentifier,
+ kCFPreferencesCurrentUser,
+ kCFPreferencesAnyHost);
+ CFPreferencesSynchronize(kAllAppsBuildIdentifier,
+ kCFPreferencesCurrentUser,
+ kCFPreferencesAnyHost);
+
+ // update our values
+ [allAppsCachedDomain_ release];
+ [allAppsCachedLanguage_ release];
+ allAppsCachedDomain_ = [domain copy];
+ allAppsCachedLanguage_ = [language copy];
+
+#if GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS
+ // NOTE: we'll go ahead and reload when this comes back to ourselves since
+ // there is a race here if two folks wrote at about the same time.
+ NSDistributedNotificationCenter *distCenter =
+ [NSDistributedNotificationCenter defaultCenter];
+ [distCenter postNotificationName:kNotificationName
+ object:nil
+ userInfo:nil];
+#endif // GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS
+}
+
+@end
diff --git a/AppKit/GTMGoogleSearchTest.m b/AppKit/GTMGoogleSearchTest.m
new file mode 100644
index 0000000..45f7e66
--- /dev/null
+++ b/AppKit/GTMGoogleSearchTest.m
@@ -0,0 +1,208 @@
+//
+// GTMGoogleSearchTest.m
+//
+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy
+// of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+//
+
+#import "GTMGoogleSearch.h"
+#import "GTMSenTestCase.h"
+#import "GTMUnitTestDevLog.h"
+#import <unistd.h>
+
+@interface GTMGoogleSearchTest : GTMTestCase
+@end
+
+@implementation GTMGoogleSearchTest
+
+- (void)testSearches {
+ typedef struct {
+ NSString *type;
+ NSString *expectedPrefix;
+ } TestSearchDesc;
+ static TestSearchDesc testSearches[] = {
+ { GTMGoogleSearchFroogle, @"http://www.google.xxx/products?" },
+ { GTMGoogleSearchGroups, @"http://www.google.xxx/groups?" },
+ { GTMGoogleSearchImages, @"http://www.google.xxx/images?"},
+ { GTMGoogleSearchLocal, @"http://www.google.xxx/local?"},
+ { GTMGoogleSearchNews, @"http://www.google.xxx/news?"},
+ { GTMGoogleSearchFinance, @"http://www.google.xxx/finance?"},
+ { GTMGoogleSearchBooks, @"http://www.google.xxx/books?"},
+ { GTMGoogleSearchWeb, @"http://www.google.xxx/search?"},
+ };
+
+ GTMGoogleSearch *googleSearch = [GTMGoogleSearch sharedInstance];
+ STAssertNotNil(googleSearch, nil);
+
+ // force the current app values so we aren't at the mercy of the
+ // global setting the users locale.
+ [googleSearch updatePreferredDomain:@"xxx"
+ language:@"yyy"
+ currentApplicationOnly:TRUE];
+
+ size_t count = sizeof(testSearches) / sizeof(testSearches[0]);
+ NSDictionary *globalArgs
+ = [NSDictionary dictionaryWithObject:@"f" forKey:@"foo"];
+ [googleSearch setGlobalSearchArguments:globalArgs];
+ NSDictionary *args = [NSDictionary dictionaryWithObject:@"Baba"
+ forKey:@"BaR"];
+ NSString *expectedStrings[] = {
+ @"oe=UTF-8", @"hl=yyy", @"q=Foobar",
+ @"foo=f", @"ie=UTF-8", @"BaR=Baba"
+ };
+ for (size_t i = 0; i < count; i++) {
+ // test building the url
+ NSString *urlString = [googleSearch searchURLFor:@"Foobar"
+ ofType:testSearches[i].type
+ arguments:args];
+ STAssertTrue([urlString hasPrefix:testSearches[i].expectedPrefix],
+ @"Bad URL? URL:%@ Expected Prefix:%@",
+ urlString, testSearches[i].expectedPrefix);
+ for (size_t j = 0;
+ j < sizeof(expectedStrings) / sizeof(expectedStrings[0]);
+ ++j) {
+ STAssertGreaterThan([urlString rangeOfString:expectedStrings[j]].length,
+ (NSUInteger)0, @"URL: %@ expectedString: %@",
+ urlString, expectedStrings[j]);
+ }
+ }
+
+ // clear what we just set for this test
+ [googleSearch setGlobalSearchArguments:nil];
+ [googleSearch clearPreferredDomainAndLanguageForCurrentApplication];
+}
+
+- (void)testBadInputs {
+ GTMGoogleSearch *googleSearch = [GTMGoogleSearch sharedInstance];
+ STAssertNotNil(googleSearch, nil);
+ NSDictionary *args = [NSDictionary dictionaryWithObject:@"Ba!ba"
+ forKey:@"Ba=R"];
+ [GTMUnitTestDevLogDebug expectString:
+ @"Unescaped string Foo bar in argument pair {q,Foo bar } "
+ @"in -[GTMGoogleSearch searchURLFor:ofType:arguments:]"];
+ [GTMUnitTestDevLogDebug expectString:
+ @"Unescaped string Ba=R in argument pair {Ba=R, Ba!ba} "
+ @"in -[GTMGoogleSearch searchURLFor:ofType:arguments:]"];
+ [GTMUnitTestDevLogDebug expectString:
+ @"Unescaped string Ba!ba in argument pair {Ba=R,Ba!ba } "
+ @"in -[GTMGoogleSearch searchURLFor:ofType:arguments:]"];
+ NSString *urlString = [googleSearch searchURLFor:@"Foo bar"
+ ofType:GTMGoogleSearchFroogle
+ arguments:args];
+ STAssertNotNil(urlString, nil);
+}
+
+- (void)testPreferredDefaults {
+ GTMGoogleSearch *googleSearch = [GTMGoogleSearch sharedInstance];
+ STAssertNotNil(googleSearch, nil);
+
+ // hey, we're a unit test, so start by blowing away what we have at the
+ // app level.
+ [googleSearch clearPreferredDomainAndLanguageForCurrentApplication];
+
+ // in theory, we could fetch now and save off what we get to reset at the
+ // end of this, but we can't tell if that was an "all apps" setting, or if
+ // it was the default, so...hey, we're a unit test, we'll just stomp what's
+ // there and clear it out when done...
+ [googleSearch clearPreferredDomainAndLanguageForAllApps];
+
+ // make sure the individual accessors work...
+
+ // since they system level default can be set by any app, we just have to
+ // check for non nil here (also the users locale could control what
+ // we get if nothing is set).
+ NSString *domain;
+ NSString *lang;
+ // now do a detailed check...
+ BOOL areCurrentAppOnly = YES;
+ [googleSearch preferredDomain:&domain
+ language:&lang
+ areCurrentAppOnly:&areCurrentAppOnly];
+ // should get something for defaults...
+ STAssertNotNil(domain, nil);
+ STAssertNotNil(lang, nil);
+ STAssertFalse(areCurrentAppOnly, nil);
+
+ // test it for "all apps"...
+ [googleSearch updatePreferredDomain:@"domain"
+ language:@"lang"
+ currentApplicationOnly:NO];
+ [googleSearch preferredDomain:&domain
+ language:&lang
+ areCurrentAppOnly:&areCurrentAppOnly];
+ STAssertEqualObjects(domain, @"domain", nil);
+ STAssertEqualObjects(lang, @"lang", nil);
+ STAssertFalse(areCurrentAppOnly, nil);
+
+ // test it for this app...
+ [googleSearch updatePreferredDomain:@"domainThisApp"
+ language:@"langThisApp"
+ currentApplicationOnly:YES];
+ [googleSearch preferredDomain:&domain
+ language:&lang
+ areCurrentAppOnly:&areCurrentAppOnly];
+ STAssertEqualObjects(domain, @"domainThisApp", nil);
+ STAssertEqualObjects(lang, @"langThisApp", nil);
+ STAssertTrue(areCurrentAppOnly, nil);
+
+ // clear what we just set for this app
+ [googleSearch clearPreferredDomainAndLanguageForCurrentApplication];
+
+ // should get back what we set for all apps
+ [googleSearch preferredDomain:&domain
+ language:&lang
+ areCurrentAppOnly:&areCurrentAppOnly];
+ STAssertEqualObjects(domain, @"domain", nil);
+ STAssertEqualObjects(lang, @"lang", nil);
+ STAssertFalse(areCurrentAppOnly, nil);
+#if GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS
+ // We don't test launching other tasks on the phone since this isn't a valid
+ // case until we can support real multiple tasks on the phone.
+
+ // try changing the value directly in the plist file (as if another app had
+ // done it) and sending our notification.
+ [[NSTask launchedTaskWithLaunchPath:@"/usr/bin/defaults"
+ arguments:[NSArray arrayWithObjects:@"write",
+ @"com.google.GoogleSearchAllApps",
+ @"{ \"com.google.PreferredDomain\" = xxx;"
+ @"\"com.google.PreferredLanguage\" = yyy; }",
+ nil]] waitUntilExit];
+ // Sleep for a moment to let things flush
+ // (seen rarely as a problem on aharper's machine).
+ sleep(1);
+ NSDistributedNotificationCenter *distCenter =
+ [NSDistributedNotificationCenter defaultCenter];
+ [distCenter postNotificationName:@"com.google.GoogleSearchAllApps.prefsWritten"
+ object:nil
+ userInfo:nil
+ options:NSNotificationDeliverImmediately];
+
+ // Spin the runloop so the notifications fire.
+ NSRunLoop *currentLoop = [NSRunLoop currentRunLoop];
+ [currentLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
+ // did we get what we expected?
+ [googleSearch preferredDomain:&domain
+ language:&lang
+ areCurrentAppOnly:&areCurrentAppOnly];
+ STAssertEqualObjects(domain, @"xxx", nil);
+ STAssertEqualObjects(lang, @"yyy", nil);
+ STAssertFalse(areCurrentAppOnly, nil);
+#endif // GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS
+
+ // lastly, clean up what we set for all apps to leave the system at the
+ // default.
+ [googleSearch clearPreferredDomainAndLanguageForAllApps];
+}
+
+@end
diff --git a/AppKit/GTMHotKeyTextFieldTest.m b/AppKit/GTMHotKeyTextFieldTest.m
index b3e7e89..e48ee94 100644
--- a/AppKit/GTMHotKeyTextFieldTest.m
+++ b/AppKit/GTMHotKeyTextFieldTest.m
@@ -265,7 +265,7 @@
GTMHotKeyTextField *field = [controller_ view];
STAssertNotNil(field, nil);
NSString *expectedNumberString = @"Hot key fields don't take numbers.";
- [GTMUnitTestDevLog expect:6 casesOfString:expectedNumberString];
+ [GTMUnitTestDevLog expect:6 casesOfString:@"%@", expectedNumberString];
[field setDoubleValue:2];
[field setIntValue:-1];
[field setFloatValue:0];
@@ -273,7 +273,7 @@
STAssertEquals([field intValue], 0, nil);
STAssertEquals([field floatValue], 0.0f, nil);
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
- [GTMUnitTestDevLog expect:2 casesOfString:expectedNumberString];
+ [GTMUnitTestDevLog expect:2 casesOfString:@"%@", expectedNumberString];
[field setIntegerValue:5];
STAssertEquals([field integerValue], (NSInteger)0, nil);
#endif
@@ -285,14 +285,14 @@
};
for (size_t i = 0;
i < sizeof(takeNumberSels) / sizeof(takeNumberSels[0]); ++i) {
- [GTMUnitTestDevLog expect:2 casesOfString:expectedNumberString];
+ [GTMUnitTestDevLog expect:2 casesOfString:@"%@", expectedNumberString];
[field performSelector:takeNumberSels[i] withObject:self];
[field performSelector:takeNumberSels[i] withObject:nil];
}
NSString *expectedStringString
= @"Hot key fields want dictionaries, not strings.";
- [GTMUnitTestDevLog expect:6 casesOfString:expectedStringString];
+ [GTMUnitTestDevLog expect:6 casesOfString:@"%@", expectedStringString];
[field takeStringValueFrom:self];
[field takeStringValueFrom:nil];
[field setStringValue:nil];
diff --git a/AppKit/GTMNSImage+Scaling.h b/AppKit/GTMNSImage+Scaling.h
index 7d48577..0f87709 100644
--- a/AppKit/GTMNSImage+Scaling.h
+++ b/AppKit/GTMNSImage+Scaling.h
@@ -19,7 +19,7 @@
//
-#import <Foundation/Foundation.h>
+#import <AppKit/AppKit.h>
#import "GTMDefines.h"
@interface NSImage (GTMNSImageScaling)
@@ -30,7 +30,9 @@
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6
// Return the exact or next largest representation for a size
// If you are on SnowLeopard use
-// -[NSImage bestRepresentationForRect:context:hints:]
+// -[NSImage bestRepresentationForRect:context:hints:]
+// Also, please see http://openradar.appspot.com/radar?id=394401
+// and read notes in GTMNSImage+ScalingTest.m. Search for "8052200".
- (NSImageRep *)gtm_bestRepresentationForSize:(NSSize)size;
#endif
diff --git a/AppKit/GTMNSImage+ScalingTest.m b/AppKit/GTMNSImage+ScalingTest.m
index dddd00f..426e21b 100644
--- a/AppKit/GTMNSImage+ScalingTest.m
+++ b/AppKit/GTMNSImage+ScalingTest.m
@@ -49,7 +49,7 @@
STAssertNotNil([testImage gtm_representationOfSize:NSMakeSize(32, 32)], nil);
NSImage *duplicate = [testImage gtm_duplicateOfSize:NSMakeSize(48, 48)];
- bestRepRect = NSMakeRect(0, 0, 50, 50);
+ bestRepRect = NSMakeRect(0, 0, 48, 48);
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
rep = [duplicate bestRepresentationForRect:bestRepRect
context:nil
@@ -60,6 +60,24 @@
STAssertTrue(NSEqualSizes([rep size], NSMakeSize(48, 48)),
@"Size is %@", NSStringFromSize([rep size]));
+ // This should IMHO return 48,48 on both 10.6 and 10.5. It makes no sense
+ // at all that it returns 32,32 on 10_6 when the above code works for 48,48.
+ // rdar://8052200 "NSImage bestRepresentationForRect:context:hints: doesn't
+ // return the best rep"
+ // http://openradar.appspot.com/radar?id=394401
+ bestRepRect = NSMakeRect(0, 0, 50, 50);
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
+ rep = [duplicate bestRepresentationForRect:bestRepRect
+ context:nil
+ hints:nil];
+ STAssertFalse(NSEqualSizes([rep size], NSMakeSize(48, 48)),
+ @"Size is %@", NSStringFromSize([rep size]));
+#else
+ rep = [duplicate gtm_bestRepresentationForSize:bestRepRect.size];
+ STAssertTrue(NSEqualSizes([rep size], NSMakeSize(48, 48)),
+ @"Size is %@", NSStringFromSize([rep size]));
+#endif // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
+
}
@end
diff --git a/AppKit/GTMNSImage+SearchCache.h b/AppKit/GTMNSImage+SearchCache.h
index b0999bf..4e3a10d 100644
--- a/AppKit/GTMNSImage+SearchCache.h
+++ b/AppKit/GTMNSImage+SearchCache.h
@@ -32,6 +32,8 @@
// TODO(alcor): this class should have basic MRU cache
//
+#import <AppKit/AppKit.h>
+
@interface NSImage (GTMNSImageSearchCache)
+ (NSImage *)gtm_imageWithPath:(NSString *)path;
+ (NSImage *)gtm_imageNamed:(NSString *)name;
diff --git a/AppKit/TestData/GTMUILocalizerAndLayoutTweakerTest4-0.10_4_SDK.10.6.tiff b/AppKit/TestData/GTMUILocalizerAndLayoutTweakerTest4-0.10_4_SDK.10.6.tiff
new file mode 100644
index 0000000..29c9762
--- /dev/null
+++ b/AppKit/TestData/GTMUILocalizerAndLayoutTweakerTest4-0.10_4_SDK.10.6.tiff
Binary files differ
diff --git a/AppKit/TestData/GTMUILocalizerAndLayoutTweakerTest4-1.10_4_SDK.10.6.tiff b/AppKit/TestData/GTMUILocalizerAndLayoutTweakerTest4-1.10_4_SDK.10.6.tiff
new file mode 100644
index 0000000..eb9815e
--- /dev/null
+++ b/AppKit/TestData/GTMUILocalizerAndLayoutTweakerTest4-1.10_4_SDK.10.6.tiff
Binary files differ
diff --git a/AppKit/TestData/GTMUILocalizerAndLayoutTweakerTest4-2.10_4_SDK.10.6.tiff b/AppKit/TestData/GTMUILocalizerAndLayoutTweakerTest4-2.10_4_SDK.10.6.tiff
new file mode 100644
index 0000000..f677712
--- /dev/null
+++ b/AppKit/TestData/GTMUILocalizerAndLayoutTweakerTest4-2.10_4_SDK.10.6.tiff
Binary files differ