diff options
25 files changed, 459 insertions, 90 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 2e4e679..1df2b76 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -4469,6 +4469,9 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_EXCEPTIONS_ACTION_HEADER" desc="A column header for the action column of the cookie/image/javascript/plugins exceptions dialog"> Action </message> + <message name="IDS_EXCEPTIONS_OTR_HEADER" desc="A column header for the incognito column of the cookie/image/javascript/plugins exceptions dialog"> + Incognito + </message> <message name="IDS_EXCEPTIONS_ADD_BUTTON" desc="A button in the cookie/image/javascript/plugins exceptions dialog for adding new exception rules."> Add... </message> @@ -4490,6 +4493,9 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_EXCEPTIONS_BLOCK_BUTTON" desc="A label to display in the exception page's action column when a site's content setting is blocked for a given domain."> Block </message> + <message name="IDS_EXCEPTIONS_OTR_IN_ITALICS" desc="A label informing the user that incognito-only exceptions are displayed in italics"> + Exceptions displayed in italics only apply to this incognito session. + </message> <message name="IDS_EXCEPTIONS_NOT_SET_BUTTON" desc="A label to display in the exception page's action column when a site's content setting has not yet been set for a given domain."> Not set </message> @@ -4522,6 +4528,9 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_EXCEPTION_EDITOR_ACTION_TITLE" desc="Title of the action combobox in the exception editor"> Action: </message> + <message name="IDS_EXCEPTION_EDITOR_OTR_TITLE" desc="Title of the incognito checkbox in the exception editor"> + Only apply to this incognito session + </message> <!-- Cookie alert dialog --> <message name="IDS_COOKIE_ALERT_TITLE" desc="Format string for cookie alert dialog title"> diff --git a/chrome/app/nibs/ContentExceptionsWindow.xib b/chrome/app/nibs/ContentExceptionsWindow.xib index 9e2b30f..2fdf4f4 100644 --- a/chrome/app/nibs/ContentExceptionsWindow.xib +++ b/chrome/app/nibs/ContentExceptionsWindow.xib @@ -8,7 +8,7 @@ <string key="IBDocument.HIToolboxVersion">353.00</string> <object class="NSMutableArray" key="IBDocument.EditedObjectIDs"> <bool key="EncodedWithXMLCoder">YES</bool> - <integer value="2"/> + <integer value="10"/> </object> <object class="NSArray" key="IBDocument.PluginDependencies"> <bool key="EncodedWithXMLCoder">YES</bool> @@ -75,14 +75,14 @@ <object class="_NSCornerView" key="NSCornerView" id="274818157"> <reference key="NSNextResponder" ref="832680793"/> <int key="NSvFlags">-2147483392</int> - <string key="NSFrame">{{-26, 0}, {16, 17}}</string> + <string key="NSFrame">{{477, 0}, {16, 17}}</string> <reference key="NSSuperview" ref="832680793"/> </object> <object class="NSMutableArray" key="NSTableColumns"> <bool key="EncodedWithXMLCoder">YES</bool> <object class="NSTableColumn" id="20203331"> <string key="NSIdentifier">pattern</string> - <double key="NSWidth">3.120000e+02</double> + <double key="NSWidth">2.530000e+02</double> <double key="NSMinWidth">4.000000e+01</double> <double key="NSMaxWidth">1.000000e+03</double> <object class="NSTableHeaderCell" key="NSHeaderCell"> @@ -141,7 +141,7 @@ </object> <object class="NSTableColumn" id="332085935"> <string key="NSIdentifier">action</string> - <double key="NSWidth">1.730000e+02</double> + <double key="NSWidth">1.140000e+02</double> <double key="NSMinWidth">4.000000e+01</double> <double key="NSMaxWidth">1.000000e+03</double> <object class="NSTableHeaderCell" key="NSHeaderCell"> @@ -199,6 +199,47 @@ <bool key="NSIsEditable">YES</bool> <reference key="NSTableView" ref="178750169"/> </object> + <object class="NSTableColumn" id="972931040"> + <string key="NSIdentifier">otr</string> + <double key="NSWidth">8.000000e+01</double> + <double key="NSMinWidth">4.000000e+01</double> + <double key="NSMaxWidth">1.000000e+03</double> + <object class="NSTableHeaderCell" key="NSHeaderCell"> + <int key="NSCellFlags">75628096</int> + <int key="NSCellFlags2">2048</int> + <string key="NSContents">^IDS_EXCEPTIONS_OTR_HEADER</string> + <reference key="NSSupport" ref="26"/> + <object class="NSColor" key="NSBackgroundColor"> + <int key="NSColorSpace">3</int> + <bytes key="NSWhite">MC4zMzMzMzI5OQA</bytes> + </object> + <reference key="NSTextColor" ref="1021472174"/> + </object> + <object class="NSButtonCell" key="NSDataCell" id="214434166"> + <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags2">134348800</int> + <string key="NSContents"/> + <reference key="NSSupport" ref="26"/> + <reference key="NSControlView" ref="178750169"/> + <int key="NSButtonFlags">1215582719</int> + <int key="NSButtonFlags2">130</int> + <object class="NSCustomResource" key="NSNormalImage"> + <string key="NSClassName">NSImage</string> + <string key="NSResourceName">NSSwitch</string> + </object> + <object class="NSButtonImageSource" key="NSAlternateImage"> + <string key="NSImageName">NSSwitch</string> + </object> + <string key="NSAlternateContents"/> + <string key="NSKeyEquivalent"/> + <int key="NSPeriodicDelay">200</int> + <int key="NSPeriodicInterval">25</int> + </object> + <int key="NSResizingMask">3</int> + <bool key="NSIsResizeable">YES</bool> + <bool key="NSIsEditable">YES</bool> + <reference key="NSTableView" ref="178750169"/> + </object> </object> <double key="NSIntercellSpacingWidth">3.000000e+00</double> <double key="NSIntercellSpacingHeight">2.000000e+00</double> @@ -233,7 +274,7 @@ <object class="NSScroller" id="984908608"> <reference key="NSNextResponder" ref="832680793"/> <int key="NSvFlags">-2147483392</int> - <string key="NSFrame">{{368, 17}, {15, 327}}</string> + <string key="NSFrame">{{477, 17}, {15, 336}}</string> <reference key="NSSuperview" ref="832680793"/> <reference key="NSTarget" ref="832680793"/> <string key="NSAction">_doScroller:</string> @@ -242,12 +283,12 @@ <object class="NSScroller" id="689783017"> <reference key="NSNextResponder" ref="832680793"/> <int key="NSvFlags">-2147483392</int> - <string key="NSFrame">{{1, 344}, {367, 15}}</string> + <string key="NSFrame">{{1, 353}, {476, 15}}</string> <reference key="NSSuperview" ref="832680793"/> <int key="NSsFlags">1</int> <reference key="NSTarget" ref="832680793"/> <string key="NSAction">_doScroller:</string> - <double key="NSPercent">9.973890e-01</double> + <double key="NSPercent">7.361319e-01</double> </object> <object class="NSClipView" id="522115304"> <reference key="NSNextResponder" ref="832680793"/> @@ -613,6 +654,7 @@ <bool key="EncodedWithXMLCoder">YES</bool> <reference ref="20203331"/> <reference ref="332085935"/> + <reference ref="972931040"/> </object> <reference key="parent" ref="832680793"/> </object> @@ -753,6 +795,20 @@ <reference key="object" ref="985169067"/> <reference key="parent" ref="13599172"/> </object> + <object class="IBObjectRecord"> + <int key="objectID">68</int> + <reference key="object" ref="972931040"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="214434166"/> + </object> + <reference key="parent" ref="178750169"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">72</int> + <reference key="object" ref="214434166"/> + <reference key="parent" ref="972931040"/> + </object> </object> </object> <object class="NSMutableDictionary" key="flattenedProperties"> @@ -791,7 +847,9 @@ <string>54.IBPluginDependency</string> <string>6.IBPluginDependency</string> <string>64.IBPluginDependency</string> + <string>68.IBPluginDependency</string> <string>7.IBPluginDependency</string> + <string>72.IBPluginDependency</string> <string>8.IBPluginDependency</string> <string>9.IBPluginDependency</string> </object> @@ -800,10 +858,10 @@ <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <string>{{507, 468}, {533, 448}}</string> + <string>{{257, 468}, {533, 448}}</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <boolean value="YES" id="5"/> - <string>{{507, 468}, {533, 448}}</string> + <string>{{257, 468}, {533, 448}}</string> <boolean value="NO"/> <string>{196, 240}</string> <string>{{357, 418}, {480, 270}}</string> @@ -832,6 +890,8 @@ <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> </object> </object> <object class="NSMutableDictionary" key="unlocalizedProperties"> @@ -854,7 +914,7 @@ </object> </object> <nil key="sourceID"/> - <int key="maxID">67</int> + <int key="maxID">72</int> </object> <object class="IBClassDescriber" key="IBDocument.Classes"> <object class="NSMutableArray" key="referencedPartialClassDescriptions"> @@ -997,6 +1057,13 @@ <string key="className">NSObject</string> <object class="IBClassDescriptionSource" key="sourceIdentifier"> <string key="majorKey">IBProjectSource</string> + <string key="minorKey">browser/cocoa/objc_zombie.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> <string key="minorKey">browser/cocoa/status_bubble_mac.h</string> </object> </object> diff --git a/chrome/browser/cocoa/content_exceptions_window_controller.h b/chrome/browser/cocoa/content_exceptions_window_controller.h index 1d1bc2a..131cf72 100644 --- a/chrome/browser/cocoa/content_exceptions_window_controller.h +++ b/chrome/browser/cocoa/content_exceptions_window_controller.h @@ -28,11 +28,16 @@ class UpdatingContentSettingsObserver; ContentSettingsType settingsType_; HostContentSettingsMap* settingsMap_; // weak + HostContentSettingsMap* otrSettingsMap_; // weak scoped_ptr<ContentExceptionsTableModel> model_; // Is set if "Ask" should be a valid option in the "action" popup. BOOL showAsk_; + // Is set if adding and editing exceptions for the current OTR session should + // be allowed. + BOOL otrAllowed_; + // Listens for changes to the content settings and reloads the data when they // change. See comment in -modelDidChange in the mm file for details. scoped_ptr<UpdatingContentSettingsObserver> tableObserver_; @@ -49,7 +54,8 @@ class UpdatingContentSettingsObserver; // Returns the content exceptions window controller for |settingsType|. // Changes made by the user in the window are persisted in |settingsMap|. + (id)controllerForType:(ContentSettingsType)settingsType - settingsMap:(HostContentSettingsMap*)settingsMap; + settingsMap:(HostContentSettingsMap*)settingsMap + otrSettingsMap:(HostContentSettingsMap*)otrSettingsMap; // Shows the exceptions dialog as a modal sheet attached to |window|. - (void)attachSheetTo:(NSWindow*)window; diff --git a/chrome/browser/cocoa/content_exceptions_window_controller.mm b/chrome/browser/cocoa/content_exceptions_window_controller.mm index 0ebcb8e..692fe86 100644 --- a/chrome/browser/cocoa/content_exceptions_window_controller.mm +++ b/chrome/browser/cocoa/content_exceptions_window_controller.mm @@ -17,9 +17,11 @@ @interface ContentExceptionsWindowController (Private) - (id)initWithType:(ContentSettingsType)settingsType - settingsMap:(HostContentSettingsMap*)settingsMap; + settingsMap:(HostContentSettingsMap*)settingsMap + otrSettingsMap:(HostContentSettingsMap*)otrSettingsMap; - (void)updateRow:(NSInteger)row - withEntry:(const HostContentSettingsMap::PatternSettingPair&)entry; + withEntry:(const HostContentSettingsMap::PatternSettingPair&)entry + forOtr:(BOOL)isOtr; - (void)adjustEditingButtons; - (void)modelDidChange; - (size_t)menuItemCount; @@ -141,25 +143,32 @@ static ContentExceptionsWindowController* @implementation ContentExceptionsWindowController + (id)controllerForType:(ContentSettingsType)settingsType - settingsMap:(HostContentSettingsMap*)settingsMap { + settingsMap:(HostContentSettingsMap*)settingsMap + otrSettingsMap:(HostContentSettingsMap*)otrSettingsMap { if (!g_exceptionWindows[settingsType]) { g_exceptionWindows[settingsType] = - [[ContentExceptionsWindowController alloc] initWithType:settingsType - settingsMap:settingsMap]; + [[ContentExceptionsWindowController alloc] + initWithType:settingsType + settingsMap:settingsMap + otrSettingsMap:otrSettingsMap]; } return g_exceptionWindows[settingsType]; } - (id)initWithType:(ContentSettingsType)settingsType - settingsMap:(HostContentSettingsMap*)settingsMap { + settingsMap:(HostContentSettingsMap*)settingsMap + otrSettingsMap:(HostContentSettingsMap*)otrSettingsMap { NSString* nibpath = [mac_util::MainAppBundle() pathForResource:@"ContentExceptionsWindow" ofType:@"nib"]; if ((self = [super initWithWindowNibPath:nibpath owner:self])) { settingsType_ = settingsType; settingsMap_ = settingsMap; - model_.reset(new ContentExceptionsTableModel(settingsMap_, settingsType_)); + otrSettingsMap_ = otrSettingsMap; + model_.reset(new ContentExceptionsTableModel( + settingsMap_, otrSettingsMap_, settingsType_)); showAsk_ = settingsType_ == CONTENT_SETTINGS_TYPE_COOKIES; + otrAllowed_ = otrSettingsMap != NULL; tableObserver_.reset(new UpdatingContentSettingsObserver(self)); updatesEnabled_ = YES; @@ -199,6 +208,11 @@ static ContentExceptionsWindowController* NSCell* patternCell = [[tableView_ tableColumnWithIdentifier:@"pattern"] dataCell]; [patternCell setFormatter:[[[PatternFormatter alloc] init] autorelease]]; + + if (!otrAllowed_) { + [tableView_ + removeTableColumn:[tableView_ tableColumnWithIdentifier:@"otr"]]; + } } - (void)setMinWidth:(CGFloat)minWidth { @@ -339,10 +353,14 @@ static ContentExceptionsWindowController* objectValueForTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row { const HostContentSettingsMap::PatternSettingPair* entry; - if (newException_.get() && row >= model_->RowCount()) + int isOtr; + if (newException_.get() && row >= model_->RowCount()) { entry = newException_.get(); - else + isOtr = 0; + } else { entry = &model_->entry_at(row); + isOtr = model_->entry_is_off_the_record(row) ? 1 : 0; + } NSObject* result = nil; NSString* identifier = [tableColumn identifier]; @@ -350,6 +368,8 @@ static ContentExceptionsWindowController* result = base::SysUTF8ToNSString(entry->first.AsString()); } else if ([identifier isEqualToString:@"action"]) { result = [NSNumber numberWithInt:[self indexForSetting:entry->second]]; + } else if ([identifier isEqualToString:@"otr"]) { + result = [NSNumber numberWithInt:isOtr]; } else { NOTREACHED(); } @@ -358,19 +378,20 @@ static ContentExceptionsWindowController* // Updates exception at |row| to contain the data in |entry|. - (void)updateRow:(NSInteger)row - withEntry:(const HostContentSettingsMap::PatternSettingPair&)entry { + withEntry:(const HostContentSettingsMap::PatternSettingPair&)entry + forOtr:(BOOL)isOtr { // TODO(thakis): This apparently moves an edited row to the back of the list. // It's what windows and linux do, but it's kinda sucky. Fix. // http://crbug.com/36904 updatesEnabled_ = NO; if (row < model_->RowCount()) model_->RemoveException(row); - model_->AddException(entry.first, entry.second); + model_->AddException(entry.first, entry.second, isOtr); updatesEnabled_ = YES; [self modelDidChange]; // For now, at least re-select the edited element. - int newIndex = model_->IndexOfExceptionByPattern(entry.first); + int newIndex = model_->IndexOfExceptionByPattern(entry.first, isOtr); DCHECK(newIndex != -1); [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:newIndex] byExtendingSelection:NO]; @@ -395,6 +416,9 @@ static ContentExceptionsWindowController* HostContentSettingsMap::PatternSettingPair originalEntry = isNewRow ? *newException_ : model_->entry_at(row); HostContentSettingsMap::PatternSettingPair entry = originalEntry; + bool isOtr = + isNewRow ? 0 : model_->entry_is_off_the_record(row); + bool wasOtr = isOtr; // Modify it. NSString* identifier = [tableColumn identifier]; @@ -406,6 +430,9 @@ static ContentExceptionsWindowController* int index = [object intValue]; entry.second = [self settingForIndex:index]; } + if ([identifier isEqualToString:@"otr"]) { + isOtr = [object intValue] != 0; + } // Commit modification, if any. if (isNewRow) { @@ -415,7 +442,7 @@ static ContentExceptionsWindowController* [self adjustEditingButtons]; return; // Commit new rows only when the pattern has been set. } - int newIndex = model_->IndexOfExceptionByPattern(entry.first); + int newIndex = model_->IndexOfExceptionByPattern(entry.first, false); if (newIndex != -1) { // The new pattern was already in the table. Focus existing row instead of // overwriting it with a new one. @@ -426,8 +453,8 @@ static ContentExceptionsWindowController* return; } } - if (entry != originalEntry || isNewRow) - [self updateRow:row withEntry:entry]; + if (entry != originalEntry || wasOtr != isOtr || isNewRow) + [self updateRow:row withEntry:entry forOtr:isOtr]; } @@ -458,7 +485,8 @@ static ContentExceptionsWindowController* return; // The model caches its data, meaning we need to recreate it on every change. - model_.reset(new ContentExceptionsTableModel(settingsMap_, settingsType_)); + model_.reset(new ContentExceptionsTableModel( + settingsMap_, otrSettingsMap_, settingsType_)); [tableView_ reloadData]; [self adjustEditingButtons]; diff --git a/chrome/browser/cocoa/content_exceptions_window_controller_unittest.mm b/chrome/browser/cocoa/content_exceptions_window_controller_unittest.mm index 995c21e..730a045 100644 --- a/chrome/browser/cocoa/content_exceptions_window_controller_unittest.mm +++ b/chrome/browser/cocoa/content_exceptions_window_controller_unittest.mm @@ -57,7 +57,8 @@ class ContentExceptionsWindowControllerTest : public CocoaTest { ContentExceptionsWindowController* GetController(ContentSettingsType type) { id controller = [ContentExceptionsWindowController controllerForType:type - settingsMap:settingsMap_.get()]; + settingsMap:settingsMap_.get() + otrSettingsMap:NULL]; [controller showWindow:nil]; return controller; } @@ -96,7 +97,8 @@ TEST_F(ContentExceptionsWindowControllerTest, Construction) { ContentExceptionsWindowController* controller = [ContentExceptionsWindowController controllerForType:CONTENT_SETTINGS_TYPE_PLUGINS - settingsMap:settingsMap_.get()]; + settingsMap:settingsMap_.get() + otrSettingsMap:NULL]; [controller showWindow:nil]; [controller close]; // Should autorelease. } diff --git a/chrome/browser/cocoa/content_settings_dialog_controller.mm b/chrome/browser/cocoa/content_settings_dialog_controller.mm index a981a0f..40fceae 100644 --- a/chrome/browser/cocoa/content_settings_dialog_controller.mm +++ b/chrome/browser/cocoa/content_settings_dialog_controller.mm @@ -333,8 +333,13 @@ class PrefObserverDisabler { - (void)showExceptionsForType:(ContentSettingsType)settingsType { HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap(); + HostContentSettingsMap* offTheRecordSettingsMap = + profile_->HasOffTheRecordProfile() ? + profile_->GetOffTheRecordProfile()->GetHostContentSettingsMap() : + NULL; [[ContentExceptionsWindowController controllerForType:settingsType - settingsMap:settingsMap] + settingsMap:settingsMap + otrSettingsMap:offTheRecordSettingsMap] attachSheetTo:[self window]]; } diff --git a/chrome/browser/content_exceptions_table_model.cc b/chrome/browser/content_exceptions_table_model.cc index 93efed5..e32bc81 100644 --- a/chrome/browser/content_exceptions_table_model.cc +++ b/chrome/browser/content_exceptions_table_model.cc @@ -12,28 +12,44 @@ ContentExceptionsTableModel::ContentExceptionsTableModel( HostContentSettingsMap* map, + HostContentSettingsMap* off_the_record_map, ContentSettingsType type) : map_(map), + off_the_record_map_(off_the_record_map), content_type_(type), observer_(NULL) { // Load the contents. map->GetSettingsForOneType(type, &entries_); + if (off_the_record_map) + off_the_record_map->GetSettingsForOneType(type, &off_the_record_entries_); } void ContentExceptionsTableModel::AddException( const HostContentSettingsMap::Pattern& pattern, - ContentSetting setting) { - entries_.push_back( + ContentSetting setting, + bool is_off_the_record) { + DCHECK(!is_off_the_record || off_the_record_map_); + + int insert_position = + is_off_the_record ? RowCount() : static_cast<int>(entries_.size()); + + entries(is_off_the_record).push_back( HostContentSettingsMap::PatternSettingPair(pattern, setting)); - map_->SetContentSetting(pattern, content_type_, setting); + map(is_off_the_record)->SetContentSetting(pattern, content_type_, setting); if (observer_) - observer_->OnItemsAdded(RowCount() - 1, 1); + observer_->OnItemsAdded(insert_position, 1); } void ContentExceptionsTableModel::RemoveException(int row) { - const HostContentSettingsMap::PatternSettingPair& pair = entries_[row]; - map_->SetContentSetting(pair.first, content_type_, CONTENT_SETTING_DEFAULT); - entries_.erase(entries_.begin() + row); + bool is_off_the_record = entry_is_off_the_record(row); + int position_to_delete = + is_off_the_record ? row - static_cast<int>(entries_.size()) : row; + const HostContentSettingsMap::PatternSettingPair& pair = entry_at(row); + + map(is_off_the_record)->SetContentSetting( + pair.first, content_type_, CONTENT_SETTING_DEFAULT); + entries(is_off_the_record).erase( + entries(is_off_the_record).begin() + position_to_delete); if (observer_) observer_->OnItemsRemoved(row, 1); } @@ -41,28 +57,37 @@ void ContentExceptionsTableModel::RemoveException(int row) { void ContentExceptionsTableModel::RemoveAll() { int old_row_count = RowCount(); entries_.clear(); + off_the_record_entries_.clear(); map_->ClearSettingsForOneType(content_type_); + if (off_the_record_map_) + off_the_record_map_->ClearSettingsForOneType(content_type_); if (observer_) observer_->OnItemsRemoved(0, old_row_count); } int ContentExceptionsTableModel::IndexOfExceptionByPattern( - const HostContentSettingsMap::Pattern& pattern) { + const HostContentSettingsMap::Pattern& pattern, + bool is_off_the_record) { + DCHECK(!is_off_the_record || off_the_record_map_); + + int offset = + is_off_the_record ? static_cast<int>(entries_.size()) : 0; + // This is called on every key type in the editor. Move to a map if we end up // with lots of exceptions. - for (size_t i = 0; i < entries_.size(); ++i) { - if (entries_[i].first == pattern) - return static_cast<int>(i); + for (size_t i = 0; i < entries(is_off_the_record).size(); ++i) { + if (entries(is_off_the_record)[i].first == pattern) + return offset + static_cast<int>(i); } return -1; } int ContentExceptionsTableModel::RowCount() { - return static_cast<int>(entries_.size()); + return static_cast<int>(entries_.size() + off_the_record_entries_.size()); } std::wstring ContentExceptionsTableModel::GetText(int row, int column_id) { - HostContentSettingsMap::PatternSettingPair entry = entries_[row]; + HostContentSettingsMap::PatternSettingPair entry = entry_at(row); switch (column_id) { case IDS_EXCEPTIONS_PATTERN_HEADER: diff --git a/chrome/browser/content_exceptions_table_model.h b/chrome/browser/content_exceptions_table_model.h index da8889e..469dac0 100644 --- a/chrome/browser/content_exceptions_table_model.h +++ b/chrome/browser/content_exceptions_table_model.h @@ -15,18 +15,28 @@ class ContentExceptionsTableModel : public TableModel { public: ContentExceptionsTableModel(HostContentSettingsMap* map, + HostContentSettingsMap* off_the_record_map, ContentSettingsType content_type); HostContentSettingsMap* map() const { return map_; } + HostContentSettingsMap* off_the_record_map() const { + return off_the_record_map_; + } ContentSettingsType content_type() const { return content_type_; } + bool entry_is_off_the_record(int index) { + return index >= static_cast<int>(entries_.size()); + } + const HostContentSettingsMap::PatternSettingPair& entry_at(int index) { - return entries_[index]; + return (entry_is_off_the_record(index) ? + off_the_record_entries_[index - entries_.size()] : entries_[index]); } // Adds a new exception on the map and table model. void AddException(const HostContentSettingsMap::Pattern& pattern, - ContentSetting setting); + ContentSetting setting, + bool is_off_the_record); // Removes the exception at the specified index from both the map and model. void RemoveException(int row); @@ -36,7 +46,8 @@ class ContentExceptionsTableModel : public TableModel { // Returns the index of the specified exception given a host, or -1 if there // is no exception for the specified host. - int IndexOfExceptionByPattern(const HostContentSettingsMap::Pattern& pattern); + int IndexOfExceptionByPattern(const HostContentSettingsMap::Pattern& pattern, + bool is_off_the_record); // TableModel overrides: virtual int RowCount(); @@ -44,9 +55,18 @@ class ContentExceptionsTableModel : public TableModel { virtual void SetObserver(TableModelObserver* observer); private: + HostContentSettingsMap* map(bool is_off_the_record) { + return is_off_the_record ? off_the_record_map_ : map_; + } + HostContentSettingsMap::SettingsForOneType& entries(bool is_off_the_record) { + return is_off_the_record ? off_the_record_entries_ : entries_; + } + HostContentSettingsMap* map_; + HostContentSettingsMap* off_the_record_map_; ContentSettingsType content_type_; HostContentSettingsMap::SettingsForOneType entries_; + HostContentSettingsMap::SettingsForOneType off_the_record_entries_; TableModelObserver* observer_; DISALLOW_COPY_AND_ASSIGN(ContentExceptionsTableModel); diff --git a/chrome/browser/gtk/options/content_exception_editor.cc b/chrome/browser/gtk/options/content_exception_editor.cc index ea12db9..002dfb3 100644 --- a/chrome/browser/gtk/options/content_exception_editor.cc +++ b/chrome/browser/gtk/options/content_exception_editor.cc @@ -18,9 +18,11 @@ ContentExceptionEditor::ContentExceptionEditor( GtkWindow* parent, ContentExceptionEditor::Delegate* delegate, ContentExceptionsTableModel* model, + bool allow_off_the_record, int index, const HostContentSettingsMap::Pattern& pattern, - ContentSetting setting) + ContentSetting setting, + bool is_off_the_record) : delegate_(delegate), model_(model), cb_model_(model->content_type() == CONTENT_SETTINGS_TYPE_COOKIES), @@ -56,6 +58,11 @@ ContentExceptionEditor::ContentExceptionEditor( gtk_combo_box_set_active(GTK_COMBO_BOX(action_combo_), cb_model_.IndexForSetting(setting_)); + otr_checkbox_ = gtk_check_button_new_with_label( + l10n_util::GetStringUTF8(IDS_EXCEPTION_EDITOR_OTR_TITLE).c_str()); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(otr_checkbox_), + is_off_the_record); + GtkWidget* table = gtk_util::CreateLabeledControlsGroup( NULL, l10n_util::GetStringUTF8(IDS_EXCEPTION_EDITOR_PATTERN_TITLE).c_str(), @@ -63,6 +70,10 @@ ContentExceptionEditor::ContentExceptionEditor( l10n_util::GetStringUTF8(IDS_EXCEPTION_EDITOR_ACTION_TITLE).c_str(), action_combo_, NULL); + if (allow_off_the_record) { + gtk_table_attach(GTK_TABLE(table), otr_checkbox_, + 0, 2, 2, 3, GTK_FILL, GTK_FILL, 0, 0); + } gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox), table, FALSE, FALSE, 0); @@ -79,9 +90,10 @@ ContentExceptionEditor::ContentExceptionEditor( } bool ContentExceptionEditor::IsPatternValid( - const HostContentSettingsMap::Pattern& pattern) const { + const HostContentSettingsMap::Pattern& pattern, + bool is_off_the_record) const { bool is_valid_pattern = pattern.IsValid() && - (model_->IndexOfExceptionByPattern(pattern) == -1); + (model_->IndexOfExceptionByPattern(pattern, is_off_the_record) == -1); return is_new() ? is_valid_pattern : (!pattern.AsString().empty() && ((pattern_ == pattern) || is_valid_pattern)); @@ -96,7 +108,9 @@ void ContentExceptionEditor::UpdateImage(GtkWidget* image, bool is_valid) { void ContentExceptionEditor::OnEntryChanged(GtkWidget* entry) { HostContentSettingsMap::Pattern new_pattern( gtk_entry_get_text(GTK_ENTRY(entry))); - bool is_valid = IsPatternValid(new_pattern); + bool is_off_the_record = + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(otr_checkbox_)); + bool is_valid = IsPatternValid(new_pattern, is_off_the_record); gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog_), GTK_RESPONSE_OK, is_valid); UpdateImage(pattern_image_, is_valid); @@ -109,7 +123,10 @@ void ContentExceptionEditor::OnResponse(GtkWidget* sender, int response_id) { gtk_entry_get_text(GTK_ENTRY(entry_))); ContentSetting setting = cb_model_.SettingForIndex( gtk_combo_box_get_active(GTK_COMBO_BOX(action_combo_))); - delegate_->AcceptExceptionEdit(new_pattern, setting, index_, is_new()); + bool is_off_the_record = + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(otr_checkbox_)); + delegate_->AcceptExceptionEdit( + new_pattern, setting, is_off_the_record, index_, is_new()); } gtk_widget_destroy(dialog_); diff --git a/chrome/browser/gtk/options/content_exception_editor.h b/chrome/browser/gtk/options/content_exception_editor.h index 5bd7ad0..98dcbf9 100644 --- a/chrome/browser/gtk/options/content_exception_editor.h +++ b/chrome/browser/gtk/options/content_exception_editor.h @@ -26,6 +26,7 @@ class ContentExceptionEditor { virtual void AcceptExceptionEdit( const HostContentSettingsMap::Pattern& pattern, ContentSetting setting, + bool is_off_the_record, int index, bool is_new) = 0; @@ -36,15 +37,18 @@ class ContentExceptionEditor { ContentExceptionEditor(GtkWindow* parent, Delegate* delegate, ContentExceptionsTableModel* model, + bool allow_off_the_record, int index, const HostContentSettingsMap::Pattern& pattern, - ContentSetting setting); + ContentSetting setting, + bool is_off_the_record); private: // Returns true if we're adding a new item. bool is_new() const { return index_ == -1; } - bool IsPatternValid(const HostContentSettingsMap::Pattern& pattern) const; + bool IsPatternValid(const HostContentSettingsMap::Pattern& pattern, + bool is_off_the_record) const; void UpdateImage(GtkWidget* image, bool is_valid); @@ -69,6 +73,7 @@ class ContentExceptionEditor { GtkWidget* entry_; GtkWidget* pattern_image_; GtkWidget* action_combo_; + GtkWidget* otr_checkbox_; DISALLOW_COPY_AND_ASSIGN(ContentExceptionEditor); }; diff --git a/chrome/browser/gtk/options/content_exceptions_window_gtk.cc b/chrome/browser/gtk/options/content_exceptions_window_gtk.cc index 0aa85e3..5894e9f 100644 --- a/chrome/browser/gtk/options/content_exceptions_window_gtk.cc +++ b/chrome/browser/gtk/options/content_exceptions_window_gtk.cc @@ -26,6 +26,7 @@ ContentExceptionsWindowGtk* instances[CONTENT_SETTINGS_NUM_TYPES] = { NULL }; void ContentExceptionsWindowGtk::ShowExceptionsWindow( GtkWindow* parent, HostContentSettingsMap* map, + HostContentSettingsMap* off_the_record_map, ContentSettingsType type) { DCHECK(map); DCHECK(type < CONTENT_SETTINGS_NUM_TYPES); @@ -34,7 +35,8 @@ void ContentExceptionsWindowGtk::ShowExceptionsWindow( if (!instances[type]) { // Create the options window. - instances[type] = new ContentExceptionsWindowGtk(parent, map, type); + instances[type] = + new ContentExceptionsWindowGtk(parent, map, off_the_record_map, type); } else { gtk_util::PresentWindow(instances[type]->dialog_, 0); } @@ -46,10 +48,13 @@ ContentExceptionsWindowGtk::~ContentExceptionsWindowGtk() { ContentExceptionsWindowGtk::ContentExceptionsWindowGtk( GtkWindow* parent, HostContentSettingsMap* map, - ContentSettingsType type) { + HostContentSettingsMap* off_the_record_map, + ContentSettingsType type) + : allow_off_the_record_(off_the_record_map) { // Build the model adapters that translate views and TableModels into // something GTK can use. - list_store_ = gtk_list_store_new(COL_COUNT, G_TYPE_STRING, G_TYPE_STRING); + list_store_ = gtk_list_store_new( + COL_COUNT, G_TYPE_STRING, G_TYPE_STRING, PANGO_TYPE_STYLE); treeview_ = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store_)); g_object_unref(list_store_); @@ -62,6 +67,7 @@ ContentExceptionsWindowGtk::ContentExceptionsWindowGtk( l10n_util::GetStringUTF8(IDS_EXCEPTIONS_PATTERN_HEADER).c_str(), gtk_cell_renderer_text_new(), "text", COL_PATTERN, + "style", COL_OTR, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_), pattern_column); gtk_tree_view_column_set_sort_column_id(pattern_column, COL_PATTERN); @@ -70,6 +76,7 @@ ContentExceptionsWindowGtk::ContentExceptionsWindowGtk( l10n_util::GetStringUTF8(IDS_EXCEPTIONS_ACTION_HEADER).c_str(), gtk_cell_renderer_text_new(), "text", COL_ACTION, + "style", COL_OTR, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_), action_column); gtk_tree_view_column_set_sort_column_id(action_column, COL_ACTION); @@ -81,7 +88,7 @@ ContentExceptionsWindowGtk::ContentExceptionsWindowGtk( G_CALLBACK(OnTreeSelectionChangedThunk), this); // Bind |list_store_| to our C++ model. - model_.reset(new ContentExceptionsTableModel(map, type)); + model_.reset(new ContentExceptionsTableModel(map, off_the_record_map, type)); model_adapter_.reset(new gtk_tree::TableAdapter(this, list_store_, model_.get())); // Force a reload of everything to copy data into |list_store_|. @@ -103,6 +110,8 @@ ContentExceptionsWindowGtk::ContentExceptionsWindowGtk( GtkWidget* hbox = gtk_hbox_new(FALSE, gtk_util::kControlSpacing); gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog_)->vbox), hbox); + GtkWidget* treeview_box = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); + // Create a scrolled window to wrap the treeview widget. GtkWidget* scrolled = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), @@ -110,7 +119,23 @@ ContentExceptionsWindowGtk::ContentExceptionsWindowGtk( gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(scrolled), treeview_); - gtk_box_pack_start(GTK_BOX(hbox), scrolled, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(treeview_box), scrolled, TRUE, TRUE, 0); + + // If we also have an OTR profile, inform the user that OTR exceptions are + // displayed in italics. + if (allow_off_the_record_) { + GtkWidget* incognito_label = gtk_label_new( + l10n_util::GetStringUTF8(IDS_EXCEPTIONS_OTR_IN_ITALICS).c_str()); + PangoAttrList* attributes = pango_attr_list_new(); + pango_attr_list_insert(attributes, + pango_attr_style_new(PANGO_STYLE_ITALIC)); + gtk_label_set_attributes(GTK_LABEL(incognito_label), attributes); + pango_attr_list_unref(attributes); + gtk_misc_set_alignment(GTK_MISC(incognito_label), 0, 0); + gtk_box_pack_start(GTK_BOX(treeview_box), incognito_label, FALSE, FALSE, 0); + } + + gtk_box_pack_start(GTK_BOX(hbox), treeview_box, TRUE, TRUE, 0); GtkWidget* button_box = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); @@ -161,19 +186,27 @@ void ContentExceptionsWindowGtk::SetColumnValues(int row, GtkTreeIter* iter) { std::wstring action = model_->GetText(row, IDS_EXCEPTIONS_ACTION_HEADER); gtk_list_store_set(list_store_, iter, COL_ACTION, WideToUTF8(action).c_str(), -1); + + bool is_off_the_record = model_->entry_is_off_the_record(row); + PangoStyle style = + is_off_the_record ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL; + gtk_list_store_set(list_store_, iter, COL_OTR, style, -1); } void ContentExceptionsWindowGtk::AcceptExceptionEdit( const HostContentSettingsMap::Pattern& pattern, ContentSetting setting, + bool is_off_the_record, int index, bool is_new) { + DCHECK(!is_off_the_record || allow_off_the_record_); + if (!is_new) model_->RemoveException(index); - model_->AddException(pattern, setting); + model_->AddException(pattern, setting, is_off_the_record); - int new_index = model_->IndexOfExceptionByPattern(pattern); + int new_index = model_->IndexOfExceptionByPattern(pattern, is_off_the_record); DCHECK_NE(-1, new_index); gtk_tree::SelectAndFocusRowNum(new_index, GTK_TREE_VIEW(treeview_)); @@ -196,9 +229,9 @@ void ContentExceptionsWindowGtk::UpdateButtonState() { void ContentExceptionsWindowGtk::Add(GtkWidget* widget) { new ContentExceptionEditor(GTK_WINDOW(dialog_), - this, model_.get(), -1, + this, model_.get(), allow_off_the_record_, -1, HostContentSettingsMap::Pattern(), - CONTENT_SETTING_BLOCK); + CONTENT_SETTING_BLOCK, false); } void ContentExceptionsWindowGtk::Edit(GtkWidget* widget) { @@ -208,8 +241,10 @@ void ContentExceptionsWindowGtk::Edit(GtkWidget* widget) { int index = *indices.begin(); const HostContentSettingsMap::PatternSettingPair& entry = model_->entry_at(index); - new ContentExceptionEditor(GTK_WINDOW(dialog_), this, model_.get(), index, - entry.first, entry.second); + new ContentExceptionEditor(GTK_WINDOW(dialog_), this, model_.get(), + allow_off_the_record_, index, + entry.first, entry.second, + model_->entry_is_off_the_record(index)); } void ContentExceptionsWindowGtk::Remove(GtkWidget* widget) { diff --git a/chrome/browser/gtk/options/content_exceptions_window_gtk.h b/chrome/browser/gtk/options/content_exceptions_window_gtk.h index c415419..aadd3ad 100644 --- a/chrome/browser/gtk/options/content_exceptions_window_gtk.h +++ b/chrome/browser/gtk/options/content_exceptions_window_gtk.h @@ -26,6 +26,7 @@ class ContentExceptionsWindowGtk : public gtk_tree::TableAdapter::Delegate, public: static void ShowExceptionsWindow(GtkWindow* window, HostContentSettingsMap* map, + HostContentSettingsMap* off_the_record_map, ContentSettingsType content_type); ~ContentExceptionsWindowGtk(); @@ -37,6 +38,7 @@ class ContentExceptionsWindowGtk : public gtk_tree::TableAdapter::Delegate, virtual void AcceptExceptionEdit( const HostContentSettingsMap::Pattern& pattern, ContentSetting setting, + bool is_off_the_record, int index, bool is_new); @@ -45,11 +47,13 @@ class ContentExceptionsWindowGtk : public gtk_tree::TableAdapter::Delegate, enum { COL_PATTERN, COL_ACTION, + COL_OTR, COL_COUNT }; ContentExceptionsWindowGtk(GtkWindow* parent, HostContentSettingsMap* map, + HostContentSettingsMap* off_the_record_map, ContentSettingsType type); // Updates which buttons are enabled. @@ -79,6 +83,9 @@ class ContentExceptionsWindowGtk : public gtk_tree::TableAdapter::Delegate, // gold standard data. scoped_ptr<ContentExceptionsTableModel> model_; + // True if we also show exceptions from an OTR profile. + bool allow_off_the_record_; + // The adapter that ferries data back and forth between |model_| and // |list_store_| whenever either of them change. scoped_ptr<gtk_tree::TableAdapter> model_adapter_; diff --git a/chrome/browser/gtk/options/content_filter_page_gtk.cc b/chrome/browser/gtk/options/content_filter_page_gtk.cc index 522a9a1..ae568ab 100644 --- a/chrome/browser/gtk/options/content_filter_page_gtk.cc +++ b/chrome/browser/gtk/options/content_filter_page_gtk.cc @@ -184,9 +184,13 @@ void ContentFilterPageGtk::OnExceptionsClicked(GtkWidget* button) { } HostContentSettingsMap* settings_map = profile()->GetHostContentSettingsMap(); + HostContentSettingsMap* otr_settings_map = + profile()->HasOffTheRecordProfile() ? + profile()->GetOffTheRecordProfile()->GetHostContentSettingsMap() : + NULL; ContentExceptionsWindowGtk::ShowExceptionsWindow( GTK_WINDOW(gtk_widget_get_toplevel(button)), - settings_map, content_type_); + settings_map, otr_settings_map, content_type_); } void ContentFilterPageGtk::OnPluginsPageLinkClicked(GtkWidget* button) { diff --git a/chrome/browser/gtk/options/cookie_filter_page_gtk.cc b/chrome/browser/gtk/options/cookie_filter_page_gtk.cc index e5714b2..d32ed23 100644 --- a/chrome/browser/gtk/options/cookie_filter_page_gtk.cc +++ b/chrome/browser/gtk/options/cookie_filter_page_gtk.cc @@ -170,9 +170,13 @@ void CookieFilterPageGtk::OnCookiesAllowToggled(GtkWidget* toggle_button) { void CookieFilterPageGtk::OnExceptionsClicked(GtkWidget* button) { HostContentSettingsMap* settings_map = profile()->GetHostContentSettingsMap(); + HostContentSettingsMap* otr_settings_map = + profile()->HasOffTheRecordProfile() ? + profile()->GetOffTheRecordProfile()->GetHostContentSettingsMap() : + NULL; ContentExceptionsWindowGtk::ShowExceptionsWindow( GTK_WINDOW(gtk_widget_get_toplevel(button)), - settings_map, CONTENT_SETTINGS_TYPE_COOKIES); + settings_map, otr_settings_map, CONTENT_SETTINGS_TYPE_COOKIES); } void CookieFilterPageGtk::OnBlockThirdPartyToggled(GtkWidget* toggle_button) { diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc index a2ddb0b..e9b76d9 100644 --- a/chrome/browser/profile.cc +++ b/chrome/browser/profile.cc @@ -346,6 +346,10 @@ class OffTheRecordProfileImpl : public Profile, NOTREACHED(); } + virtual bool HasOffTheRecordProfile() { + return true; + } + virtual Profile* GetOriginalProfile() { return profile_; } @@ -1024,6 +1028,10 @@ void ProfileImpl::DestroyOffTheRecordProfile() { off_the_record_profile_.reset(); } +bool ProfileImpl::HasOffTheRecordProfile() { + return off_the_record_profile_.get() != NULL; +} + Profile* ProfileImpl::GetOriginalProfile() { return this; } diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h index 6c3eb45..f493dac 100644 --- a/chrome/browser/profile.h +++ b/chrome/browser/profile.h @@ -150,6 +150,9 @@ class Profile { // Destroys the off the record profile. virtual void DestroyOffTheRecordProfile() = 0; + // True if an off the record profile exists. + virtual bool HasOffTheRecordProfile() = 0; + // Return the original "recording" profile. This method returns this if the // profile is not off the record. virtual Profile* GetOriginalProfile() = 0; @@ -480,6 +483,7 @@ class ProfileImpl : public Profile, virtual bool IsOffTheRecord(); virtual Profile* GetOffTheRecordProfile(); virtual void DestroyOffTheRecordProfile(); + virtual bool HasOffTheRecordProfile(); virtual Profile* GetOriginalProfile(); virtual webkit_database::DatabaseTracker* GetDatabaseTracker(); virtual history::TopSites* GetTopSites(); diff --git a/chrome/browser/views/options/content_exceptions_table_view.cc b/chrome/browser/views/options/content_exceptions_table_view.cc new file mode 100644 index 0000000..0f7fa6a --- /dev/null +++ b/chrome/browser/views/options/content_exceptions_table_view.cc @@ -0,0 +1,33 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/views/options/content_exceptions_table_view.h" + +#include "gfx/font.h" + +ContentExceptionsTableView::ContentExceptionsTableView( + ContentExceptionsTableModel* model, + const std::vector<TableColumn>& columns) + : views::TableView(model, columns, views::TEXT_ONLY, false, true, false), + exceptions_(model) { + SetCustomColorsEnabled(true); +} + +bool ContentExceptionsTableView::GetCellColors(int model_row, + int column, + ItemColor* foreground, + ItemColor* background, + LOGFONT* logfont) { + if (!exceptions_->entry_is_off_the_record(model_row)) + return false; + + foreground->color_is_set = false; + background->color_is_set = false; + + gfx::Font font; + font = font.DeriveFont(0, gfx::Font::ITALIC); + HFONT hf = font.hfont(); + GetObject(hf, sizeof(LOGFONT), logfont); + return true; +} diff --git a/chrome/browser/views/options/content_exceptions_table_view.h b/chrome/browser/views/options/content_exceptions_table_view.h new file mode 100644 index 0000000..57c4ab0 --- /dev/null +++ b/chrome/browser/views/options/content_exceptions_table_view.h @@ -0,0 +1,30 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_VIEWS_OPTIONS_CONTENT_EXCEPTIONS_TABLE_VIEW_H_ +#define CHROME_BROWSER_VIEWS_OPTIONS_CONTENT_EXCEPTIONS_TABLE_VIEW_H_ + +#include "chrome/browser/content_exceptions_table_model.h" +#include "views/controls/table/table_view.h" + +// A thin wrapper around TableView that displays off-the-record entries in +// italics. +class ContentExceptionsTableView : public views::TableView { + public: + ContentExceptionsTableView(ContentExceptionsTableModel* model, + const std::vector<TableColumn>& columns); + + virtual ~ContentExceptionsTableView() {} + + private: + virtual bool GetCellColors(int model_row, + int column, + ItemColor* foreground, + ItemColor* background, + LOGFONT* logfont); + + ContentExceptionsTableModel* exceptions_; +}; + +#endif // CHROME_BROWSER_VIEWS_OPTIONS_CONTENT_EXCEPTIONS_TABLE_VIEW_H_ diff --git a/chrome/browser/views/options/content_filter_page_view.cc b/chrome/browser/views/options/content_filter_page_view.cc index 45720e3..e7664cf 100644 --- a/chrome/browser/views/options/content_filter_page_view.cc +++ b/chrome/browser/views/options/content_filter_page_view.cc @@ -166,7 +166,11 @@ void ContentFilterPageView::ButtonPressed(views::Button* sender, profile()->GetGeolocationContentSettingsMap())); } else { ExceptionsView::ShowExceptionsWindow(GetWindow()->GetNativeWindow(), - profile()->GetHostContentSettingsMap(), content_type_); + profile()->GetHostContentSettingsMap(), + profile()->HasOffTheRecordProfile() ? + profile()->GetOffTheRecordProfile()->GetHostContentSettingsMap() : + NULL, + content_type_); } return; } diff --git a/chrome/browser/views/options/exception_editor_view.cc b/chrome/browser/views/options/exception_editor_view.cc index 4e358bf..ab08563 100644 --- a/chrome/browser/views/options/exception_editor_view.cc +++ b/chrome/browser/views/options/exception_editor_view.cc @@ -21,15 +21,19 @@ ExceptionEditorView::ExceptionEditorView( Delegate* delegate, ContentExceptionsTableModel* model, + bool allow_off_the_record, int index, const HostContentSettingsMap::Pattern& pattern, - ContentSetting setting) + ContentSetting setting, + bool is_off_the_record) : delegate_(delegate), model_(model), cb_model_(model->content_type() == CONTENT_SETTINGS_TYPE_COOKIES), + allow_off_the_record_(allow_off_the_record), index_(index), pattern_(pattern), - setting_(setting) { + setting_(setting), + is_off_the_record_(is_off_the_record) { Init(); } @@ -55,7 +59,8 @@ bool ExceptionEditorView::IsDialogButtonEnabled( MessageBoxFlags::DialogButton button) const { if (button == MessageBoxFlags::DIALOGBUTTON_OK) { return IsPatternValid(HostContentSettingsMap::Pattern( - UTF16ToUTF8(pattern_tf_->text()))); + UTF16ToUTF8(pattern_tf_->text())), + incognito_cb_->checked()); } return true; } @@ -68,7 +73,9 @@ bool ExceptionEditorView::Accept() { HostContentSettingsMap::Pattern new_pattern(UTF16ToUTF8(pattern_tf_->text())); ContentSetting setting = cb_model_.SettingForIndex(action_cb_->selected_item()); - delegate_->AcceptExceptionEdit(new_pattern, setting, index_, is_new()); + bool is_off_the_record = incognito_cb_->checked(); + delegate_->AcceptExceptionEdit( + new_pattern, setting, is_off_the_record, index_, is_new()); return true; } @@ -80,7 +87,7 @@ void ExceptionEditorView::ContentsChanged(views::Textfield* sender, const std::wstring& new_contents) { GetDialogClientView()->UpdateDialogButtons(); UpdateImageView(pattern_iv_, IsPatternValid(HostContentSettingsMap::Pattern( - UTF16ToUTF8(pattern_tf_->text())))); + UTF16ToUTF8(pattern_tf_->text())), incognito_cb_->checked())); } bool ExceptionEditorView::HandleKeystroke( @@ -99,12 +106,16 @@ void ExceptionEditorView::Init() { pattern_iv_ = new views::ImageView; UpdateImageView(pattern_iv_, IsPatternValid(HostContentSettingsMap::Pattern( - UTF16ToUTF8(pattern_tf_->text())))); + UTF16ToUTF8(pattern_tf_->text())), is_off_the_record_)); action_cb_ = new views::Combobox(&cb_model_); if (!is_new()) action_cb_->SetSelectedItem(cb_model_.IndexForSetting(setting_)); + incognito_cb_ = new views::Checkbox( + l10n_util::GetString(IDS_EXCEPTION_EDITOR_OTR_TITLE)); + incognito_cb_->SetChecked(is_off_the_record_); + GridLayout* layout = CreatePanelGridLayout(this); SetLayoutManager(layout); @@ -128,6 +139,11 @@ void ExceptionEditorView::Init() { layout->StartRowWithPadding(0, 1, 0, kRelatedControlVerticalSpacing); layout->AddView(CreateLabel(IDS_EXCEPTION_EDITOR_ACTION_TITLE)); layout->AddView(action_cb_); + + if (allow_off_the_record_) { + layout->StartRowWithPadding(0, 1, 0, kRelatedControlVerticalSpacing); + layout->AddView(incognito_cb_, 3, 1, GridLayout::FILL, GridLayout::FILL); + } } views::Label* ExceptionEditorView::CreateLabel(int message_id) { @@ -137,9 +153,10 @@ views::Label* ExceptionEditorView::CreateLabel(int message_id) { } bool ExceptionEditorView::IsPatternValid( - const HostContentSettingsMap::Pattern& pattern) const { + const HostContentSettingsMap::Pattern& pattern, + bool is_off_the_record) const { bool is_valid_pattern = pattern.IsValid() && - (model_->IndexOfExceptionByPattern(pattern) == -1); + (model_->IndexOfExceptionByPattern(pattern, is_off_the_record) == -1); return is_new() ? is_valid_pattern : (!pattern.AsString().empty() && ((pattern_ == pattern) || is_valid_pattern)); diff --git a/chrome/browser/views/options/exception_editor_view.h b/chrome/browser/views/options/exception_editor_view.h index 4c73141..3c815db 100644 --- a/chrome/browser/views/options/exception_editor_view.h +++ b/chrome/browser/views/options/exception_editor_view.h @@ -12,6 +12,7 @@ #include "chrome/common/content_settings.h" #include "chrome/common/content_settings_types.h" #include "views/window/dialog_delegate.h" +#include "views/controls/button/checkbox.h" #include "views/controls/combobox/combobox.h" #include "views/controls/textfield/textfield.h" @@ -38,6 +39,7 @@ class ExceptionEditorView : public views::View, virtual void AcceptExceptionEdit( const HostContentSettingsMap::Pattern& pattern, ContentSetting setting, + bool is_off_the_record, int index, bool is_new) = 0; @@ -50,9 +52,11 @@ class ExceptionEditorView : public views::View, // used by ExceptionEditorView but instead passed to the delegate. ExceptionEditorView(Delegate* delegate, ContentExceptionsTableModel* model, + bool allow_off_the_record, int index, const HostContentSettingsMap::Pattern& pattern, - ContentSetting setting); + ContentSetting setting, + bool is_off_the_record); virtual ~ExceptionEditorView() {} void Show(gfx::NativeWindow parent); @@ -82,7 +86,8 @@ class ExceptionEditorView : public views::View, // Returns true if we're adding a new item. bool is_new() const { return index_ == -1; } - bool IsPatternValid(const HostContentSettingsMap::Pattern& pattern) const; + bool IsPatternValid(const HostContentSettingsMap::Pattern& pattern, + bool is_off_the_record) const; void UpdateImageView(views::ImageView* image_view, bool is_valid); @@ -91,13 +96,16 @@ class ExceptionEditorView : public views::View, ContentSettingComboModel cb_model_; // Index of the item being edited. If -1, indices this is a new entry. + const bool allow_off_the_record_; const int index_; const HostContentSettingsMap::Pattern pattern_; const ContentSetting setting_; + const bool is_off_the_record_; views::Textfield* pattern_tf_; views::ImageView* pattern_iv_; views::Combobox* action_cb_; + views::Checkbox* incognito_cb_; DISALLOW_COPY_AND_ASSIGN(ExceptionEditorView); }; diff --git a/chrome/browser/views/options/exceptions_view.cc b/chrome/browser/views/options/exceptions_view.cc index 8d7fc76..eadaf75 100644 --- a/chrome/browser/views/options/exceptions_view.cc +++ b/chrome/browser/views/options/exceptions_view.cc @@ -8,10 +8,12 @@ #include <vector> #include "app/l10n_util.h" +#include "chrome/browser/views/options/content_exceptions_table_view.h" #include "grit/generated_resources.h" #include "grit/locale_settings.h" #include "gfx/rect.h" #include "views/controls/button/native_button.h" +#include "views/controls/label.h" #include "views/controls/table/table_view.h" #include "views/grid_layout.h" #include "views/standard_layout.h" @@ -21,11 +23,14 @@ static const int kExceptionsViewInsetSize = 5; static ExceptionsView* instances[CONTENT_SETTINGS_NUM_TYPES] = { NULL }; // static -void ExceptionsView::ShowExceptionsWindow(gfx::NativeWindow parent, - HostContentSettingsMap* map, - ContentSettingsType content_type) { +void ExceptionsView::ShowExceptionsWindow( + gfx::NativeWindow parent, + HostContentSettingsMap* map, + HostContentSettingsMap* off_the_record_map, + ContentSettingsType content_type) { if (!instances[content_type]) { - instances[content_type] = new ExceptionsView(map, content_type); + instances[content_type] = + new ExceptionsView(map, off_the_record_map, content_type); views::Window::CreateChromeWindow(parent, gfx::Rect(), instances[content_type]); } @@ -125,20 +130,25 @@ std::wstring ExceptionsView::GetWindowTitle() const { void ExceptionsView::AcceptExceptionEdit( const HostContentSettingsMap::Pattern& pattern, ContentSetting setting, + bool is_off_the_record, int index, bool is_new) { + DCHECK(!is_off_the_record || allow_off_the_record_); + if (!is_new) model_.RemoveException(index); - model_.AddException(pattern, setting); + model_.AddException(pattern, setting, is_off_the_record); - int new_index = model_.IndexOfExceptionByPattern(pattern); + int new_index = model_.IndexOfExceptionByPattern(pattern, is_off_the_record); DCHECK(new_index != -1); table_->Select(new_index); } ExceptionsView::ExceptionsView(HostContentSettingsMap* map, + HostContentSettingsMap* off_the_record_map, ContentSettingsType type) - : model_(map, type), + : model_(map, off_the_record_map, type), + allow_off_the_record_(off_the_record_map != NULL), table_(NULL), add_button_(NULL), edit_button_(NULL), @@ -159,8 +169,7 @@ void ExceptionsView::Init() { columns.push_back( TableColumn(IDS_EXCEPTIONS_ACTION_HEADER, TableColumn::LEFT, -1, .25)); columns.back().sortable = true; - table_ = new views::TableView(&model_, columns, views::TEXT_ONLY, false, true, - false); + table_ = new ContentExceptionsTableView(&model_, columns); views::TableView::SortDescriptors sort; sort.push_back( views::TableView::SortDescriptor(IDS_EXCEPTIONS_PATTERN_HEADER, true)); @@ -202,6 +211,15 @@ void ExceptionsView::Init() { layout->AddView(table_); layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); + if (allow_off_the_record_) { + views::Label* label = new views::Label(l10n_util::GetString( + IDS_EXCEPTIONS_OTR_IN_ITALICS)); + label->SetHorizontalAlignment(views::Label::ALIGN_LEFT); + layout->StartRow(0, single_column_layout_id); + layout->AddView(label, 1, 1, GridLayout::LEADING, GridLayout::CENTER); + layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); + } + UpdateButtonState(); } @@ -215,9 +233,9 @@ void ExceptionsView::UpdateButtonState() { void ExceptionsView::Add() { ExceptionEditorView* view = - new ExceptionEditorView(this, &model_, -1, + new ExceptionEditorView(this, &model_, allow_off_the_record_, -1, HostContentSettingsMap::Pattern(), - CONTENT_SETTING_BLOCK); + CONTENT_SETTING_BLOCK, false); view->Show(window()->GetNativeWindow()); UpdateButtonState(); @@ -229,7 +247,9 @@ void ExceptionsView::Edit() { const HostContentSettingsMap::PatternSettingPair& entry = model_.entry_at(index); ExceptionEditorView* view = - new ExceptionEditorView(this, &model_, index, entry.first, entry.second); + new ExceptionEditorView(this, &model_, allow_off_the_record_, index, + entry.first, entry.second, + model_.entry_is_off_the_record(index)); view->Show(window()->GetNativeWindow()); } diff --git a/chrome/browser/views/options/exceptions_view.h b/chrome/browser/views/options/exceptions_view.h index 241d055..ceb9bcb 100644 --- a/chrome/browser/views/options/exceptions_view.h +++ b/chrome/browser/views/options/exceptions_view.h @@ -38,6 +38,7 @@ class ExceptionsView : public ExceptionEditorView::Delegate, // Shows the Exceptions window. static void ShowExceptionsWindow(gfx::NativeWindow parent, HostContentSettingsMap* map, + HostContentSettingsMap* off_the_record_map, ContentSettingsType content_type); virtual ~ExceptionsView(); @@ -69,11 +70,14 @@ class ExceptionsView : public ExceptionEditorView::Delegate, virtual void AcceptExceptionEdit( const HostContentSettingsMap::Pattern& pattern, ContentSetting setting, + bool is_off_the_record, int index, bool is_new); private: - ExceptionsView(HostContentSettingsMap* map, ContentSettingsType type); + ExceptionsView(HostContentSettingsMap* map, + HostContentSettingsMap* off_the_record_map, + ContentSettingsType type); void Init(); @@ -95,6 +99,9 @@ class ExceptionsView : public ExceptionEditorView::Delegate, // The model displayed in the table. ContentExceptionsTableModel model_; + // True if the user can also add off the record entries. + bool allow_off_the_record_; + views::TableView* table_; views::NativeButton* add_button_; diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 495d6d6..282b174 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2560,6 +2560,8 @@ 'browser/views/options/advanced_contents_view.h', 'browser/views/options/advanced_page_view.cc', 'browser/views/options/advanced_page_view.h', + 'browser/views/options/content_exceptions_table_view.cc', + 'browser/views/options/content_exceptions_table_view.h', 'browser/views/options/content_page_view.cc', 'browser/views/options/content_page_view.h', 'browser/views/options/content_filter_page_view.cc', diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h index adc8d95..b2b572b 100644 --- a/chrome/test/testing_profile.h +++ b/chrome/test/testing_profile.h @@ -100,6 +100,8 @@ class TestingProfile : public Profile { virtual void DestroyOffTheRecordProfile() {} + virtual bool HasOffTheRecordProfile() { return false; } + virtual Profile* GetOriginalProfile() { return this; } virtual webkit_database::DatabaseTracker* GetDatabaseTracker(); virtual VisitedLinkMaster* GetVisitedLinkMaster() { return NULL; } |