PageRenderTime 82ms CodeModel.GetById 11ms app.highlight 66ms RepoModel.GetById 1ms app.codeStats 0ms

/core/externals/update-engine/externals/gdata-objectivec-client/Examples/AnalyticsSample/AnalyticsSampleWindowController.m

http://macfuse.googlecode.com/
Objective C | 515 lines | 328 code | 116 blank | 71 comment | 30 complexity | 2267f219013fb13df81d8cc1ccd9a71f MD5 | raw file
  1/* Copyright (c) 2009 Google Inc.
  2 *
  3 * Licensed under the Apache License, Version 2.0 (the "License");
  4 * you may not use this file except in compliance with the License.
  5 * You may obtain a copy of the License at
  6 *
  7 *     http://www.apache.org/licenses/LICENSE-2.0
  8 *
  9 * Unless required by applicable law or agreed to in writing, software
 10 * distributed under the License is distributed on an "AS IS" BASIS,
 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12 * See the License for the specific language governing permissions and
 13 * limitations under the License.
 14 */
 15
 16//
 17//  AnalyticsSampleWindowController.m
 18//
 19
 20//
 21// IMPORTANT:
 22//
 23// The XML-based API for Google Analytics has been replaced with a more efficient
 24// and easier-to-use JSON API.  The JSON API is documented at
 25//
 26//   https://developers.google.com/analytics
 27//
 28// See the new Objective-C client library and sample code at
 29//   http://code.google.com/p/google-api-objectivec-client/
 30//
 31// This sample application and library support for the XML-based Analytics
 32// API will eventually be removed.
 33//
 34
 35#import "AnalyticsSampleWindowController.h"
 36
 37@interface AnalyticsSampleWindowController (PrivateMethods)
 38- (void)updateUI;
 39
 40- (void)fetchFeedOfAccounts;
 41- (void)fetchSelectedAccount;
 42- (void)fetchSelectedAnalyticsData;
 43
 44- (GDataServiceGoogleAnalytics *)analyticsService;
 45- (GDataEntryAnalyticsAccount *)selectedAccount;
 46- (GDataEntryAnalyticsData *)selectedAnalyticsData;
 47
 48- (NSString *)itemListForPopup:(NSPopUpButton *)popup;
 49- (NSString *)analyticsDateStringForDatePicker:(NSDatePicker *)picker;
 50
 51- (GDataFeedAnalyticsAccount *)accountFeed;
 52- (void)setAccountFeed:(GDataFeedAnalyticsAccount *)feed;
 53- (NSError *)accountFetchError;
 54- (void)setAccountFetchError:(NSError *)error;
 55
 56- (GDataFeedAnalyticsData *)analyticsDataFeed;
 57- (void)setAnalyticsDataFeed:(GDataFeedAnalyticsData *)feed;
 58- (NSError *)analyticsDataFetchError;
 59- (void)setAnalyticsDataFetchError:(NSError *)error;
 60@end
 61
 62@implementation AnalyticsSampleWindowController
 63
 64static AnalyticsSampleWindowController* gWindowController = nil;
 65
 66+ (AnalyticsSampleWindowController *)sharedAnalyticsSampleWindowController {
 67
 68  if (!gWindowController) {
 69    gWindowController = [[AnalyticsSampleWindowController alloc] init];
 70  }
 71  return gWindowController;
 72}
 73
 74- (id)init {
 75  return [self initWithWindowNibName:@"AnalyticsSampleWindow"];
 76}
 77
 78// dimensions and metrics, from
 79// http://code.google.com/apis/analytics/docs/gdata/gdataReferenceDimensionsMetrics.html
 80
 81- (NSArray *)dimensionNames {
 82  return [NSArray arrayWithObjects:
 83          @"ga:browser", @"ga:browserVersion", @"ga:city",
 84          @"ga:connectionSpeed", @"ga:continent", @"ga:visitCount",
 85          @"ga:country", @"ga:date", @"ga:day", @"ga:daysSinceLastVisit",
 86          @"ga:flashVersion", @"ga:hostname", @"ga:hour", @"ga:javaEnabled",
 87          @"ga:language", @"ga:latitude", @"ga:longitude", @"ga:month",
 88          @"ga:networkDomain", @"ga:networkLocation", @"ga:pageDepth",
 89          @"ga:operatingSystem", @"ga:operatingSystemVersion", @"ga:region",
 90          @"ga:screenColors", @"ga:screenResolution", @"ga:subContinent",
 91          @"ga:userDefinedValue", @"ga:visitLength", @"ga:visitorType",
 92          @"ga:week", @"ga:year", @"ga:adContent", @"ga:adGroup", @"ga:adSlot",
 93          @"ga:adSlotPosition", @"ga:campaign", @"ga:keyword", @"ga:medium",
 94          @"ga:referralPath", @"ga:source", @"ga:exitPagePath",
 95          @"ga:landingPagePath",  @"ga:secondPagePath", @"ga:pagePath",
 96          @"ga:pageTitle", @"ga:affiliation", @"ga:daysToTransaction",
 97          @"ga:productCategory", @"ga:productName", @"ga:productSku",
 98          @"ga:transactionId", @"ga:searchCategory",
 99          @"ga:searchDestinationPage", @"ga:searchKeyword",
100          @"ga:searchKeywordRefinement", @"ga:searchStartPage",
101          @"ga:searchUsed", @"ga:nextPagePath", @"ga:previousPagePath",
102          @"ga:eventCategory", @"ga:eventAction", @"ga:eventLabel", nil];
103}
104
105- (NSArray *)metricNames {
106  return [NSArray arrayWithObjects:
107          @"ga:adClicks", @"ga:adCost", @"ga:bounces ", @"ga:CPC", @"ga:CPM",
108          @"ga:CTR", @"ga:entrances", @"ga:exits", @"ga:goal1Completions",
109          @"ga:goal1Starts", @"ga:goal1Value", @"ga:goal2Completions",
110          @"ga:goal2Starts", @"ga:goal2Value", @"ga:goal3Completions",
111          @"ga:goal3Starts", @"ga:goal3Value", @"ga:goal4Completions",
112          @"ga:goal4Starts", @"ga:goal4Value", @"ga:goalCompletionsAll",
113          @"ga:goalStartsAll", @"ga:goalValueAll", @"ga:impressions",
114          @"ga:itemQuantity", @"ga:itemRevenue", @"ga:newVisits",
115          @"ga:pageviews", @"ga:searchDepth", @"ga:searchDuration",
116          @"ga:searchExits", @"ga:searchRefinements", @"ga:searchUniques",
117          @"ga:searchVisits", @"ga:timeOnPage", @"ga:timeOnSite",
118          @"ga:transactionRevenue", @"ga:transactions",
119          @"ga:transactionShipping", @"ga:transactionTax",
120          @"ga:uniquePageviews", @"ga:uniquePurchases",
121          @"ga:visitors", @"ga:visits",
122          @"ga:totalEvents", @"ga:uniqueEvents", @"ga:eventValue", nil];
123}
124
125- (void)awakeFromNib {
126  // Set the result text fields to have a distinctive color and mono-spaced font
127  // to aid in understanding of each query operation.
128
129  [mAccountsResultTextField setTextColor:[NSColor darkGrayColor]];
130  [mAnalyticsDataResultTextField setTextColor:[NSColor darkGrayColor]];
131
132  NSFont *resultTextFont = [NSFont fontWithName:@"Monaco" size:9];
133  [mAccountsResultTextField setFont:resultTextFont];
134  [mAnalyticsDataResultTextField setFont:resultTextFont];
135
136  // set the date pickers to run from last week to today
137  NSTimeInterval aWeekAgo = -7 * 24 * 60 * 60;
138  [mStartDatePicker setDateValue:[NSDate dateWithTimeIntervalSinceNow:aWeekAgo]];
139  [mEndDatePicker setDateValue:[NSDate date]];
140
141  // load the pop-ups for dimensions and metrics, and check one item for each
142  [mDimensionsPopup addItemsWithTitles:[self dimensionNames]];
143  [[mDimensionsPopup itemWithTitle:@"ga:country"] setState:NSOnState];
144
145  [mMetricsPopup addItemsWithTitles:[self metricNames]];
146  [[mMetricsPopup itemWithTitle:@"ga:pageviews"] setState:NSOnState];
147
148  [self updateUI];
149}
150
151- (void)dealloc {
152  [mAccountFeed release];
153  [mAccountFetchError release];
154
155  [mAnalyticsDataFeed release];
156  [mAnalyticsDataFetchError release];
157
158  [super dealloc];
159}
160
161#pragma mark -
162
163- (void)updateUI {
164
165  // account list display
166  [mAccountsTable reloadData];
167
168  if (mIsAccountFetchPending) {
169    [mAccountsProgressIndicator startAnimation:self];
170  } else {
171    [mAccountsProgressIndicator stopAnimation:self];
172  }
173
174  // account fetch result or selected item
175  NSString *accountResultStr = @"";
176  if (mAccountFetchError) {
177    accountResultStr = [mAccountFetchError description];
178  } else {
179    GDataEntryAnalyticsAccount *account = [self selectedAccount];
180    if (account) {
181      accountResultStr = [account description];
182    }
183  }
184  [mAccountsResultTextField setString:accountResultStr];
185
186
187  // analyticsData list display
188  [mAnalyticsDataTable reloadData];
189
190  if (mIsAnalyticsDataFetchPending) {
191    [mAnalyticsDataProgressIndicator startAnimation:self];
192  } else {
193    [mAnalyticsDataProgressIndicator stopAnimation:self];
194  }
195
196  // analyticsData fetch result or selected item
197  NSString *analyticsDataResultStr = @"";
198  if (mAnalyticsDataFetchError) {
199    analyticsDataResultStr = [mAnalyticsDataFetchError description];
200  } else {
201    GDataEntryAnalyticsData *analyticsData = [self selectedAnalyticsData];
202    if (analyticsData) {
203      analyticsDataResultStr = [analyticsData description];
204    }
205  }
206  [mAnalyticsDataResultTextField setString:analyticsDataResultStr];
207
208
209  // the reload button is useful after the user changes dates or checkboxes
210  // for metrics and dimensions
211  GDataEntryAnalyticsAccount *selectedAccount = [self selectedAccount];
212  [mReloadButton setEnabled:(selectedAccount != nil)];
213
214
215  // update the comma-separated lists of dimensions and metrics to match the
216  // checked items in the pop-up menus
217  NSString *dimensions = [self itemListForPopup:mDimensionsPopup];
218  [mDimensionsField setStringValue:dimensions];
219
220  NSString *metrics = [self itemListForPopup:mMetricsPopup];
221  [mMetricsField setStringValue:metrics];
222}
223
224- (IBAction)loggingCheckboxClicked:(id)sender {
225  [GTMHTTPFetcher setLoggingEnabled:[sender state]];
226}
227
228#pragma mark IBActions
229
230- (IBAction)getAccountsClicked:(id)sender {
231
232  NSCharacterSet *whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
233
234  NSString *username = [mUsernameField stringValue];
235  username = [username stringByTrimmingCharactersInSet:whitespace];
236
237  if ([username rangeOfString:@"@"].location == NSNotFound) {
238    // if no domain was supplied, add @gmail.com
239    username = [username stringByAppendingString:@"@gmail.com"];
240  }
241
242  [mUsernameField setStringValue:username];
243
244  [self fetchFeedOfAccounts];
245}
246
247#pragma mark -
248
249// get a account service object with the current username/password
250//
251// A "service" object handles networking tasks.  Service objects
252// contain user authentication information as well as networking
253// state information (such as cookies and the "last modified" date for
254// fetched data.)
255
256- (GDataServiceGoogleAnalytics *)analyticsService {
257
258  static GDataServiceGoogleAnalytics* service = nil;
259
260  if (!service) {
261    service = [[GDataServiceGoogleAnalytics alloc] init];
262
263    [service setShouldCacheResponseData:YES];
264    [service setServiceShouldFollowNextLinks:YES];
265  }
266
267  // username/password may change
268  NSString *username = [mUsernameField stringValue];
269  NSString *password = [mPasswordField stringValue];
270
271  [service setUserCredentialsWithUsername:username
272                                 password:password];
273  return service;
274}
275
276// get the account selected in the top list, or nil if none
277- (GDataEntryAnalyticsAccount *)selectedAccount {
278
279  NSArray *accounts = [mAccountFeed entries];
280  int rowIndex = [mAccountsTable selectedRow];
281  if ([accounts count] > 0 && rowIndex > -1) {
282
283    GDataEntryAnalyticsAccount *account = [accounts objectAtIndex:rowIndex];
284    return account;
285  }
286  return nil;
287}
288
289// get the analyticsData selected in the second list, or nil if none
290- (GDataEntryAnalyticsData *)selectedAnalyticsData {
291
292  NSArray *entries = [mAnalyticsDataFeed entries];
293  int rowIndex = [mAnalyticsDataTable selectedRow];
294  if ([entries count] > 0 && rowIndex > -1) {
295
296    GDataEntryAnalyticsData *analyticsData = [entries objectAtIndex:rowIndex];
297    return analyticsData;
298  }
299  return nil;
300}
301
302- (IBAction)refreshAccountData:(id)sender {
303  [self fetchSelectedAccount];
304}
305
306#pragma mark Fetch feed of all of the user's accounts
307
308// begin retrieving the list of the user's accounts
309- (void)fetchFeedOfAccounts {
310
311  [self setAccountFeed:nil];
312  [self setAccountFetchError:nil];
313
314  [self setAnalyticsDataFeed:nil];
315  [self setAnalyticsDataFetchError:nil];
316
317  mIsAccountFetchPending = YES;
318
319  GDataServiceGoogleAnalytics *service = [self analyticsService];
320  NSURL *feedURL = [NSURL URLWithString:kGDataGoogleAnalyticsDefaultAccountFeed];
321  [service fetchFeedWithURL:feedURL
322                  feedClass:[GDataFeedAnalyticsAccount class]
323                   delegate:self
324          didFinishSelector:@selector(accountFeedTicket:finishedWithFeed:error:)];
325
326  [self updateUI];
327}
328
329// account list fetch callback
330- (void)accountFeedTicket:(GDataServiceTicket *)ticket
331         finishedWithFeed:(GDataFeedAnalyticsAccount *)feed
332                    error:(NSError *)error {
333
334  [self setAccountFeed:feed];
335  [self setAccountFetchError:error];
336
337  mIsAccountFetchPending = NO;
338  [self updateUI];
339}
340
341#pragma mark Fetch a account's analyticsData
342
343// for the account selected in the top list, begin retrieving the feed of
344// analytics data
345
346- (void)fetchSelectedAccount {
347
348  GDataEntryAnalyticsAccount *accountEntry = [self selectedAccount];
349  if (accountEntry != nil) {
350
351    [self setAnalyticsDataFeed:nil];
352    [self setAnalyticsDataFetchError:nil];
353    mIsAnalyticsDataFetchPending = YES;
354
355    NSString *tableID = [accountEntry tableID];
356
357    NSString *startDateStr, *endDateStr;
358    startDateStr = [self analyticsDateStringForDatePicker:mStartDatePicker];
359    endDateStr = [self analyticsDateStringForDatePicker:mEndDatePicker];
360
361    GDataQueryAnalytics *query;
362    query = [GDataQueryAnalytics analyticsDataQueryWithTableID:tableID
363                                               startDateString:startDateStr
364                                                 endDateString:endDateStr];
365
366    NSString *dimensions = [self itemListForPopup:mDimensionsPopup];
367    [query setDimensions:dimensions];
368
369    NSString *metrics = [self itemListForPopup:mMetricsPopup];
370    [query setMetrics:metrics];
371
372    GDataServiceGoogleAnalytics *service = [self analyticsService];
373    [service fetchFeedWithQuery:query
374                      feedClass:[GDataFeedAnalyticsData class]
375                       delegate:self
376              didFinishSelector:@selector(analyticsDataFeedTicket:finishedWithFeed:error:)];
377    [self updateUI];
378  }
379}
380
381// analytics data fetch callback
382- (void)analyticsDataFeedTicket:(GDataServiceTicket *)ticket
383               finishedWithFeed:(GDataFeedAnalyticsData *)feed
384                          error:(NSError *)error {
385
386  [self setAnalyticsDataFeed:feed];
387  [self setAnalyticsDataFetchError:error];
388
389  mIsAnalyticsDataFetchPending = NO;
390
391  [self updateUI];
392}
393
394#pragma mark TableView delegate methods
395//
396// table view delegate methods
397//
398
399- (void)tableViewSelectionDidChange:(NSNotification *)notification {
400  id obj = [notification object];
401  if (obj == mAccountsTable) {
402    // the user clicked on an account, so fetch its analytics data
403    [self fetchSelectedAccount];
404  } else {
405    // the user clicked on an analytics data entry
406    [self updateUI];
407  }
408}
409
410// table view data source methods
411- (int)numberOfRowsInTableView:(NSTableView *)tableView {
412  if (tableView == mAccountsTable) {
413    return [[mAccountFeed entries] count];
414  } else  {
415    return [[mAnalyticsDataFeed entries] count];
416  }
417}
418
419- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row {
420  if (tableView == mAccountsTable) {
421    // get the account entry's title
422    GDataEntryAnalyticsAccount *entry;
423    entry = [[mAccountFeed entries] objectAtIndex:row];
424
425    return [[entry title] stringValue];
426  } else {
427    // get the analyticsData entry's title
428    GDataEntryAnalyticsData *entry;
429    entry = [[mAnalyticsDataFeed entries] objectAtIndex:row];
430
431    return [[entry title] stringValue];
432  }
433}
434
435#pragma mark Menu item actions
436
437- (IBAction)menuItemClicked:(id)sender {
438  // toggle the checkmark for the selected pop-up menu item
439  NSMenuItem *item = [sender selectedItem];
440  int oldState = [item state];
441  [item setState:(!oldState)];
442
443  [self updateUI];
444}
445
446#pragma mark UI-related utilities
447
448// return a date string like @"2001-03-15" for the date picker
449- (NSString *)analyticsDateStringForDatePicker:(NSDatePicker *)picker {
450  NSDate *date = [picker dateValue];
451
452  unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit
453                       | NSDayCalendarUnit;
454  NSCalendar *calendar = [NSCalendar currentCalendar];
455
456  NSDateComponents *dateComponents = [calendar components:unitFlags
457                                                 fromDate:date];
458  NSString *dateString = [NSString stringWithFormat:@"%04u-%02u-%02u",
459                          [dateComponents year], [dateComponents month],
460                          [dateComponents day]];
461  return dateString;
462}
463
464// return a comma-separated list string like @"ga:country,ga:networkDomain"
465- (NSString *)itemListForPopup:(NSPopUpButton *)popup {
466
467  NSArray *checkedItems = [GDataUtilities objectsFromArray:[popup itemArray]
468                                                 withValue:[NSNumber numberWithInt:NSOnState]
469                                                forKeyPath:@"state"];
470
471  NSArray *titles = [checkedItems valueForKey:@"title"];
472  NSString *commaSeparatedList = [titles componentsJoinedByString:@","];
473  return commaSeparatedList;
474}
475
476#pragma mark Setters and Getters
477
478- (GDataFeedAnalyticsAccount *)accountFeed {
479  return mAccountFeed;
480}
481
482- (void)setAccountFeed:(GDataFeedAnalyticsAccount *)feed {
483  [mAccountFeed autorelease];
484  mAccountFeed = [feed retain];
485}
486
487- (NSError *)accountFetchError {
488  return mAccountFetchError;
489}
490
491- (void)setAccountFetchError:(NSError *)error {
492  [mAccountFetchError release];
493  mAccountFetchError = [error retain];
494}
495
496
497- (GDataFeedAnalyticsData *)analyticsDataFeed {
498  return mAnalyticsDataFeed;
499}
500
501- (void)setAnalyticsDataFeed:(GDataFeedAnalyticsData *)feed {
502  [mAnalyticsDataFeed autorelease];
503  mAnalyticsDataFeed = [feed retain];
504}
505
506- (NSError *)analyticsDataFetchError {
507  return mAnalyticsDataFetchError;
508}
509
510- (void)setAnalyticsDataFetchError:(NSError *)error {
511  [mAnalyticsDataFetchError release];
512  mAnalyticsDataFetchError = [error retain];
513}
514
515@end