| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "chrome/browser/cocoa/about_window_controller.h" |
| 6 |
| 5 #include "app/l10n_util_mac.h" | 7 #include "app/l10n_util_mac.h" |
| 6 #include "app/resource_bundle.h" | 8 #include "app/resource_bundle.h" |
| 7 #include "base/logging.h" | 9 #include "base/logging.h" |
| 8 #include "base/mac_util.h" | 10 #include "base/mac_util.h" |
| 9 #include "base/string_util.h" | 11 #include "base/string_util.h" |
| 10 #include "base/sys_string_conversions.h" | 12 #include "base/sys_string_conversions.h" |
| 11 #import "chrome/app/keystone_glue.h" | |
| 12 #include "chrome/browser/browser_list.h" | 13 #include "chrome/browser/browser_list.h" |
| 13 #import "chrome/browser/cocoa/about_window_controller.h" | |
| 14 #import "chrome/browser/cocoa/background_tile_view.h" | 14 #import "chrome/browser/cocoa/background_tile_view.h" |
| 15 #import "chrome/browser/cocoa/keystone_glue.h" |
| 15 #include "chrome/browser/cocoa/restart_browser.h" | 16 #include "chrome/browser/cocoa/restart_browser.h" |
| 16 #include "grit/chromium_strings.h" | 17 #include "grit/chromium_strings.h" |
| 17 #include "grit/generated_resources.h" | 18 #include "grit/generated_resources.h" |
| 18 #include "grit/theme_resources.h" | 19 #include "grit/theme_resources.h" |
| 19 #include "grit/locale_settings.h" | 20 #include "grit/locale_settings.h" |
| 20 #include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" | 21 #include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" |
| 21 | 22 |
| 22 namespace { | 23 namespace { |
| 23 | 24 |
| 24 void AttributedStringAppendString(NSMutableAttributedString* attr_str, | 25 void AttributedStringAppendString(NSMutableAttributedString* attr_str, |
| (...skipping 27 matching lines...) Expand all Loading... |
| 52 range:range]; | 53 range:range]; |
| 53 } | 54 } |
| 54 | 55 |
| 55 } // namespace | 56 } // namespace |
| 56 | 57 |
| 57 @interface AboutWindowController(Private) | 58 @interface AboutWindowController(Private) |
| 58 | 59 |
| 59 // Launches a check for available updates. | 60 // Launches a check for available updates. |
| 60 - (void)checkForUpdate; | 61 - (void)checkForUpdate; |
| 61 | 62 |
| 63 // Turns the update and promotion blocks on and off as needed based on whether |
| 64 // updates are possible and promotion is desired or required. |
| 65 - (void)adjustUpdateUIVisibility; |
| 66 |
| 67 // Maintains the update and promotion block visibility and window sizing. |
| 68 // This uses bool instead of BOOL for the convenience of the internal |
| 69 // implementation. |
| 70 - (void)setAllowsUpdate:(bool)update allowsPromotion:(bool)promotion; |
| 71 |
| 62 // Notification callback, called with the status of asynchronous | 72 // Notification callback, called with the status of asynchronous |
| 63 // -checkForUpdate and -updateNow: operations. | 73 // -checkForUpdate and -updateNow: operations. |
| 64 - (void)updateStatus:(NSNotification*)notification; | 74 - (void)updateStatus:(NSNotification*)notification; |
| 65 | 75 |
| 66 // These methods maintain the image (or throbber) and text displayed regarding | 76 // These methods maintain the image (or throbber) and text displayed regarding |
| 67 // update status. -setUpdateThrobberMessage: starts a progress throbber and | 77 // update status. -setUpdateThrobberMessage: starts a progress throbber and |
| 68 // sets the text. -setUpdateImage:message: displays an image and sets the | 78 // sets the text. -setUpdateImage:message: displays an image and sets the |
| 69 // text. | 79 // text. |
| 70 - (void)setUpdateThrobberMessage:(NSString*)message; | 80 - (void)setUpdateThrobberMessage:(NSString*)message; |
| 71 - (void)setUpdateImage:(int)imageID message:(NSString*)message; | 81 - (void)setUpdateImage:(int)imageID message:(NSString*)message; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 99 } | 109 } |
| 100 | 110 |
| 101 - (void)dealloc { | 111 - (void)dealloc { |
| 102 [[NSNotificationCenter defaultCenter] removeObserver:self]; | 112 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 103 [super dealloc]; | 113 [super dealloc]; |
| 104 } | 114 } |
| 105 | 115 |
| 106 // YES when an About box is currently showing the kAutoupdateInstallFailed | 116 // YES when an About box is currently showing the kAutoupdateInstallFailed |
| 107 // status, or if no About box is visible, if the most recent About box to be | 117 // status, or if no About box is visible, if the most recent About box to be |
| 108 // closed was closed while showing this status. When an About box opens, if | 118 // closed was closed while showing this status. When an About box opens, if |
| 109 // the recent status is kAutoupdateInstallFailed and | 119 // the recent status is kAutoupdateInstallFailed or kAutoupdatePromoteFailed |
| 110 // recentShownInstallFailedStatus is NO, the failure needs to be shown instead | 120 // and recentShownUserActionFailedStatus is NO, the failure needs to be shown |
| 111 // of launching a new update check. recentShownInstallFailedStatus is | 121 // instead of launching a new update check. recentShownInstallFailedStatus is |
| 112 // maintained by -updateStatus:. | 122 // maintained by -updateStatus:. |
| 113 static BOOL recentShownInstallFailedStatus = NO; | 123 static BOOL recentShownUserActionFailedStatus = NO; |
| 114 | 124 |
| 115 - (void)awakeFromNib { | 125 - (void)awakeFromNib { |
| 116 NSBundle* bundle = mac_util::MainAppBundle(); | 126 NSBundle* bundle = mac_util::MainAppBundle(); |
| 117 NSString* chromeVersion = | 127 NSString* chromeVersion = |
| 118 [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; | 128 [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; |
| 119 | 129 |
| 120 #if defined(GOOGLE_CHROME_BUILD) | 130 #if defined(GOOGLE_CHROME_BUILD) |
| 121 NSString* version = chromeVersion; | 131 NSString* version = chromeVersion; |
| 122 #else // GOOGLE_CHROME_BUILD | 132 #else // GOOGLE_CHROME_BUILD |
| 123 // The format string is not localized, but this is how the displayed version | 133 // The format string is not localized, but this is how the displayed version |
| (...skipping 15 matching lines...) Expand all Loading... |
| 139 [logoView_ setImage:logoImage]; | 149 [logoView_ setImage:logoImage]; |
| 140 | 150 |
| 141 [[legalText_ textStorage] setAttributedString:[[self class] legalTextBlock]]; | 151 [[legalText_ textStorage] setAttributedString:[[self class] legalTextBlock]]; |
| 142 | 152 |
| 143 // Resize our text view now so that the |updateShift| below is set | 153 // Resize our text view now so that the |updateShift| below is set |
| 144 // correctly. The About box has its controls manually positioned, so we need | 154 // correctly. The About box has its controls manually positioned, so we need |
| 145 // to calculate how much larger (or smaller) our text box is and store that | 155 // to calculate how much larger (or smaller) our text box is and store that |
| 146 // difference in |legalShift|. We do something similar with |updateShift| | 156 // difference in |legalShift|. We do something similar with |updateShift| |
| 147 // below, which is either 0, or the amount of space to offset the window size | 157 // below, which is either 0, or the amount of space to offset the window size |
| 148 // because the view that contains the update button has been removed because | 158 // because the view that contains the update button has been removed because |
| 149 // this build doesn't have KeyStone. | 159 // this build doesn't have Keystone. |
| 150 NSRect oldLegalRect = [legalBlock_ frame]; | 160 NSRect oldLegalRect = [legalBlock_ frame]; |
| 151 [legalText_ sizeToFit]; | 161 [legalText_ sizeToFit]; |
| 152 NSRect newRect = oldLegalRect; | 162 NSRect newRect = oldLegalRect; |
| 153 newRect.size.height = [legalText_ frame].size.height; | 163 newRect.size.height = [legalText_ frame].size.height; |
| 154 [legalBlock_ setFrame:newRect]; | 164 [legalBlock_ setFrame:newRect]; |
| 155 CGFloat legalShift = newRect.size.height - oldLegalRect.size.height; | 165 CGFloat legalShift = newRect.size.height - oldLegalRect.size.height; |
| 156 | 166 |
| 157 KeystoneGlue* keystoneGlue = [KeystoneGlue defaultKeystoneGlue]; | 167 NSRect backgroundFrame = [backgroundView_ frame]; |
| 158 CGFloat updateShift; | 168 backgroundFrame.origin.y += legalShift; |
| 159 if (keystoneGlue) { | 169 [backgroundView_ setFrame:backgroundFrame]; |
| 170 |
| 171 NSSize windowDelta = NSMakeSize(0.0, legalShift); |
| 172 [GTMUILocalizerAndLayoutTweaker |
| 173 resizeWindowWithoutAutoResizingSubViews:[self window] |
| 174 delta:windowDelta]; |
| 175 |
| 176 windowHeight_ = [[self window] frame].size.height; |
| 177 |
| 178 [self adjustUpdateUIVisibility]; |
| 179 |
| 180 // Don't do anything update-related if adjustUpdateUIVisibility decided that |
| 181 // updates aren't possible. |
| 182 if (![updateBlock_ isHidden]) { |
| 183 KeystoneGlue* keystoneGlue = [KeystoneGlue defaultKeystoneGlue]; |
| 184 AutoupdateStatus recentStatus = [keystoneGlue recentStatus]; |
| 160 if ([keystoneGlue asyncOperationPending] || | 185 if ([keystoneGlue asyncOperationPending] || |
| 161 ([keystoneGlue recentStatus] == kAutoupdateInstallFailed && | 186 recentStatus == kAutoupdateRegisterFailed || |
| 162 !recentShownInstallFailedStatus)) { | 187 ((recentStatus == kAutoupdateInstallFailed || |
| 188 recentStatus == kAutoupdatePromoteFailed) && |
| 189 !recentShownUserActionFailedStatus)) { |
| 163 // If an asynchronous update operation is currently pending, such as a | 190 // If an asynchronous update operation is currently pending, such as a |
| 164 // check for updates or an update installation attempt, set the status | 191 // check for updates or an update installation attempt, set the status |
| 165 // up correspondingly without launching a new update check. | 192 // up correspondingly without launching a new update check. |
| 166 // | 193 // |
| 167 // If a previous update attempt was unsuccessful but no About box was | 194 // If registration failed, no other operations make sense, so just go |
| 168 // around to report the error, show it now, and allow another chance to | 195 // straight to the error. |
| 169 // install the update. | 196 // |
| 197 // If a previous update or promotion attempt was unsuccessful but no |
| 198 // About box was around to report the error, show it now, and allow |
| 199 // another chance to perform the action. |
| 170 [self updateStatus:[keystoneGlue recentNotification]]; | 200 [self updateStatus:[keystoneGlue recentNotification]]; |
| 171 } else { | 201 } else { |
| 172 // Launch a new update check, even if one was already completed, because | 202 // Launch a new update check, even if one was already completed, because |
| 173 // a new update may be available or a new update may have been installed | 203 // a new update may be available or a new update may have been installed |
| 174 // in the background since the last time an About box was displayed. | 204 // in the background since the last time an About box was displayed. |
| 175 [self checkForUpdate]; | 205 [self checkForUpdate]; |
| 176 } | 206 } |
| 177 | |
| 178 updateShift = 0.0; | |
| 179 } else { | |
| 180 // Hide all the update UI | |
| 181 [updateBlock_ setHidden:YES]; | |
| 182 | |
| 183 // Figure out the amount being removed by taking out the update block | |
| 184 // and its spacing. | |
| 185 updateShift = NSMinY([legalBlock_ frame]) - NSMinY([updateBlock_ frame]); | |
| 186 | |
| 187 NSRect legalFrame = [legalBlock_ frame]; | |
| 188 legalFrame.origin.y -= updateShift; | |
| 189 [legalBlock_ setFrame:legalFrame]; | |
| 190 } | 207 } |
| 191 | 208 |
| 192 NSRect backgroundFrame = [backgroundView_ frame]; | 209 [[self window] center]; |
| 193 backgroundFrame.origin.y += legalShift - updateShift; | |
| 194 [backgroundView_ setFrame:backgroundFrame]; | |
| 195 | |
| 196 NSSize windowDelta = NSMakeSize(0.0, legalShift - updateShift); | |
| 197 | |
| 198 [GTMUILocalizerAndLayoutTweaker | |
| 199 resizeWindowWithoutAutoResizingSubViews:[self window] | |
| 200 delta:windowDelta]; | |
| 201 } | 210 } |
| 202 | 211 |
| 203 - (void)windowWillClose:(NSNotification*)notification { | 212 - (void)windowWillClose:(NSNotification*)notification { |
| 204 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; | 213 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; |
| 205 [center postNotificationName:kUserClosedAboutNotification object:self]; | 214 [center postNotificationName:kUserClosedAboutNotification object:self]; |
| 206 } | 215 } |
| 207 | 216 |
| 217 - (void)adjustUpdateUIVisibility { |
| 218 bool allowUpdate; |
| 219 bool allowPromotion; |
| 220 |
| 221 KeystoneGlue* keystoneGlue = [KeystoneGlue defaultKeystoneGlue]; |
| 222 if (keystoneGlue && ![keystoneGlue isOnReadOnlyFilesystem]) { |
| 223 AutoupdateStatus recentStatus = [keystoneGlue recentStatus]; |
| 224 if (recentStatus == kAutoupdateRegistering || |
| 225 recentStatus == kAutoupdateRegisterFailed || |
| 226 recentStatus == kAutoupdatePromoted) { |
| 227 // Show the update block while registering so that there's a progress |
| 228 // spinner, and if registration failed so that there's an error message. |
| 229 // Show it following a promotion because updates should be possible |
| 230 // after promotion successfully completes. |
| 231 allowUpdate = true; |
| 232 |
| 233 // Promotion isn't possible at this point. |
| 234 allowPromotion = false; |
| 235 } else if (recentStatus == kAutoupdatePromoteFailed) { |
| 236 // TODO(mark): Add kAutoupdatePromoting to this block. KSRegistration |
| 237 // currently handles the promotion synchronously, meaning that the main |
| 238 // thread's loop doesn't spin, meaning that animations and other updates |
| 239 // to the window won't occur until KSRegistration is done with |
| 240 // promotion. This looks laggy and bad and probably qualifies as |
| 241 // "jank." For now, there just won't be any visual feedback while |
| 242 // promotion is in progress, but it should complete (or fail) very |
| 243 // quickly. http://b/2290009. |
| 244 // |
| 245 // Also see the TODO for kAutoupdatePromoting in -updateStatus:version:. |
| 246 // |
| 247 // Show the update block so that there's some visual feedback that |
| 248 // promotion is under way or that it's failed. Show the promotion block |
| 249 // because the user either just clicked that button or because the user |
| 250 // should be able to click it again. |
| 251 allowUpdate = true; |
| 252 allowPromotion = true; |
| 253 } else { |
| 254 // Show the update block only if a promotion is not absolutely required. |
| 255 allowUpdate = ![keystoneGlue needsPromotion]; |
| 256 |
| 257 // Show the promotion block if promotion is a possibility. |
| 258 allowPromotion = [keystoneGlue wantsPromotion]; |
| 259 } |
| 260 } else { |
| 261 // There is no glue, or the application is on a read-only filesystem. |
| 262 // Updates and promotions are impossible. |
| 263 allowUpdate = false; |
| 264 allowPromotion = false; |
| 265 } |
| 266 |
| 267 [self setAllowsUpdate:allowUpdate allowsPromotion:allowPromotion]; |
| 268 } |
| 269 |
| 270 - (void)setAllowsUpdate:(bool)update allowsPromotion:(bool)promotion { |
| 271 bool oldUpdate = ![updateBlock_ isHidden]; |
| 272 bool oldPromotion = ![promotionBlock_ isHidden]; |
| 273 |
| 274 if (promotion == oldPromotion && update == oldUpdate) { |
| 275 return; |
| 276 } |
| 277 |
| 278 NSRect updateFrame = [updateBlock_ frame]; |
| 279 NSRect promotionFrame = [promotionBlock_ frame]; |
| 280 |
| 281 // This routine assumes no space between the update and promotion blocks. |
| 282 DCHECK_EQ(NSMinY(updateFrame), NSMaxY(promotionFrame)); |
| 283 |
| 284 bool promotionOnly = !update && promotion; |
| 285 bool oldPromotionOnly = !oldUpdate && oldPromotion; |
| 286 if (promotionOnly != oldPromotionOnly) { |
| 287 // The window is transitioning from having a promotion block and no update |
| 288 // block to any other state, or the other way around. Move the promotion |
| 289 // frame up so that its top edge is in the same position as the update |
| 290 // frame's top edge, or move it back down to its original location. |
| 291 promotionFrame.origin.y += (promotionOnly ? 1.0 : -1.0) * |
| 292 NSHeight(updateFrame); |
| 293 } |
| 294 |
| 295 CGFloat delta = 0.0; |
| 296 |
| 297 if (update != oldUpdate) { |
| 298 [updateBlock_ setHidden:!update]; |
| 299 delta += (update ? 1.0 : -1.0) * NSHeight(updateFrame); |
| 300 } |
| 301 |
| 302 if (promotion != oldPromotion) { |
| 303 [promotionBlock_ setHidden:!promotion]; |
| 304 delta += (promotion ? 1.0 : -1.0) * NSHeight(promotionFrame); |
| 305 } |
| 306 |
| 307 NSRect legalFrame = [legalBlock_ frame]; |
| 308 |
| 309 bool updateOrPromotion = update || promotion; |
| 310 bool oldUpdateOrPromotion = oldUpdate || oldPromotion; |
| 311 if (updateOrPromotion != oldUpdateOrPromotion) { |
| 312 // The window is transitioning from having an update or promotion block or |
| 313 // both to not having either, or the other way around. Adjust delta to |
| 314 // account for the space between the legal block and the update or |
| 315 // promotion block. When the update and promotion blocks are not visible, |
| 316 // this extra spacing is not used. |
| 317 delta += (updateOrPromotion ? 1.0 : -1.0) * |
| 318 (NSMinY(legalFrame) - NSMaxY(updateFrame)); |
| 319 } |
| 320 |
| 321 // The promotion frame may have changed even if delta is 0, so always reset |
| 322 // its frame. |
| 323 promotionFrame.origin.y += delta; |
| 324 [promotionBlock_ setFrame:promotionFrame]; |
| 325 |
| 326 if (delta) { |
| 327 updateFrame.origin.y += delta; |
| 328 [updateBlock_ setFrame:updateFrame]; |
| 329 |
| 330 legalFrame.origin.y += delta; |
| 331 [legalBlock_ setFrame:legalFrame]; |
| 332 |
| 333 NSRect backgroundFrame = [backgroundView_ frame]; |
| 334 backgroundFrame.origin.y += delta; |
| 335 [backgroundView_ setFrame:backgroundFrame]; |
| 336 |
| 337 // GTMUILocalizerAndLayoutTweaker resizes the window without any |
| 338 // opportunity for animation. In order to animate, disable window |
| 339 // updates, save the current frame, let GTMUILocalizerAndLayoutTweaker do |
| 340 // its thing, save the desired frame, restore the original frame, and then |
| 341 // animate. |
| 342 NSWindow* window = [self window]; |
| 343 [window disableScreenUpdatesUntilFlush]; |
| 344 |
| 345 NSRect oldFrame = [window frame]; |
| 346 |
| 347 // GTMUILocalizerAndLayoutTweaker applies its delta to the window's |
| 348 // current size (like oldFrame.size), but oldFrame isn't trustworthy if |
| 349 // an animation is in progress. Set the window's frame to |
| 350 // intermediateFrame, which is a frame of the size that an existing |
| 351 // animation is animating to, so that GTM can apply the delta to the right |
| 352 // size. |
| 353 NSRect intermediateFrame = oldFrame; |
| 354 intermediateFrame.origin.y -= intermediateFrame.size.height - windowHeight_; |
| 355 intermediateFrame.size.height = windowHeight_; |
| 356 [window setFrame:intermediateFrame display:NO]; |
| 357 |
| 358 NSSize windowDelta = NSMakeSize(0.0, delta); |
| 359 [GTMUILocalizerAndLayoutTweaker |
| 360 resizeWindowWithoutAutoResizingSubViews:window |
| 361 delta:windowDelta]; |
| 362 [window setFrameTopLeftPoint:NSMakePoint(NSMinX(intermediateFrame), |
| 363 NSMaxY(intermediateFrame))]; |
| 364 NSRect newFrame = [window frame]; |
| 365 |
| 366 windowHeight_ += delta; |
| 367 |
| 368 if (![[self window] isVisible]) { |
| 369 // Don't animate if the window isn't on screen yet. |
| 370 [window setFrame:newFrame display:NO]; |
| 371 } else { |
| 372 [window setFrame:oldFrame display:NO]; |
| 373 [window setFrame:newFrame display:YES animate:YES]; |
| 374 } |
| 375 } |
| 376 } |
| 377 |
| 208 - (void)setUpdateThrobberMessage:(NSString*)message { | 378 - (void)setUpdateThrobberMessage:(NSString*)message { |
| 209 [updateStatusIndicator_ setHidden:YES]; | 379 [updateStatusIndicator_ setHidden:YES]; |
| 210 | 380 |
| 211 [spinner_ setHidden:NO]; | 381 [spinner_ setHidden:NO]; |
| 212 [spinner_ startAnimation:self]; | 382 [spinner_ startAnimation:self]; |
| 213 | 383 |
| 214 [updateText_ setStringValue:message]; | 384 [updateText_ setStringValue:message]; |
| 215 } | 385 } |
| 216 | 386 |
| 217 - (void)setUpdateImage:(int)imageID message:(NSString*)message { | 387 - (void)setUpdateImage:(int)imageID message:(NSString*)message { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 232 | 402 |
| 233 // Immediately, kAutoupdateStatusNotification will be posted, and | 403 // Immediately, kAutoupdateStatusNotification will be posted, and |
| 234 // -updateStatus: will be called with status kAutoupdateChecking. | 404 // -updateStatus: will be called with status kAutoupdateChecking. |
| 235 // | 405 // |
| 236 // Upon completion, kAutoupdateStatusNotification will be posted, and | 406 // Upon completion, kAutoupdateStatusNotification will be posted, and |
| 237 // -updateStatus: will be called with a status indicating the result of the | 407 // -updateStatus: will be called with a status indicating the result of the |
| 238 // check. | 408 // check. |
| 239 } | 409 } |
| 240 | 410 |
| 241 - (IBAction)updateNow:(id)sender { | 411 - (IBAction)updateNow:(id)sender { |
| 242 updateTriggered_ = YES; | |
| 243 | |
| 244 [[KeystoneGlue defaultKeystoneGlue] installUpdate]; | 412 [[KeystoneGlue defaultKeystoneGlue] installUpdate]; |
| 245 | 413 |
| 246 // Immediately, kAutoupdateStatusNotification will be posted, and | 414 // Immediately, kAutoupdateStatusNotification will be posted, and |
| 247 // -updateStatus: will be called with status kAutoupdateInstalling. | 415 // -updateStatus: will be called with status kAutoupdateInstalling. |
| 248 // | 416 // |
| 249 // Upon completion, kAutoupdateStatusNotification will be posted, and | 417 // Upon completion, kAutoupdateStatusNotification will be posted, and |
| 250 // -updateStatus: will be called with a status indicating the result of the | 418 // -updateStatus: will be called with a status indicating the result of the |
| 251 // installation attempt. | 419 // installation attempt. |
| 252 } | 420 } |
| 253 | 421 |
| 422 - (IBAction)promoteUpdater:(id)sender { |
| 423 [[KeystoneGlue defaultKeystoneGlue] promoteTicket]; |
| 424 |
| 425 // Immediately, kAutoupdateStatusNotification will be posted, and |
| 426 // -updateStatus: will be called with status kAutoupdatePromoting. |
| 427 // |
| 428 // Upon completion, kAutoupdateStatusNotification will be posted, and |
| 429 // -updateStatus: will be called with a status indicating a result of the |
| 430 // installation attempt. |
| 431 // |
| 432 // If the promotion was successful, KeystoneGlue will re-register the ticket |
| 433 // and -updateStatus: will be called again indicating first that |
| 434 // registration is in progress and subsequently that it has completed. |
| 435 } |
| 436 |
| 254 - (void)updateStatus:(NSNotification*)notification { | 437 - (void)updateStatus:(NSNotification*)notification { |
| 255 recentShownInstallFailedStatus = NO; | 438 recentShownUserActionFailedStatus = NO; |
| 256 | 439 |
| 257 NSDictionary* dictionary = [notification userInfo]; | 440 NSDictionary* dictionary = [notification userInfo]; |
| 258 AutoupdateStatus status = static_cast<AutoupdateStatus>( | 441 AutoupdateStatus status = static_cast<AutoupdateStatus>( |
| 259 [[dictionary objectForKey:kAutoupdateStatusStatus] intValue]); | 442 [[dictionary objectForKey:kAutoupdateStatusStatus] intValue]); |
| 260 | 443 |
| 261 // Don't assume |version| is a real string. It may be nil. | 444 // Don't assume |version| is a real string. It may be nil. |
| 262 NSString* version = [dictionary objectForKey:kAutoupdateStatusVersion]; | 445 NSString* version = [dictionary objectForKey:kAutoupdateStatusVersion]; |
| 263 | 446 |
| 447 bool updateMessage = true; |
| 264 bool throbber = false; | 448 bool throbber = false; |
| 265 int imageID = 0; | 449 int imageID = 0; |
| 266 NSString* message; | 450 NSString* message; |
| 451 bool enableUpdateButton = false; |
| 452 bool enablePromoteButton = true; |
| 267 | 453 |
| 268 switch (status) { | 454 switch (status) { |
| 455 case kAutoupdateRegistering: |
| 456 // When registering, use the "checking" message. The check will be |
| 457 // launched if appropriate immediately after registration. |
| 458 throbber = true; |
| 459 message = l10n_util::GetNSStringWithFixup(IDS_UPGRADE_CHECK_STARTED); |
| 460 enablePromoteButton = false; |
| 461 |
| 462 break; |
| 463 |
| 464 case kAutoupdateRegistered: |
| 465 // Once registered, the ability to update and promote is known. |
| 466 [self adjustUpdateUIVisibility]; |
| 467 |
| 468 if (![updateBlock_ isHidden]) { |
| 469 // If registration completes while the window is visible, go straight |
| 470 // into an update check. Return immediately, this routine will be |
| 471 // re-entered shortly with kAutoupdateChecking. |
| 472 [self checkForUpdate]; |
| 473 return; |
| 474 } |
| 475 |
| 476 // Nothing actually failed, but updates aren't possible. The throbber |
| 477 // and message are hidden, but they'll be reset to these dummy values |
| 478 // just to get the throbber to stop spinning if it's running. |
| 479 imageID = IDR_UPDATE_FAIL; |
| 480 message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR, |
| 481 IntToString16(status)); |
| 482 |
| 483 break; |
| 484 |
| 269 case kAutoupdateChecking: | 485 case kAutoupdateChecking: |
| 270 throbber = true; | 486 throbber = true; |
| 271 message = l10n_util::GetNSStringWithFixup(IDS_UPGRADE_CHECK_STARTED); | 487 message = l10n_util::GetNSStringWithFixup(IDS_UPGRADE_CHECK_STARTED); |
| 488 enablePromoteButton = false; |
| 272 | 489 |
| 273 break; | 490 break; |
| 274 | 491 |
| 275 case kAutoupdateCurrent: | 492 case kAutoupdateCurrent: |
| 276 imageID = IDR_UPDATE_UPTODATE; | 493 imageID = IDR_UPDATE_UPTODATE; |
| 277 message = l10n_util::GetNSStringFWithFixup( | 494 message = l10n_util::GetNSStringFWithFixup( |
| 278 IDS_UPGRADE_ALREADY_UP_TO_DATE, | 495 IDS_UPGRADE_ALREADY_UP_TO_DATE, |
| 279 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), | 496 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), |
| 280 base::SysNSStringToUTF16(version)); | 497 base::SysNSStringToUTF16(version)); |
| 281 | 498 |
| 282 break; | 499 break; |
| 283 | 500 |
| 284 case kAutoupdateAvailable: | 501 case kAutoupdateAvailable: |
| 285 imageID = IDR_UPDATE_AVAILABLE; | 502 imageID = IDR_UPDATE_AVAILABLE; |
| 286 message = l10n_util::GetNSStringFWithFixup( | 503 message = l10n_util::GetNSStringFWithFixup( |
| 287 IDS_UPGRADE_AVAILABLE, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)); | 504 IDS_UPGRADE_AVAILABLE, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)); |
| 288 [updateNowButton_ setEnabled:YES]; | 505 enableUpdateButton = true; |
| 289 | 506 |
| 290 break; | 507 break; |
| 291 | 508 |
| 292 case kAutoupdateInstalling: | 509 case kAutoupdateInstalling: |
| 293 // Don't let anyone click "Update Now" twice. | |
| 294 [updateNowButton_ setEnabled:NO]; | |
| 295 | |
| 296 throbber = true; | 510 throbber = true; |
| 297 message = l10n_util::GetNSStringWithFixup(IDS_UPGRADE_STARTED); | 511 message = l10n_util::GetNSStringWithFixup(IDS_UPGRADE_STARTED); |
| 512 enablePromoteButton = false; |
| 298 | 513 |
| 299 break; | 514 break; |
| 300 | 515 |
| 301 case kAutoupdateInstalled: | 516 case kAutoupdateInstalled: |
| 302 { | 517 { |
| 303 imageID = IDR_UPDATE_UPTODATE; | 518 imageID = IDR_UPDATE_UPTODATE; |
| 304 string16 productName = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME); | 519 string16 productName = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME); |
| 305 if (version) { | 520 if (version) { |
| 306 message = l10n_util::GetNSStringFWithFixup( | 521 message = l10n_util::GetNSStringFWithFixup( |
| 307 IDS_UPGRADE_SUCCESSFUL, | 522 IDS_UPGRADE_SUCCESSFUL, |
| 308 productName, | 523 productName, |
| 309 base::SysNSStringToUTF16(version)); | 524 base::SysNSStringToUTF16(version)); |
| 310 } else { | 525 } else { |
| 311 message = l10n_util::GetNSStringFWithFixup( | 526 message = l10n_util::GetNSStringFWithFixup( |
| 312 IDS_UPGRADE_SUCCESSFUL_NOVERSION, productName); | 527 IDS_UPGRADE_SUCCESSFUL_NOVERSION, productName); |
| 313 } | 528 } |
| 314 | 529 |
| 315 // TODO(mark): Turn the button in the dialog into a restart button | 530 // TODO(mark): Turn the button in the dialog into a restart button |
| 316 // instead of springing this sheet or dialog. | 531 // instead of springing this sheet or dialog. |
| 317 NSWindow* window = [self window]; | 532 NSWindow* window = [self window]; |
| 318 NSWindow* restartDialogParent = [window isVisible] ? window : nil; | 533 NSWindow* restartDialogParent = [window isVisible] ? window : nil; |
| 319 restart_browser::RequestRestart(restartDialogParent); | 534 restart_browser::RequestRestart(restartDialogParent); |
| 320 } | 535 } |
| 321 | 536 |
| 322 break; | 537 break; |
| 323 | 538 |
| 324 case kAutoupdateInstallFailed: | 539 case kAutoupdatePromoting: |
| 325 recentShownInstallFailedStatus = YES; | 540 #if 1 |
| 541 // TODO(mark): See the TODO in -adjustUpdateUIVisibility for an |
| 542 // explanation of why nothing can be done here at the moment. When |
| 543 // KSRegistration handles promotion asynchronously, this dummy block can |
| 544 // be replaced with the #else block. For now, just leave the messaging |
| 545 // alone. http://b/2290009. |
| 546 updateMessage = false; |
| 547 #else |
| 548 // The visibility may be changing. |
| 549 [self adjustUpdateUIVisibility]; |
| 326 | 550 |
| 327 // Allow another chance. | 551 // This is not a terminal state, and kAutoupdatePromoted or |
| 328 [updateNowButton_ setEnabled:YES]; | 552 // kAutoupdatePromoteFailed will follow. Use the throbber and |
| 553 // "checking" message so that it looks like something's happening. |
| 554 throbber = true; |
| 555 message = l10n_util::GetNSStringWithFixup(IDS_UPGRADE_CHECK_STARTED); |
| 556 #endif |
| 329 | 557 |
| 330 // Fall through. | 558 enablePromoteButton = false; |
| 559 |
| 560 break; |
| 561 |
| 562 case kAutoupdatePromoted: |
| 563 // The visibility may be changing. |
| 564 [self adjustUpdateUIVisibility]; |
| 565 |
| 566 if (![updateBlock_ isHidden]) { |
| 567 // If promotion completes while the window is visible, go straight |
| 568 // into an update check. Return immediately, this routine will be |
| 569 // re-entered shortly with kAutoupdateChecking. |
| 570 [self checkForUpdate]; |
| 571 return; |
| 572 } |
| 573 |
| 574 // Nothing actually failed, but updates aren't possible. The throbber |
| 575 // and message are hidden, but they'll be reset to these dummy values |
| 576 // just to get the throbber to stop spinning if it's running. |
| 577 imageID = IDR_UPDATE_FAIL; |
| 578 message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR, |
| 579 IntToString16(status)); |
| 580 |
| 581 break; |
| 582 |
| 583 case kAutoupdateRegisterFailed: |
| 584 imageID = IDR_UPDATE_FAIL; |
| 585 message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR, |
| 586 IntToString16(status)); |
| 587 enablePromoteButton = false; |
| 588 |
| 589 break; |
| 331 | 590 |
| 332 case kAutoupdateCheckFailed: | 591 case kAutoupdateCheckFailed: |
| 333 imageID = IDR_UPDATE_FAIL; | 592 imageID = IDR_UPDATE_FAIL; |
| 334 message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR, | 593 message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR, |
| 335 IntToString16(status)); | 594 IntToString16(status)); |
| 595 |
| 596 break; |
| 597 |
| 598 case kAutoupdateInstallFailed: |
| 599 recentShownUserActionFailedStatus = YES; |
| 600 |
| 601 imageID = IDR_UPDATE_FAIL; |
| 602 message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR, |
| 603 IntToString16(status)); |
| 604 |
| 605 // Allow another chance. |
| 606 enableUpdateButton = true; |
| 607 |
| 608 break; |
| 609 |
| 610 case kAutoupdatePromoteFailed: |
| 611 recentShownUserActionFailedStatus = YES; |
| 612 |
| 613 imageID = IDR_UPDATE_FAIL; |
| 614 message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR, |
| 615 IntToString16(status)); |
| 336 | 616 |
| 337 break; | 617 break; |
| 338 | 618 |
| 339 default: | 619 default: |
| 340 NOTREACHED(); | 620 NOTREACHED(); |
| 621 |
| 341 return; | 622 return; |
| 342 } | 623 } |
| 343 | 624 |
| 344 if (throbber) { | 625 if (updateMessage) { |
| 345 [self setUpdateThrobberMessage:message]; | 626 if (throbber) { |
| 346 } else { | 627 [self setUpdateThrobberMessage:message]; |
| 347 DCHECK_NE(imageID, 0); | 628 } else { |
| 348 [self setUpdateImage:imageID message:message]; | 629 DCHECK_NE(imageID, 0); |
| 630 [self setUpdateImage:imageID message:message]; |
| 631 } |
| 349 } | 632 } |
| 633 |
| 634 // Note that these buttons may be hidden depending on what |
| 635 // -adjustUpdateUIVisibility did. Their enabled/disabled status doesn't |
| 636 // necessarily have anything to do with their visibility. |
| 637 [updateNowButton_ setEnabled:enableUpdateButton]; |
| 638 [promoteButton_ setEnabled:enablePromoteButton]; |
| 350 } | 639 } |
| 351 | 640 |
| 352 - (BOOL)textView:(NSTextView *)aTextView | 641 - (BOOL)textView:(NSTextView *)aTextView |
| 353 clickedOnLink:(id)link | 642 clickedOnLink:(id)link |
| 354 atIndex:(NSUInteger)charIndex { | 643 atIndex:(NSUInteger)charIndex { |
| 355 // We always create a new window, so there's no need to try to re-use | 644 // We always create a new window, so there's no need to try to re-use |
| 356 // an existing one just to pass in the NEW_WINDOW disposition. | 645 // an existing one just to pass in the NEW_WINDOW disposition. |
| 357 Browser* browser = Browser::Create(profile_); | 646 Browser* browser = Browser::Create(profile_); |
| 358 if (browser) { | 647 if (browser) { |
| 359 browser->OpenURL(GURL([link UTF8String]), GURL(), NEW_WINDOW, | 648 browser->OpenURL(GURL([link UTF8String]), GURL(), NEW_WINDOW, |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 487 NSRange string_range = NSMakeRange(0, [legal_block length]); | 776 NSRange string_range = NSMakeRange(0, [legal_block length]); |
| 488 [legal_block addAttribute:NSFontAttributeName | 777 [legal_block addAttribute:NSFontAttributeName |
| 489 value:[NSFont labelFontOfSize:11] | 778 value:[NSFont labelFontOfSize:11] |
| 490 range:string_range]; | 779 range:string_range]; |
| 491 | 780 |
| 492 [legal_block endEditing]; | 781 [legal_block endEditing]; |
| 493 return legal_block; | 782 return legal_block; |
| 494 } | 783 } |
| 495 | 784 |
| 496 @end // @implementation AboutWindowController | 785 @end // @implementation AboutWindowController |
| OLD | NEW |