2011-07-07 13:06:03 -05:00
//
// MGMController . m
// Chromatic
//
// Created by Mr . Gecko on 6 / 9 / 11.
// Copyright ( c ) 2011 Mr . Gecko ' s Media ( James Coleman ) . http : // mrgeckosmedia . com /
//
// Permission to use , copy , modify , and / or distribute this software for any purpose
// with or without fee is hereby granted , provided that the above copyright notice
// and this permission notice appear in all copies .
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS . IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL , DIRECT , INDIRECT ,
// OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE ,
// DATA OR PROFITS , WHETHER IN AN ACTION OF CONTRACT , NEGLIGENCE OR OTHER TORTIOUS
// ACTION , ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
//
# import "MGMController.h"
# import "MGMAddons.h"
# import < MGMUsers / MGMUsers . h >
# import < GeckoReporter / GeckoReporter . h >
# import < WebKit / WebKit . h >
NSString * const MGMCopyright = @ "Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/" ;
NSString * const MGMVersion = @ "MGMVersion" ;
NSString * const MGMLaunchCount = @ "MGMLaunchCount" ;
NSString * const MGMChannel = @ "MGMChannel" ;
NSString * const MGMChromiumPath = @ "MGMChromiumPath" ;
NSString * const MGMCustomSnapshotURL = @ "MGMCustomSnapshotURL" ;
NSString * const MGMMoveToTrash = @ "MGMMoveToTrash" ;
NSString * const MGMDoneSound = @ "MGMDoneSound" ;
NSString * const MGMLaunchWhenDone = @ "MGMLaunchWhenDone" ;
NSString * const MGMQuitAfterLaunch = @ "MGMQuitAfterLaunch" ;
NSString * const MGMCPApplications = @ "/Applications" ;
NSString * const MGMCPUserApplications = @ "~/Applications" ;
NSString * const MGMCPChromium = @ "Chromium.app" ;
NSString * const MGMChromiumZip = @ "chrome-mac.zip" ;
NSString * const MGMTMPPath = @ "/tmp" ;
2014-09-28 18:27:03 -05:00
NSString * const MGMChannelsURL = @ "https://omahaproxy.appspot.com/all.json?os=mac" ;
2011-09-15 20:54:40 -05:00
static NSString * MGMSnapshotURL = @ "https://commondatastorage.googleapis.com/chromium-browser-snapshots/" ;
NSString * const MGMSnapshotPrefix = @ "Mac/" ;
2011-07-07 13:06:03 -05:00
NSString * const MGMSVNLogsURL = @ "http://build.chromium.org/f/chromium/perf/dashboard/ui/changelog.html?url=/trunk/src&range=%@:%@&mode=html&os=mac" ;
NSString * const MGMCChannel = @ "channel" ;
2014-09-28 18:27:03 -05:00
NSString * const MGMCRevision = @ "branch_base_position" ;
2011-07-07 13:06:03 -05:00
NSString * const MGMCStable = @ "stable" ;
NSString * const MGMCBeta = @ "beta" ;
NSString * const MGMCDev = @ "dev" ;
NSString * const MGMCCanary = @ "canary" ;
NSString * const MGMUBUpdate = @ "Update" ;
NSString * const MGMUBInstall = @ "Install" ;
NSString * const MGMUBCancel = @ "Cancel" ;
2011-09-15 20:54:40 -05:00
@ interface NSString ( MGMAddonsSort )
- ( NSComparisonResult ) numberCompare : ( id ) theItem ;
@ end
@ implementation NSString ( MGMAddonsSort )
- ( NSComparisonResult ) numberCompare : ( id ) theItem {
unsigned int theNumber = 0 ;
unsigned int number = 0 ;
if ( [ theItem isKindOfClass : [ NSString class ] ] )
sscanf ( [ theItem UTF8String ] , "%u" , & theNumber ) ;
sscanf ( [ self UTF8String ] , "%u" , & number ) ;
if ( number < theNumber )
return NSOrderedAscending ;
else if ( number > theNumber )
return NSOrderedDescending ;
return NSOrderedSame ;
}
@ end
2011-07-07 13:06:03 -05:00
@ interface NSOpenPanel ( MGMIgnore )
- ( void ) setDirectoryURL : ( NSURL * ) url ;
- ( void ) setDirectory : ( NSString * ) path ;
@ end
@ implementation MGMController
- ( void ) awakeFromNib {
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( setup ) name : MGMGRDoneNotification object : nil ] ;
[ MGMReporter sharedReporter ] ;
}
- ( void ) setup {
connectionManager = [ [ MGMURLConnectionManager manager ] retain ] ;
NSUserDefaults * defaults = [ NSUserDefaults standardUserDefaults ] ;
if ( [ defaults objectForKey : MGMVersion ] = = nil ) {
NSString * oldPathKey = @ "cPathKey" ;
[ defaults setObject : [ defaults stringForKey : oldPathKey ] forKey : MGMChromiumPath ] ;
[ defaults removeObjectForKey : oldPathKey ] ;
[ defaults setObject : [ [ MGMSystemInfo info ] applicationVersion ] forKey : MGMVersion ] ;
}
[ self registerDefaults ] ;
if ( [ defaults integerForKey : MGMLaunchCount ] ! = 5 ) {
[ defaults setInteger : [ defaults integerForKey : MGMLaunchCount ] + 1 forKey : MGMLaunchCount ] ;
if ( [ defaults integerForKey : MGMLaunchCount ] = = 5 ) {
NSAlert * alert = [ [ NSAlert new ] autorelease ] ;
[ alert setMessageText : @ "Donations" ] ;
[ alert setInformativeText : @ "Thank you for using Chromatic. Chromatic is donation supported software. If you like using it, please consider giving a donation to help with development." ] ;
[ alert addButtonWithTitle : @ "Yes" ] ;
[ alert addButtonWithTitle : @ "No" ] ;
int result = [ alert runModal ] ;
if ( result = = 1000 )
[ self donate : self ] ;
}
}
if ( [ defaults objectForKey : MGMCustomSnapshotURL ] ! = nil && ! [ [ defaults objectForKey : MGMCustomSnapshotURL ] isEqual : @ "" ] )
MGMSnapshotURL = [ defaults objectForKey : MGMCustomSnapshotURL ] ;
about = [ MGMAbout new ] ;
preferences = [ MGMPreferences new ] ;
[ preferences addPreferencesPaneClassName : @ "MGMGeneralPane" ] ;
[ preferences addPreferencesPaneClassName : @ "MGMAdvancedPane" ] ;
startingUp = YES ;
[ mainWindow makeKeyAndOrderFront : self ] ;
[ progress startAnimation : self ] ;
[ updateButton setEnabled : NO ] ;
[ channelPopUp selectItemAtIndex : [ defaults integerForKey : MGMChannel ] ] ;
channelRevisions = [ NSMutableDictionary new ] ;
NSString * path = [ defaults objectForKey : MGMChromiumPath ] ;
if ( path = = nil )
path = [ [ NSWorkspace sharedWorkspace ] fullPathForApplication : @ "Chromium" ] ;
if ( path = = nil ) {
NSFileManager * manager = [ NSFileManager defaultManager ] ;
if ( [ manager isWritableFileAtPath : MGMCPApplications ] ) {
path = [ MGMCPApplications stringByAppendingPathComponent : MGMCPChromium ] ;
} else {
if ( [ manager fileExistsAtPath : [ MGMCPUserApplications stringByExpandingTildeInPath ] ] )
[ manager createDirectoryAtPath : [ MGMCPUserApplications stringByExpandingTildeInPath ] withAttributes : nil ] ;
path = [ [ MGMCPUserApplications stringByExpandingTildeInPath ] stringByAppendingPathComponent : MGMCPChromium ] ;
}
}
chromiumPath = [ path copy ] ;
[ self updateChromiumPath ] ;
MGMURLBasicHandler * handler = [ MGMURLBasicHandler handlerWithRequest : [ NSURLRequest requestWithURL : [ NSURL URLWithString : MGMChannelsURL ] ] delegate : self ] ;
[ handler setFailWithError : @ selector ( channels : didFailWithError : ) ] ;
[ handler setFinish : @ selector ( channelsFinished : ) ] ;
[ connectionManager addHandler : handler ] ;
2011-09-15 20:54:40 -05:00
revisionsArray = [ NSMutableArray new ] ;
NSString * url = [ MGMSnapshotURL stringByAppendingFormat : @ "?delimiter=/&prefix=%@" , MGMSnapshotPrefix ] ;
handler = [ MGMURLBasicHandler handlerWithRequest : [ NSURLRequest requestWithURL : [ NSURL URLWithString : url ] ] delegate : self ] ;
2011-07-07 13:06:03 -05:00
[ handler setFailWithError : @ selector ( revisions : didFailWithError : ) ] ;
[ handler setFinish : @ selector ( revisionsFinished : ) ] ;
2013-10-09 10:56:58 -05:00
[ statusField setStringValue : @ "Loading Revisions" ] ;
2011-07-07 13:06:03 -05:00
[ connectionManager addHandler : handler ] ;
}
- ( void ) registerDefaults {
NSMutableDictionary * defaults = [ NSMutableDictionary dictionary ] ;
[ defaults setObject : [ NSNumber numberWithInt : 1 ] forKey : MGMLaunchCount ] ;
[ defaults setObject : [ NSNumber numberWithInt : 4 ] forKey : MGMChannel ] ;
[ defaults setObject : [ NSNumber numberWithBool : YES ] forKey : MGMMoveToTrash ] ;
[ defaults setObject : [ NSNumber numberWithBool : YES ] forKey : MGMDoneSound ] ;
[ defaults setObject : [ NSNumber numberWithBool : NO ] forKey : MGMLaunchWhenDone ] ;
[ defaults setObject : [ NSNumber numberWithBool : NO ] forKey : MGMQuitAfterLaunch ] ;
[ [ NSUserDefaults standardUserDefaults ] registerDefaults : defaults ] ;
}
- ( IBAction ) about : ( id ) sender {
[ about show ] ;
}
- ( IBAction ) preferences : ( id ) sender {
[ preferences showPreferences ] ;
}
- ( IBAction ) donate : ( id ) sender {
[ [ NSWorkspace sharedWorkspace ] openURL : [ NSURL URLWithString : @ "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=9184741" ] ] ;
}
- ( IBAction ) openSource : ( id ) sender {
[ [ NSWorkspace sharedWorkspace ] openURL : [ NSURL URLWithString : @ "http://opensource.mrgeckosmedia.com/Chromatic?application" ] ] ;
}
- ( void ) channels : ( MGMURLBasicHandler * ) theHandler didFailWithError : ( NSError * ) theError {
NSLog ( @ "%@" , theError ) ;
NSAlert * alert = [ [ NSAlert new ] autorelease ] ;
[ alert setMessageText : @ "Error loading channel info" ] ;
[ alert setInformativeText : [ theError localizedDescription ] ] ;
[ alert runModal ] ;
}
- ( void ) channelsFinished : ( MGMURLBasicHandler * ) theHandler {
NSArray * versions = [ [ [ [ theHandler data ] parseJSON ] objectAtIndex : 0 ] objectForKey : @ "versions" ] ;
if ( versions = = nil ) {
NSAlert * alert = [ [ NSAlert new ] autorelease ] ;
[ alert setMessageText : @ "Error loading channel info" ] ;
[ alert setInformativeText : @ "The JSON was unable to be parsed." ] ;
[ alert runModal ] ;
}
for ( int i = 0 ; i < [ versions count ] ; i + + ) {
NSDictionary * versionInfo = [ versions objectAtIndex : i ] ;
2011-12-28 10:36:16 -06:00
id channel = [ versionInfo objectForKey : MGMCRevision ] ;
[ channelRevisions setObject : ( [ channel isKindOfClass : [ NSString class ] ] ? channel : [ channel stringValue ] ) forKey : [ versionInfo objectForKey : MGMCChannel ] ] ;
2011-07-07 13:06:03 -05:00
}
[ progress setIndeterminate : NO ] ;
[ progress startAnimation : self ] ;
[ progress setDoubleValue : 0.25 ] ;
}
- ( void ) revisions : ( MGMURLBasicHandler * ) theHandler didFailWithError : ( NSError * ) theError {
NSLog ( @ "%@" , theError ) ;
NSAlert * alert = [ [ NSAlert new ] autorelease ] ;
[ alert setMessageText : @ "Error loading revisions" ] ;
[ alert setInformativeText : [ theError localizedDescription ] ] ;
[ alert runModal ] ;
NSMenu * items = [ NSMenu new ] ;
2011-09-15 20:54:40 -05:00
[ revisionsArray sortUsingSelector : @ selector ( numberCompare : ) ] ;
for ( unsigned int i = 0 ; i < [ revisionsArray count ] ; i + + ) {
2011-07-07 13:06:03 -05:00
NSMenuItem * item = [ NSMenuItem new ] ;
2011-09-15 20:54:40 -05:00
[ item setTitle : [ revisionsArray objectAtIndex : i ] ] ;
2011-07-07 13:06:03 -05:00
[ items addItem : item ] ;
[ item release ] ;
}
2011-09-15 20:54:40 -05:00
[ buildPopUp removeAllItems ] ;
2011-07-07 13:06:03 -05:00
[ buildPopUp setMenu : items ] ;
[ items release ] ;
2011-09-15 20:54:40 -05:00
[ revisionsArray release ] ;
revisionsArray = nil ;
2011-07-07 13:06:03 -05:00
[ self channelSelect : self ] ;
}
2011-09-15 20:54:40 -05:00
- ( void ) revisionsFinished : ( MGMURLBasicHandler * ) theHandler {
NSError * error = nil ;
NSXMLDocument * xml = [ [ NSXMLDocument alloc ] initWithData : [ theHandler data ] options : NSXMLDocumentTidyXML error : & error ] ;
[ progress setDoubleValue : 0.50 ] ;
if ( error ! = nil ) {
NSLog ( @ "%@" , error ) ;
NSAlert * alert = [ [ NSAlert new ] autorelease ] ;
[ alert setMessageText : @ "Error parsing revisions" ] ;
[ alert setInformativeText : [ error localizedDescription ] ] ;
[ alert runModal ] ;
NSMenu * items = [ NSMenu new ] ;
[ revisionsArray sortUsingSelector : @ selector ( numberCompare : ) ] ;
for ( unsigned int i = 0 ; i < [ revisionsArray count ] ; i + + ) {
NSMenuItem * item = [ NSMenuItem new ] ;
[ item setTitle : [ revisionsArray objectAtIndex : i ] ] ;
[ items addItem : item ] ;
[ item release ] ;
}
[ buildPopUp removeAllItems ] ;
[ buildPopUp setMenu : items ] ;
[ items release ] ;
[ revisionsArray release ] ;
revisionsArray = nil ;
[ self channelSelect : self ] ;
} else {
NSXMLElement * rootElement = [ xml rootElement ] ;
NSArray * isTruncated = [ rootElement elementsForName : @ "IsTruncated" ] ;
NSArray * commonPrefixes = [ rootElement elementsForName : @ "CommonPrefixes" ] ;
for ( int i = 0 ; i < [ commonPrefixes count ] ; i + + ) {
NSArray * prefix = [ [ commonPrefixes objectAtIndex : i ] elementsForName : @ "Prefix" ] ;
if ( [ prefix count ] < 1 )
continue ;
NSArray * parsed = [ [ [ prefix objectAtIndex : 0 ] stringValue ] componentsSeparatedByString : @ "/" ] ;
if ( [ parsed count ] < 2 )
continue ;
2013-10-09 10:56:58 -05:00
if ( [ [ parsed objectAtIndex : 1 ] length ] >= 40 )
continue ;
2011-09-15 20:54:40 -05:00
[ revisionsArray addObject : [ parsed objectAtIndex : 1 ] ] ;
}
NSArray * nextMarkers = [ rootElement elementsForName : @ "NextMarker" ] ;
if ( [ isTruncated count ] > 0 && [ [ [ isTruncated objectAtIndex : 0 ] stringValue ] isEqual : @ "true" ] && [ nextMarkers count ] > 0 ) {
NSString * nextMarker = [ [ nextMarkers objectAtIndex : 0 ] stringValue ] ;
NSString * url = [ MGMSnapshotURL stringByAppendingFormat : @ "?delimiter=/&prefix=%@&marker=%@" , MGMSnapshotPrefix , nextMarker ] ;
MGMURLBasicHandler * handler = [ MGMURLBasicHandler handlerWithRequest : [ NSURLRequest requestWithURL : [ NSURL URLWithString : url ] ] delegate : self ] ;
[ handler setFailWithError : @ selector ( revisions : didFailWithError : ) ] ;
[ handler setFinish : @ selector ( revisionsFinished : ) ] ;
[ connectionManager addHandler : handler ] ;
} else {
NSMenu * items = [ NSMenu new ] ;
[ revisionsArray sortUsingSelector : @ selector ( numberCompare : ) ] ;
for ( unsigned int i = 0 ; i < [ revisionsArray count ] ; i + + ) {
NSMenuItem * item = [ NSMenuItem new ] ;
[ item setTitle : [ revisionsArray objectAtIndex : i ] ] ;
[ items addItem : item ] ;
[ item release ] ;
}
[ buildPopUp removeAllItems ] ;
[ buildPopUp setMenu : items ] ;
[ items release ] ;
[ revisionsArray release ] ;
revisionsArray = nil ;
2013-10-09 10:56:58 -05:00
[ statusField setStringValue : @ "" ] ;
2011-09-15 20:54:40 -05:00
[ self channelSelect : self ] ;
}
}
[ xml release ] ;
}
2011-07-07 13:06:03 -05:00
- ( IBAction ) channelSelect : ( id ) sender {
[ [ NSUserDefaults standardUserDefaults ] setInteger : [ channelPopUp indexOfSelectedItem ] forKey : MGMChannel ] ;
NSArray * revisions = [ buildPopUp itemTitles ] ;
NSString * revision = nil ;
if ( [ channelPopUp indexOfSelectedItem ] = = 0 )
revision = [ channelRevisions objectForKey : MGMCStable ] ;
else if ( [ channelPopUp indexOfSelectedItem ] = = 1 )
revision = [ channelRevisions objectForKey : MGMCBeta ] ;
else if ( [ channelPopUp indexOfSelectedItem ] = = 2 )
revision = [ channelRevisions objectForKey : MGMCDev ] ;
else if ( [ channelPopUp indexOfSelectedItem ] = = 3 )
revision = [ channelRevisions objectForKey : MGMCCanary ] ;
if ( revision = = nil )
revision = [ revisions lastObject ] ;
long itemIndex = [ revisions indexOfObject : revision ] ;
if ( itemIndex = = NSNotFound ) {
[ buildWarningField setHidden : NO ] ;
for ( unsigned int i = 0 ; i < [ revisions count ] ; i + + ) {
2011-09-15 20:54:40 -05:00
if ( [ ( NSString * ) [ revisions objectAtIndex : i ] numberCompare : revision ] = = NSOrderedDescending ) {
2011-07-07 13:06:03 -05:00
itemIndex = i ;
break ;
}
}
if ( itemIndex = = NSNotFound )
itemIndex = [ revisions count ] -1 ;
} else {
[ buildWarningField setHidden : YES ] ;
}
[ buildPopUp selectItemAtIndex : itemIndex ] ;
if ( startingUp )
[ progress setDoubleValue : 0.75 ] ;
[ self buildSelect : self ] ;
}
- ( IBAction ) buildSelect : ( id ) sender {
2011-09-15 20:54:40 -05:00
NSURL * buildURL = [ [ [ [ NSURL URLWithString : MGMSnapshotURL ] appendPathComponent : MGMSnapshotPrefix ] appendPathComponent : [ buildPopUp titleOfSelectedItem ] ] appendPathComponent : @ "REVISIONS" ] ;
2011-07-07 13:06:03 -05:00
MGMURLBasicHandler * handler = [ MGMURLBasicHandler handlerWithRequest : [ NSURLRequest requestWithURL : buildURL ] delegate : self ] ;
[ handler setFailWithError : @ selector ( revision : didFailWithError : ) ] ;
[ handler setReceiveResponse : @ selector ( revision : didReceiveResponse : ) ] ;
[ handler setFinish : @ selector ( revisionDidFinish : ) ] ;
[ connectionManager addHandler : handler ] ;
if ( ! [ [ yourBuildField stringValue ] isEqual : @ "" ] && [ buildPopUp indexOfSelectedItem ] ! = -1 && ! [ [ yourBuildField stringValue ] isEqual : [ buildPopUp titleOfSelectedItem ] ] )
[ svnLogsButton setEnabled : YES ] ;
else
[ svnLogsButton setEnabled : NO ] ;
}
- ( void ) revision : ( MGMURLBasicHandler * ) theHandler didFailWithError : ( NSError * ) theError {
NSLog ( @ "%@" , theError ) ;
NSAlert * alert = [ [ NSAlert new ] autorelease ] ;
[ alert setMessageText : @ "Error loading revision info" ] ;
[ alert setInformativeText : [ theError localizedDescription ] ] ;
[ alert runModal ] ;
if ( startingUp ) {
[ progress setDoubleValue : 1.0 ] ;
[ progress setIndeterminate : YES ] ;
[ progress setDoubleValue : 0.0 ] ;
[ progress stopAnimation : self ] ;
[ updateButton setEnabled : YES ] ;
startingUp = NO ;
}
}
- ( void ) revision : ( MGMURLBasicHandler * ) theHandler didReceiveResponse : ( NSHTTPURLResponse * ) theResponse {
NSString * modified = [ [ theResponse allHeaderFields ] objectForKey : @ "Last-Modified" ] ;
NSDateFormatter * formatter = [ NSDateFormatter new ] ;
[ formatter setLocale : [ [ [ NSLocale alloc ] initWithLocaleIdentifier : @ "en_US" ] autorelease ] ] ;
[ formatter setDateFormat : @ "EEE, dd MMM yyyy HH:mm:ss zzz" ] ;
NSDate * date = [ formatter dateFromString : modified ] ;
[ formatter release ] ;
formatter = [ NSDateFormatter new ] ;
[ formatter setDateFormat : @ "MMMM d, yyyy hh:mm:ss a" ] ;
NSString * dateString = [ formatter stringFromDate : date ] ;
[ formatter release ] ;
if ( dateString ! = nil )
[ buildDateField setStringValue : dateString ] ;
else
[ buildDateField setStringValue : @ "N/A" ] ;
}
- ( void ) revisionDidFinish : ( MGMURLBasicHandler * ) theHandler {
NSDictionary * revisionInfo = [ [ theHandler data ] parseJSON ] ;
NSString * webkit = [ [ revisionInfo objectForKey : @ "webkit_revision" ] stringValue ] ;
if ( webkit ! = nil )
[ webKitBuildField setStringValue : webkit ] ;
else
[ webKitBuildField setStringValue : @ "0" ] ;
NSString * v8 = [ [ revisionInfo objectForKey : @ "v8_revision" ] stringValue ] ;
if ( v8 ! = nil )
[ v8BuildField setStringValue : v8 ] ;
else
[ v8BuildField setStringValue : @ "0" ] ;
if ( startingUp ) {
[ progress setDoubleValue : 1.0 ] ;
[ progress setIndeterminate : YES ] ;
[ progress setDoubleValue : 0.0 ] ;
[ progress stopAnimation : self ] ;
[ updateButton setEnabled : YES ] ;
startingUp = NO ;
}
}
- ( IBAction ) choosePath : ( id ) sender {
NSOpenPanel * openPanel = [ NSOpenPanel openPanel ] ;
if ( [ openPanel respondsToSelector : @ selector ( setDirectory : ) ] )
[ openPanel setDirectory : [ chromiumPath stringByDeletingLastPathComponent ] ] ;
else
[ openPanel setDirectoryURL : [ NSURL fileURLWithPath : [ chromiumPath stringByDeletingLastPathComponent ] ] ] ;
[ openPanel setCanChooseFiles : NO ] ;
[ openPanel setCanChooseDirectories : YES ] ;
[ openPanel setAllowsMultipleSelection : NO ] ;
[ openPanel setTitle : @ "Choose path for Chromium" ] ;
[ openPanel setPrompt : @ "Choose" ] ;
int result = [ openPanel runModal ] ;
if ( result = = NSOKButton ) {
NSString * newPath = [ [ [ openPanel URLs ] objectAtIndex : 0 ] path ] ;
NSFileManager * manager = [ NSFileManager defaultManager ] ;
if ( [ manager isWritableFileAtPath : newPath ] ) {
[ chromiumPath release ] ;
chromiumPath = [ [ newPath stringByAppendingPathComponent : MGMCPChromium ] retain ] ;
[ [ NSUserDefaults standardUserDefaults ] setObject : chromiumPath forKey : MGMChromiumPath ] ;
[ self updateChromiumPath ] ;
} else {
NSAlert * alert = [ [ NSAlert new ] autorelease ] ;
[ alert setInformativeText : @ "Not Writable" ] ;
[ alert setMessageText : @ "The directory you choose is not writable. To beable to use it with Chromatic, you need to change permissions." ] ;
[ alert runModal ] ;
}
}
}
- ( void ) updateChromiumPath {
NSFileManager * manager = [ NSFileManager defaultManager ] ;
if ( [ manager fileExistsAtPath : chromiumPath ] ) {
NSDictionary * chromiumInfo = ( NSDictionary * ) CFBundleCopyInfoDictionaryInDirectory ( ( CFURLRef ) [ NSURL fileURLWithPath : chromiumPath ] ) ;
2012-09-01 07:02:34 -05:00
NSString * build = [ chromiumInfo objectForKey : @ "SVNRevision" ] ;
if ( build = = nil )
build = [ chromiumInfo objectForKey : @ "SCMRevision" ] ;
if ( build ! = nil )
[ yourBuildField setStringValue : build ] ;
2011-07-07 13:06:03 -05:00
[ chromiumInfo release ] ;
NSDictionary * chromeAttributes = [ manager attributesOfItemAtPath : chromiumPath ] ;
NSDate * date = [ chromeAttributes objectForKey : NSFileModificationDate ] ;
NSDateFormatter * formatter = [ [ NSDateFormatter new ] autorelease ] ;
[ formatter setDateFormat : @ "MMMM d, yyyy hh:mm:ss a" ] ;
[ installDateField setStringValue : [ formatter stringFromDate : date ] ] ;
[ launchButton setEnabled : YES ] ;
[ updateButton setTitle : MGMUBUpdate ] ;
if ( ! [ [ yourBuildField stringValue ] isEqual : @ "" ] && [ buildPopUp indexOfSelectedItem ] ! = -1 && ! [ [ yourBuildField stringValue ] isEqual : [ buildPopUp titleOfSelectedItem ] ] )
[ svnLogsButton setEnabled : YES ] ;
else
[ svnLogsButton setEnabled : NO ] ;
} else {
[ launchButton setEnabled : NO ] ;
[ svnLogsButton setEnabled : NO ] ;
[ yourBuildField setStringValue : @ "" ] ;
[ installDateField setStringValue : @ "" ] ;
[ updateButton setTitle : MGMUBInstall ] ;
}
[ pathField setStringValue : [ chromiumPath stringByDeletingLastPathComponent ] ] ;
}
- ( IBAction ) launchChromium : ( id ) sender {
[ [ NSWorkspace sharedWorkspace ] launchApplication : chromiumPath ] ;
if ( [ [ NSUserDefaults standardUserDefaults ] boolForKey : MGMQuitAfterLaunch ] )
[ [ NSApplication sharedApplication ] terminate : self ] ;
}
- ( IBAction ) viewSVNLogs : ( id ) sender {
NSString * revision1 , * revision2 , * tmp ;
revision1 = [ yourBuildField stringValue ] ;
revision2 = [ buildPopUp titleOfSelectedItem ] ;
2011-09-15 20:54:40 -05:00
if ( [ revision1 numberCompare : revision2 ] = = NSOrderedDescending ) {
2011-07-07 13:06:03 -05:00
tmp = revision1 ;
revision1 = revision2 ;
revision2 = tmp ;
}
NSURL * url = [ NSURL URLWithString : [ NSString stringWithFormat : MGMSVNLogsURL , revision1 , revision2 ] ] ;
[ [ svnLogsBrowser mainFrame ] loadRequest : [ NSURLRequest requestWithURL : url ] ] ;
[ svnLogsWindow makeKeyAndOrderFront : self ] ;
}
- ( IBAction ) update : ( id ) sender {
if ( [ [ updateButton title ] isEqual : MGMUBCancel ] ) {
[ connectionManager cancelHandler : updateHandler ] ;
[ updateHandler release ] ;
updateHandler = nil ;
[ [ NSFileManager defaultManager ] removeItemAtPath : [ MGMTMPPath stringByAppendingPathComponent : MGMChromiumZip ] ] ;
[ self updateDone ] ;
} else {
[ progress startAnimation : self ] ;
startTime = [ [ NSDate date ] timeIntervalSince1970 ] ;
2011-09-15 20:54:40 -05:00
NSURL * url = [ [ [ [ NSURL URLWithString : MGMSnapshotURL ] appendPathComponent : MGMSnapshotPrefix ] appendPathComponent : [ buildPopUp titleOfSelectedItem ] ] appendPathComponent : MGMChromiumZip ] ;
2011-07-07 13:06:03 -05:00
[ updateHandler release ] ;
updateHandler = [ [ MGMURLBasicHandler handlerWithRequest : [ NSURLRequest requestWithURL : url ] delegate : self ] retain ] ;
[ updateHandler setFile : [ MGMTMPPath stringByAppendingPathComponent : MGMChromiumZip ] ] ;
[ updateHandler setFailWithError : @ selector ( update : didFailWithError : ) ] ;
[ updateHandler setReceiveResponse : @ selector ( update : didReceiveResponse : ) ] ;
[ updateHandler setBytesReceived : @ selector ( update : receivedBytes : totalBytes : expectedBytes : ) ] ;
[ updateHandler setFinish : @ selector ( updateDidFinish : ) ] ;
[ updateHandler setSynchronous : NO ] ;
[ connectionManager addHandler : updateHandler ] ;
[ channelPopUp setEnabled : NO ] ;
[ buildPopUp setEnabled : NO ] ;
[ updateButton setTitle : MGMUBCancel ] ;
}
}
- ( void ) windowWillClose : ( NSNotification * ) notification {
[ [ svnLogsBrowser mainFrame ] loadHTMLString : @ "" baseURL : nil ] ;
}
- ( void ) update : ( MGMURLBasicHandler * ) theHandler didFailWithError : ( NSError * ) theError {
NSLog ( @ "%@" , theError ) ;
NSAlert * alert = [ [ NSAlert new ] autorelease ] ;
[ alert setMessageText : @ "Error downloading update" ] ;
[ alert setInformativeText : [ theError localizedDescription ] ] ;
[ alert runModal ] ;
}
- ( void ) update : ( MGMURLBasicHandler * ) theHandler didReceiveResponse : ( NSHTTPURLResponse * ) theResponse {
[ progress setIndeterminate : NO ] ;
[ progress startAnimation : self ] ;
bytesReceivedArray = [ NSMutableArray new ] ;
}
- ( void ) update : ( MGMURLBasicHandler * ) theHandler receivedBytes : ( unsigned long ) theBytes totalBytes : ( unsigned long ) theTotalBytes expectedBytes : ( unsigned long ) theExpectedBytes {
bytesReceived + = theBytes ;
if ( lastCheck = = nil || [ lastCheck timeIntervalSinceNow ] < -1.0 ) {
[ lastCheck release ] ;
lastCheck = [ NSDate new ] ;
while ( [ bytesReceivedArray count ] > 15 ) {
[ bytesReceivedArray removeObjectAtIndex : 0 ] ;
}
[ bytesReceivedArray addObject : [ NSNumber numberWithUnsignedLong : bytesReceived ] ] ;
averageBytesReceived = 0 ;
for ( int i = 0 ; i < [ bytesReceivedArray count ] ; i + + ) {
averageBytesReceived + = [ [ bytesReceivedArray objectAtIndex : i ] unsignedLongValue ] ;
}
averageBytesReceived / = [ bytesReceivedArray count ] ;
[ statusField setStringValue : [ NSString stringWithFormat : @ "%@ of %@ (%@/sec) - %@" , [ NSString readableMemory : theTotalBytes ] , [ NSString readableMemory : theExpectedBytes ] , [ NSString readableMemory : bytesReceived ] , [ NSString readableTime : ( theExpectedBytes - theTotalBytes ) / averageBytesReceived ] ] ] ;
bytesReceived = 0 ;
}
[ progress setDoubleValue : ( double ) theTotalBytes / ( double ) theExpectedBytes ] ;
totalBytes = theTotalBytes ;
}
- ( void ) updateDidFinish : ( MGMURLBasicHandler * ) theHandler {
[ updateHandler release ] ;
updateHandler = nil ;
[ bytesReceivedArray release ] ;
bytesReceivedArray = nil ;
[ updateButton setEnabled : NO ] ;
[ progress setIndeterminate : YES ] ;
[ progress startAnimation : self ] ;
[ statusField setStringValue : @ "Uncompressing and installing update." ] ;
unzipTask = [ NSTask new ] ;
[ unzipTask setLaunchPath : @ "/usr/bin/ditto" ] ;
[ unzipTask setArguments : [ NSArray arrayWithObjects : @ "-v" , @ "-x" , @ "-k" , @ "--rsrc" , [ MGMTMPPath stringByAppendingPathComponent : MGMChromiumZip ] , MGMTMPPath , nil ] ] ;
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( updateUnzipped : ) name : NSTaskDidTerminateNotification object : unzipTask ] ;
[ unzipTask launch ] ;
}
- ( void ) updateUnzipped : ( NSNotification * ) theNotification {
NSUserDefaults * defaults = [ NSUserDefaults standardUserDefaults ] ;
NSFileManager * manager = [ NSFileManager defaultManager ] ;
if ( [ manager fileExistsAtPath : chromiumPath ] ) {
if ( [ defaults boolForKey : MGMMoveToTrash ] ) {
NSString * trash = [ @ "~/.Trash" stringByExpandingTildeInPath ] ;
NSInteger tag ;
[ [ NSWorkspace sharedWorkspace ] performFileOperation : NSWorkspaceRecycleOperation source : [ chromiumPath stringByDeletingLastPathComponent ] destination : trash files : [ NSArray arrayWithObject : [ chromiumPath lastPathComponent ] ] tag : & tag ] ;
if ( tag ! = 0 )
NSLog ( @ "Error Deleting: %ld" , ( long ) tag ) ;
} else {
[ manager removeItemAtPath : chromiumPath ] ;
}
}
NSString * extractedPath = [ [ MGMTMPPath stringByAppendingPathComponent : [ MGMChromiumZip stringByDeletingPathExtension ] ] stringByAppendingPathComponent : MGMCPChromium ] ;
if ( ! [ manager moveItemAtPath : extractedPath toPath : chromiumPath ] ) {
NSBeep ( ) ;
[ self updateDone ] ;
[ statusField setStringValue : [ NSString stringWithFormat : @ "Unable to %@ due to an error. This may be a permissions issue." , [ [ updateButton title ] lowercaseString ] ] ] ;
return ;
}
[ manager removeItemAtPath : [ extractedPath stringByDeletingLastPathComponent ] ] ;
[ manager removeItemAtPath : [ MGMTMPPath stringByAppendingPathComponent : MGMChromiumZip ] ] ;
[ manager setAttributes : [ NSDictionary dictionaryWithObject : [ NSDate date ] forKey : NSFileModificationDate ] ofItemAtPath : chromiumPath ] ;
[ NSThread sleepUntilDate : [ NSDate dateWithTimeIntervalSinceNow : 1 ] ] ;
[ self updateDone ] ;
int time = [ [ NSDate date ] timeIntervalSince1970 ] - startTime ;
[ statusField setStringValue : [ NSString stringWithFormat : @ "%@ downloaded at %@/sec in %@" , [ NSString readableMemory : totalBytes ] , [ NSString readableMemory : averageBytesReceived ] , [ NSString readableTime : time ] ] ] ;
if ( [ defaults boolForKey : MGMDoneSound ] ) {
NSSound * done = [ NSSound soundNamed : @ "Glass" ] ;
[ done setDelegate : self ] ;
[ done play ] ;
}
[ updateButton setEnabled : YES ] ;
if ( [ defaults boolForKey : MGMLaunchWhenDone ] && [ defaults boolForKey : MGMDoneSound ] && ! [ defaults boolForKey : MGMQuitAfterLaunch ] )
[ self launchChromium : self ] ;
}
- ( void ) sound : ( NSSound * ) sound didFinishPlaying : ( BOOL ) didFinish {
if ( didFinish ) {
[ sound release ] ;
NSUserDefaults * defaults = [ NSUserDefaults standardUserDefaults ] ;
if ( [ defaults boolForKey : MGMLaunchWhenDone ] && [ defaults boolForKey : MGMQuitAfterLaunch ] )
[ self launchChromium : self ] ;
}
}
- ( void ) updateDone {
[ self updateChromiumPath ] ;
[ channelPopUp setEnabled : YES ] ;
[ buildPopUp setEnabled : YES ] ;
[ progress setIndeterminate : YES ] ;
[ progress setDoubleValue : 0.0 ] ;
[ progress stopAnimation : self ] ;
[ statusField setStringValue : @ "" ] ;
}
- ( void ) applicationWillTerminate : ( NSNotification * ) aNotification {
if ( updateHandler ! = nil )
[ self update : self ] ;
}
@ end