Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(63)

Side by Side Diff: chrome/browser/cocoa/about_window_controller.mm

Issue 173606: Add background_tile_view for tiling an image as UI background (about box need... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 11 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 #include "app/l10n_util.h" 5 #include "app/l10n_util_mac.h"
6 #include "app/resource_bundle.h"
6 #include "base/file_version_info.h" 7 #include "base/file_version_info.h"
7 #include "base/logging.h" 8 #include "base/logging.h"
8 #include "base/mac_util.h" 9 #include "base/mac_util.h"
9 #include "base/string_util.h" 10 #include "base/string_util.h"
10 #include "base/sys_string_conversions.h" 11 #include "base/sys_string_conversions.h"
11 #import "chrome/app/keystone_glue.h" 12 #import "chrome/app/keystone_glue.h"
12 #import "chrome/browser/cocoa/about_window_controller.h" 13 #import "chrome/browser/cocoa/about_window_controller.h"
14 #import "chrome/browser/cocoa/background_tile_view.h"
15 #include "chrome/browser/cocoa/restart_browser.h"
16 #include "grit/chromium_strings.h"
13 #include "grit/generated_resources.h" 17 #include "grit/generated_resources.h"
18 #include "grit/theme_resources.h"
19 #include "grit/locale_settings.h"
20 #include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
14 21
15 NSString* const kUserClosedAboutNotification = 22 NSString* const kUserClosedAboutNotification =
16 @"kUserClosedAboutNotification"; 23 @"kUserClosedAboutNotification";
17 24
18 @interface AboutWindowController (Private) 25 @interface AboutWindowController (Private)
19 - (KeystoneGlue*)defaultKeystoneGlue; 26 - (KeystoneGlue*)defaultKeystoneGlue;
27 - (void)startProgressMessageID:(uint32_t)messageID;
28 - (void)startProgressMessage:(NSString*)message;
29 - (void)stopProgressMessage:(NSString*)message imageID:(uint32_t)imageID;
20 @end 30 @end
21 31
32 namespace {
33
34 // Keystone doesn't give us error numbers on some results, so we just make
35 // our own for reporting in the UI.
36 const int kUpdateInstallFailed = 128;
37 const int kUpdateInstallFailedToStart = 129;
38
39 void AttributedStringAppendString(NSMutableAttributedString* attr_str,
40 NSString* str) {
41 // You might think doing [[attr_str mutableString] appendString:str] would
42 // work, but it causes any trailing style to get extened, meaning as we
43 // append links, they grow to include the new text, not what we want.
44 NSAttributedString* new_attr_str =
45 [[[NSAttributedString alloc] initWithString:str] autorelease];
46 [attr_str appendAttributedString:new_attr_str];
47 }
48
49 void AttributedStringAppendHyperlink(NSMutableAttributedString* attr_str,
50 NSString* text, NSString* url_str) {
51
52 // Figure out the range of the text we're adding and add the text.
53 NSRange range = NSMakeRange([attr_str length], [text length]);
54 AttributedStringAppendString(attr_str, text);
55
56 // Add the link
57 [attr_str addAttribute:NSLinkAttributeName value:url_str range:range];
58
59 // Blue and underlined
60 [attr_str addAttribute:NSForegroundColorAttributeName
61 value:[NSColor blueColor]
62 range:range];
63 [attr_str addAttribute:NSUnderlineStyleAttributeName
64 value:[NSNumber numberWithInt:NSSingleUnderlineStyle]
65 range:range];
66 }
67
68 NSAttributedString* BuildLegalTextBlock() {
69 // Windows builds this up in a very complex way, we're just trying to model
70 // it the best we can to get all the information in (they actually do it
71 // but created Labels and Links that they carefully place to make it appear
72 // to be a paragraph of text).
73 // src/chrome/browser/views/about_chrome_view.cc AboutChromeView::Init()
74
75 NSMutableAttributedString* legal_block =
76 [[[NSMutableAttributedString alloc] init] autorelease];
77 [legal_block beginEditing];
78
79 NSString* copyright = l10n_util::GetNSString(IDS_ABOUT_VERSION_COPYRIGHT);
80 AttributedStringAppendString(legal_block, copyright);
81
82 // These are the markers directly in IDS_ABOUT_VERSION_LICENSE
83 NSString* kBeginLinkChr = @"BEGIN_LINK_CHR";
84 NSString* kBeginLinkOss = @"BEGIN_LINK_OSS";
85 NSString* kEndLinkChr = @"END_LINK_CHR";
86 NSString* kEndLinkOss = @"END_LINK_OSS";
87 // The CHR link should go to here
88 NSString* kChromiumProject = l10n_util::GetNSString(IDS_CHROMIUM_PROJECT_URL);
89 // The OSS link should go to here
90 NSString* kAcknowledgements = @"about:credits";
91
92 // Now fetch the license string and deal with the markers
93
94 NSString* license = l10n_util::GetNSString(IDS_ABOUT_VERSION_LICENSE);
95
96 NSRange begin_chr = [license rangeOfString:kBeginLinkChr];
97 NSRange begin_oss = [license rangeOfString:kBeginLinkOss];
98 NSRange end_chr = [license rangeOfString:kEndLinkChr];
99 NSRange end_oss = [license rangeOfString:kEndLinkOss];
100 DCHECK(begin_chr.location != NSNotFound);
101 DCHECK(begin_oss.location != NSNotFound);
102 DCHECK(end_chr.location != NSNotFound);
103 DCHECK(end_oss.location != NSNotFound);
104
105 // We don't know which link will come first, so we have to deal with things
106 // like this:
107 // [text][begin][text][end][text][start][text][end][text]
108
109 bool chromium_link_first = begin_chr.location < begin_oss.location;
110
111 NSRange* begin1 = &begin_chr;
112 NSRange* begin2 = &begin_oss;
113 NSRange* end1 = &end_chr;
114 NSRange* end2 = &end_oss;
115 NSString* link1 = kChromiumProject;
116 NSString* link2 = kAcknowledgements;
117 if (!chromium_link_first) {
118 // OSS came first, switch!
119 begin2 = &begin_chr;
120 begin1 = &begin_oss;
121 end2 = &end_chr;
122 end1 = &end_oss;
123 link2 = kChromiumProject;
124 link1 = kAcknowledgements;
125 }
126
127 NSString *sub_str;
128
129 AttributedStringAppendString(legal_block, @"\n");
130 sub_str = [license substringWithRange:NSMakeRange(0, begin1->location)];
131 AttributedStringAppendString(legal_block, sub_str);
132 sub_str = [license substringWithRange:NSMakeRange(NSMaxRange(*begin1),
133 end1->location -
134 NSMaxRange(*begin1))];
135 AttributedStringAppendHyperlink(legal_block, sub_str, link1);
136 sub_str = [license substringWithRange:NSMakeRange(NSMaxRange(*end1),
137 begin2->location -
138 NSMaxRange(*end1))];
139 AttributedStringAppendString(legal_block, sub_str);
140 sub_str = [license substringWithRange:NSMakeRange(NSMaxRange(*begin2),
141 end2->location -
142 NSMaxRange(*begin2))];
143 AttributedStringAppendHyperlink(legal_block, sub_str, link2);
144 sub_str = [license substringWithRange:NSMakeRange(NSMaxRange(*end2),
145 [license length] -
146 NSMaxRange(*end2))];
147 AttributedStringAppendString(legal_block, sub_str);
148
149 #if defined(GOOGLE_CHROME_BUILD)
150 // Terms of service is only valid for Google Chrome
151
152 // The url within terms should point here:
153 NSString* kTOS = @"about:terms";
154 // Following Window. There is one marker in the string for where the terms
155 // link goes, but the text of the link comes from a second string resources.
156 std::vector<size_t> url_offsets;
157 std::wstring w_about_terms = l10n_util::GetStringF(IDS_ABOUT_TERMS_OF_SERVICE,
158 std::wstring(),
159 std::wstring(),
160 &url_offsets);
161 DCHECK_EQ(url_offsets.size(), 1U);
162 NSString* about_terms = base::SysWideToNSString(w_about_terms);
163 NSString* terms_link_text = l10n_util::GetNSString(IDS_TERMS_OF_SERVICE);
164
165 AttributedStringAppendString(legal_block, @"\n");
166 sub_str = [about_terms substringToIndex:url_offsets[0]];
167 AttributedStringAppendString(legal_block, sub_str);
168 AttributedStringAppendHyperlink(legal_block, terms_link_text, kTOS);
169 sub_str = [about_terms substringFromIndex:url_offsets[0]];
170 AttributedStringAppendString(legal_block, sub_str);
171 #endif // defined(GOOGLE_CHROME_BUILD)
172
173 [legal_block endEditing];
174 return legal_block;
175 }
176
177 } // namespace
22 178
23 @implementation AboutWindowController 179 @implementation AboutWindowController
24 180
25 - (id)initWithWindowNibName:(NSString*)nibName { 181 - (id)initWithWindowNibName:(NSString*)nibName {
26 NSString* nibpath = [mac_util::MainAppBundle() pathForResource:nibName 182 NSString* nibpath = [mac_util::MainAppBundle() pathForResource:nibName
27 ofType:@"nib"]; 183 ofType:@"nib"];
28 self = [super initWithWindowNibPath:nibpath owner:self]; 184 self = [super initWithWindowNibPath:nibpath owner:self];
29 return self; 185 return self;
30 } 186 }
31 187
32 - (void)awakeFromNib { 188 - (void)awakeFromNib {
33 // Set our current version. 189 // Set our current version.
34 scoped_ptr<FileVersionInfo> version_info( 190 scoped_ptr<FileVersionInfo> version_info(
35 FileVersionInfo::CreateFileVersionInfoForCurrentModule()); 191 FileVersionInfo::CreateFileVersionInfoForCurrentModule());
36 NSString* version = base::SysWideToNSString(version_info->file_version()); 192 std::wstring version(version_info->product_version());
37 [version_ setStringValue:version]; 193 #if !defined(GOOGLE_CHROME_BUILD)
194 // Yes, Windows does this raw since it is only in Chromium builds
195 // src/chrome/browser/views/about_chrome_view.cc AboutChromeView::Init()
196 version += L" (";
197 version += version_info->last_change();
198 version += L")";
199 #endif
200 NSString* nsversion = base::SysWideToNSString(version);
201 [version_ setStringValue:nsversion];
38 202
39 // Localize the update now button. 203 // Put the two images into the ui
40 NSString* updateNow = base::SysWideToNSString( 204 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
41 l10n_util::GetString(IDS_ABOUT_CHROME_UPDATE_CHECK)); 205 NSImage* backgroundImage = rb.GetNSImageNamed(IDR_ABOUT_BACKGROUND_COLOR);
42 [updateNowButton_ setStringValue:updateNow]; 206 DCHECK(backgroundImage);
207 [backgroundView_ setTileImage:backgroundImage];
208 NSImage* logoImage = rb.GetNSImageNamed(IDR_ABOUT_BACKGROUND);
209 DCHECK(logoImage);
210 [logoView_ setImage:logoImage];
43 211
44 // TODO(jrg): localize the rest of the elements: 212 // Put the legal text into
45 // - "Google Chrome" string at top 213 [legalBlock_ setAttributedStringValue:BuildLegalTextBlock()];
46 // - copyright string at bottom
47 214
48 // Initiate an update check. 215 KeystoneGlue* keystone = [self defaultKeystoneGlue];
49 if ([[self defaultKeystoneGlue] checkForUpdate:self]) 216 CGFloat updateShift = 0.0;
50 [spinner_ startAnimation:self]; 217 if (keystone) {
218 // Initiate an update check.
219 if ([keystone checkForUpdate:self]) {
220 [self startProgressMessageID:IDS_UPGRADE_CHECK_STARTED];
221 }
222 } else {
223 // Hide all the update UI
224 [updateBlock_ setHidden:YES];
225 // Figure out the amount we're removing by taking about the update block
226 // (and it's spacing).
227 updateShift = NSMinY([legalBlock_ frame]) - NSMinY([updateBlock_ frame]);
228 }
229
230 // Adjust the sizes/locations.
231
232 CGFloat legalShift =
233 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:legalBlock_];
234
235 NSRect rect = [legalBlock_ frame];
236 rect.origin.y -= updateShift;
237 [legalBlock_ setFrame:rect];
238
239 rect = [backgroundView_ frame];
240 rect.origin.y = rect.origin.y - updateShift + legalShift;
241 [backgroundView_ setFrame:rect];
242
243 NSWindow* window = [self window];
244 [[window contentView] setAutoresizesSubviews:NO];
245 rect = [window frame];
246 rect.size.height = rect.size.height - updateShift + legalShift;
247 [window setFrame:rect display:NO];
248 [[window contentView] setAutoresizesSubviews:YES];
51 } 249 }
52 250
53 - (KeystoneGlue*)defaultKeystoneGlue { 251 - (KeystoneGlue*)defaultKeystoneGlue {
54 return [KeystoneGlue defaultKeystoneGlue]; 252 return [KeystoneGlue defaultKeystoneGlue];
55 } 253 }
56 254
255 - (void)startProgressMessageID:(uint32_t)messageID {
256 NSString* message = l10n_util::GetNSStringWithFixup(messageID);
257 [self startProgressMessage:message];
258 }
259
260 - (void)startProgressMessage:(NSString*)message {
261 [updateStatusIndicator_ setHidden:YES];
262 [spinner_ setHidden:NO];
263 [spinner_ startAnimation:self];
264
265 [updateText_ setStringValue:message];
266 }
267
268 - (void)stopProgressMessage:(NSString*)message imageID:(uint32_t)imageID {
269 [spinner_ stopAnimation:self];
270 [spinner_ setHidden:YES];
271 if (imageID) {
272 [updateStatusIndicator_ setHidden:NO];
273 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
274 NSImage* statusImage = rb.GetNSImageNamed(imageID);
275 DCHECK(statusImage);
276 [updateStatusIndicator_ setImage:statusImage];
277 }
278
279 [updateText_ setStringValue:message];
280 }
281
57 // Callback from KeystoneGlue; implementation of KeystoneGlueCallbacks protocol. 282 // Callback from KeystoneGlue; implementation of KeystoneGlueCallbacks protocol.
58 // Warning: latest version may be nil if not set in server config. 283 // Warning: latest version may be nil if not set in server config.
59 - (void)upToDateCheckCompleted:(BOOL)updatesAvailable 284 - (void)upToDateCheckCompleted:(BOOL)updatesAvailable
60 latestVersion:(NSString*)latestVersion { 285 latestVersion:(NSString*)latestVersion {
61 [spinner_ stopAnimation:self]; 286 uint32_t imageID;
287 NSString* message;
288 if (updatesAvailable) {
289 newVersionAvailable_.reset([latestVersion copy]);
62 290
63 // If an update is available, be sure to enable the "update now" button. 291 // Window UI doesn't put the version number in the string.
64 NSString* display = @"No updates are available."; 292 imageID = IDR_UPDATE_AVAILABLE;
65 if (updatesAvailable) { 293 message =
294 l10n_util::GetNSStringF(IDS_UPGRADE_AVAILABLE,
295 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
66 [updateNowButton_ setEnabled:YES]; 296 [updateNowButton_ setEnabled:YES];
67 // TODO(jrg): IDS_UPGRADE_AVAILABLE seems close but there is no facility 297 } else {
68 // for specifying a verision in the update string. Do we care? 298 // NOTE: This is can be a lie, Keystone does not provide us with an error if
69 display = latestVersion ? 299 // it was not able to reach the server. So we can't completely map to the
70 [NSString stringWithFormat:@"Version %@ is available for update.", 300 // Windows UI.
71 latestVersion] : 301
72 @"A new version is available."; 302 // Keystone does not provide the version number when we are up to date so to
303 // maintain the UI, we just go fetch our version and call it good.
304 scoped_ptr<FileVersionInfo> version_info(
305 FileVersionInfo::CreateFileVersionInfoForCurrentModule());
306 std::wstring version(version_info->product_version());
307
308 // TODO: We really should check to see if what is on disk is newer then what
309 // is running and report it as such. (Windows has some messages that can
310 // help with this.) http://crbug.com/13165
311
312 imageID = IDR_UPDATE_UPTODATE;
313 message =
314 l10n_util::GetNSStringF(IDS_UPGRADE_ALREADY_UP_TO_DATE,
315 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
316 WideToUTF16(version));
73 } 317 }
74 [upToDate_ setStringValue:display]; 318 [self stopProgressMessage:message imageID:imageID];
75 } 319 }
76 320
77 - (void)windowWillClose:(NSNotification*)notification { 321 - (void)windowWillClose:(NSNotification*)notification {
78 // If an update has ever been triggered, we force reuse of the same About Box. 322 // If an update has ever been triggered, we force reuse of the same About Box.
79 // This gives us 2 things: 323 // This gives us 2 things:
80 // 1. If an update is ongoing and the window was closed we would have 324 // 1. If an update is ongoing and the window was closed we would have
81 // no way of getting status. 325 // no way of getting status.
82 // 2. If we have a "Please restart" message we want it to stay there. 326 // 2. If we have a "Please restart" message we want it to stay there.
83 if (updateTriggered_) 327 if (updateTriggered_)
84 return; 328 return;
85 329
86 [[NSNotificationCenter defaultCenter] 330 [[NSNotificationCenter defaultCenter]
87 postNotificationName:kUserClosedAboutNotification 331 postNotificationName:kUserClosedAboutNotification
88 object:self]; 332 object:self];
89 } 333 }
90 334
91 // Callback from KeystoneGlue; implementation of KeystoneGlueCallbacks protocol. 335 // Callback from KeystoneGlue; implementation of KeystoneGlueCallbacks protocol.
92 - (void)updateCompleted:(BOOL)successful installs:(int)installs { 336 - (void)updateCompleted:(BOOL)successful installs:(int)installs {
93 [spinner_ stopAnimation:self]; 337 uint32_t imageID;
94 // TODO(jrg): localize. No current string really says this. 338 NSString* message;
95 NSString* display = ((successful && installs) ? 339 if (successful && installs) {
96 @"Update completed! Please restart Chrome." : 340 imageID = IDR_UPDATE_UPTODATE;
97 @"Self update failed."); 341 if ([newVersionAvailable_.get() length]) {
98 [updateCompleted_ setStringValue:display]; 342 message =
343 l10n_util::GetNSStringF(IDS_UPGRADE_SUCCESSFUL,
344 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
345 base::SysNSStringToUTF16(
346 newVersionAvailable_.get()));
347 } else {
348 message =
349 l10n_util::GetNSStringF(IDS_UPGRADE_SUCCESSFUL_NOVERSION,
350 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
351 }
99 352
100 // Allow a second chance. 353 // Tell the user to restart their browser.
101 if (!(successful && installs)) 354 restart_browser::RequestRestart(nil);
355
356 } else {
357 imageID = IDR_UPDATE_FAIL;
358 message =
359 l10n_util::GetNSStringF(IDS_UPGRADE_ERROR,
360 IntToString16(kUpdateInstallFailed));
361
362 // Allow a second chance.
102 [updateNowButton_ setEnabled:YES]; 363 [updateNowButton_ setEnabled:YES];
364 }
365
366 [self stopProgressMessage:message imageID:imageID];
103 } 367 }
104 368
105 - (IBAction)updateNow:(id)sender { 369 - (IBAction)updateNow:(id)sender {
106 updateTriggered_ = YES; 370 updateTriggered_ = YES;
371
107 // Don't let someone click "Update Now" twice! 372 // Don't let someone click "Update Now" twice!
108 [updateNowButton_ setEnabled:NO]; 373 [updateNowButton_ setEnabled:NO];
109 [spinner_ startAnimation:self];
110 if ([[self defaultKeystoneGlue] startUpdate:self]) { 374 if ([[self defaultKeystoneGlue] startUpdate:self]) {
111 // Clear any previous error message from the throbber area. 375 // Clear any previous error message from the throbber area.
112 [updateCompleted_ setStringValue:@""]; 376 [self startProgressMessageID:IDS_UPGRADE_STARTED];
113 [spinner_ startAnimation:self];
114 } else { 377 } else {
115 // TODO(jrg): localize. 378 NSString* message =
116 // IDS_UPGRADE_ERROR doesn't work here; we don't have an error number, and 379 l10n_util::GetNSStringF(IDS_UPGRADE_ERROR,
117 // "server not available" is too specific. 380 IntToString16(kUpdateInstallFailedToStart));
118 [updateCompleted_ setStringValue:@"Failed to start updates."]; 381 [self stopProgressMessage:message imageID:IDR_UPDATE_FAIL];
119 } 382 }
120 } 383 }
121 384
122 - (NSButton*)updateButton { 385 - (NSButton*)updateButton {
123 return updateNowButton_; 386 return updateNowButton_;
124 } 387 }
125 388
126 - (NSTextField*)upToDateTextField { 389 - (NSTextField*)updateText {
127 return upToDate_; 390 return updateText_;
128 }
129
130 - (NSTextField*)updateCompletedTextField {
131 return updateCompleted_;
132 } 391 }
133 392
134 @end 393 @end
135 394
OLDNEW
« no previous file with comments | « chrome/browser/cocoa/about_window_controller.h ('k') | chrome/browser/cocoa/about_window_controller_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698