summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoratwilson@chromium.org <atwilson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-15 18:09:52 +0000
committeratwilson@chromium.org <atwilson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-15 18:09:52 +0000
commitc43207ea2d894f09a4079d4d97ad8591e8267553 (patch)
tree727703d181dbcdb75c7102e0e34b0bbe93c7d883
parenta75965d3b1a1ed03ac54aac886d7b44726d7d164 (diff)
downloadchromium_src-c43207ea2d894f09a4079d4d97ad8591e8267553.zip
chromium_src-c43207ea2d894f09a4079d4d97ad8591e8267553.tar.gz
chromium_src-c43207ea2d894f09a4079d4d97ad8591e8267553.tar.bz2
Implement new task manager mocks on windows.
Added API to differentiate between background resources and normal foreground tabs, and added support for grouping processes containing background resources in a separate section of task manager. BUG=63140 TEST=bring up task manager on windows Review URL: http://codereview.chromium.org/4987001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@66132 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--app/table_model.cc4
-rw-r--r--app/table_model.h3
-rw-r--r--chrome/app/generated_resources.grd6
-rw-r--r--chrome/browser/task_manager/task_manager.cc58
-rw-r--r--chrome/browser/task_manager/task_manager.h18
-rw-r--r--chrome/browser/task_manager/task_manager_resource_providers.cc15
-rw-r--r--chrome/browser/task_manager/task_manager_resource_providers.h15
-rw-r--r--chrome/browser/ui/views/hung_renderer_view.cc2
-rw-r--r--chrome/browser/ui/views/task_manager_view.cc57
-rw-r--r--views/controls/table/group_table_view.cc7
-rw-r--r--views/controls/table/group_table_view.h6
-rw-r--r--views/controls/table/table_view.cc6
12 files changed, 163 insertions, 34 deletions
diff --git a/app/table_model.cc b/app/table_model.cc
index 821e14c..4800f6a 100644
--- a/app/table_model.cc
+++ b/app/table_model.cc
@@ -80,6 +80,10 @@ std::wstring TableModel::GetTooltip(int row) {
return std::wstring();
}
+bool TableModel::ShouldIndent(int row) {
+ return false;
+}
+
bool TableModel::HasGroups() {
return false;
}
diff --git a/app/table_model.h b/app/table_model.h
index baae390..78dedf1 100644
--- a/app/table_model.h
+++ b/app/table_model.h
@@ -45,6 +45,9 @@ class TableModel {
// column zero.
virtual std::wstring GetTooltip(int row);
+ // If true, this row should be indented.
+ virtual bool ShouldIndent(int row);
+
// Returns true if the TableView has groups. Groups provide a way to visually
// delineate the rows in a table view. When groups are enabled table view
// shows a visual separator for each group, followed by all the rows in
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 10b50b7..3653cd6 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -3483,6 +3483,12 @@ each locale. -->
<message name="IDS_TASK_MANAGER_WEB_BROWSER_CELL_TEXT" desc="The text of the web browser process row">
Browser
</message>
+ <message name="IDS_TASK_MANAGER_BACKGROUND_SEPARATOR" desc="The heading for the background pages grouping in the task manager">
+ Background Apps and Extensions
+ </message>
+ <message name="IDS_TASK_MANAGER_FOREGROUND_SEPARATOR" desc="The heading for the foreground pages grouping in the task manager">
+ Browser Tabs and Plugins
+ </message>
<message name="IDS_TASK_MANAGER_EXTENSION_PREFIX" desc="The prefix for a Task Manager extension row (always visible if the extension has a view)">
Extension: <ph name="EXTENSION_NAME">$1<ex>Sample Extension</ex></ph>
</message>
diff --git a/chrome/browser/task_manager/task_manager.cc b/chrome/browser/task_manager/task_manager.cc
index 2080b34..c6500fa 100644
--- a/chrome/browser/task_manager/task_manager.cc
+++ b/chrome/browser/task_manager/task_manager.cc
@@ -78,14 +78,14 @@ TaskManagerModel::TaskManagerModel(TaskManager* task_manager)
new TaskManagerBrowserProcessResourceProvider(task_manager);
browser_provider->AddRef();
providers_.push_back(browser_provider);
- TaskManagerTabContentsResourceProvider* wc_provider =
- new TaskManagerTabContentsResourceProvider(task_manager);
- wc_provider->AddRef();
- providers_.push_back(wc_provider);
TaskManagerBackgroundContentsResourceProvider* bc_provider =
new TaskManagerBackgroundContentsResourceProvider(task_manager);
bc_provider->AddRef();
providers_.push_back(bc_provider);
+ TaskManagerTabContentsResourceProvider* wc_provider =
+ new TaskManagerTabContentsResourceProvider(task_manager);
+ wc_provider->AddRef();
+ providers_.push_back(wc_provider);
TaskManagerChildProcessResourceProvider* child_process_provider =
new TaskManagerChildProcessResourceProvider(task_manager);
child_process_provider->AddRef();
@@ -120,12 +120,12 @@ void TaskManagerModel::RemoveObserver(TaskManagerModelObserver* observer) {
}
string16 TaskManagerModel::GetResourceTitle(int index) const {
- CHECK(index < ResourceCount());
+ CHECK_LT(index, ResourceCount());
return WideToUTF16Hack(resources_[index]->GetTitle());
}
int64 TaskManagerModel::GetNetworkUsage(int index) const {
- CHECK(index < ResourceCount());
+ CHECK_LT(index, ResourceCount());
return GetNetworkUsage(resources_[index]);
}
@@ -142,12 +142,12 @@ string16 TaskManagerModel::GetResourceNetworkUsage(int index) const {
}
double TaskManagerModel::GetCPUUsage(int index) const {
- CHECK(index < ResourceCount());
+ CHECK_LT(index, ResourceCount());
return GetCPUUsage(resources_[index]);
}
string16 TaskManagerModel::GetResourceCPUUsage(int index) const {
- CHECK(index < ResourceCount());
+ CHECK_LT(index, ResourceCount());
return WideToUTF16Hack(StringPrintf(
#if defined(OS_MACOSX)
// Activity Monitor shows %cpu with one decimal digit -- be
@@ -180,7 +180,7 @@ string16 TaskManagerModel::GetResourcePhysicalMemory(int index) const {
}
int TaskManagerModel::GetProcessId(int index) const {
- CHECK(index < ResourceCount());
+ CHECK_LT(index, ResourceCount());
return base::GetProcId(resources_[index]->GetProcess());
}
@@ -189,13 +189,13 @@ string16 TaskManagerModel::GetResourceProcessId(int index) const {
}
string16 TaskManagerModel::GetResourceGoatsTeleported(int index) const {
- CHECK(index < ResourceCount());
+ CHECK_LT(index, ResourceCount());
return base::FormatNumber(GetGoatsTeleported(index));
}
string16 TaskManagerModel::GetResourceWebCoreImageCacheSize(
int index) const {
- CHECK(index < ResourceCount());
+ CHECK_LT(index, ResourceCount());
if (!resources_[index]->ReportsCacheStats())
return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
const WebKit::WebCache::ResourceTypeStats stats(
@@ -205,7 +205,7 @@ string16 TaskManagerModel::GetResourceWebCoreImageCacheSize(
string16 TaskManagerModel::GetResourceWebCoreScriptsCacheSize(
int index) const {
- CHECK(index < ResourceCount());
+ CHECK_LT(index, ResourceCount());
if (!resources_[index]->ReportsCacheStats())
return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
const WebKit::WebCache::ResourceTypeStats stats(
@@ -215,7 +215,7 @@ string16 TaskManagerModel::GetResourceWebCoreScriptsCacheSize(
string16 TaskManagerModel::GetResourceWebCoreCSSCacheSize(
int index) const {
- CHECK(index < ResourceCount());
+ CHECK_LT(index, ResourceCount());
if (!resources_[index]->ReportsCacheStats())
return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
const WebKit::WebCache::ResourceTypeStats stats(
@@ -224,7 +224,7 @@ string16 TaskManagerModel::GetResourceWebCoreCSSCacheSize(
}
string16 TaskManagerModel::GetResourceSqliteMemoryUsed(int index) const {
- CHECK(index < ResourceCount());
+ CHECK_LT(index, ResourceCount());
if (!resources_[index]->ReportsSqliteMemoryUsed())
return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
return GetMemCellText(resources_[index]->SqliteMemoryUsedBytes());
@@ -244,7 +244,7 @@ string16 TaskManagerModel::GetResourceV8MemoryAllocatedSize(
}
bool TaskManagerModel::IsResourceFirstInGroup(int index) const {
- CHECK(index < ResourceCount());
+ CHECK_LT(index, ResourceCount());
TaskManager::Resource* resource = resources_[index];
GroupMap::const_iterator iter = group_map_.find(resource->GetProcess());
DCHECK(iter != group_map_.end());
@@ -252,8 +252,13 @@ bool TaskManagerModel::IsResourceFirstInGroup(int index) const {
return ((*group)[0] == resource);
}
+bool TaskManagerModel::IsBackgroundResource(int index) const {
+ CHECK_LT(index, ResourceCount());
+ return resources_[index]->IsBackground();
+}
+
SkBitmap TaskManagerModel::GetResourceIcon(int index) const {
- CHECK(index < ResourceCount());
+ CHECK_LT(index, ResourceCount());
SkBitmap icon = resources_[index]->GetIcon();
if (!icon.isNull())
return icon;
@@ -265,7 +270,7 @@ SkBitmap TaskManagerModel::GetResourceIcon(int index) const {
std::pair<int, int> TaskManagerModel::GetGroupRangeForResource(int index)
const {
- CHECK(index < ResourceCount());
+ CHECK_LT(index, ResourceCount());
TaskManager::Resource* resource = resources_[index];
GroupMap::const_iterator group_iter =
group_map_.find(resource->GetProcess());
@@ -392,22 +397,22 @@ int TaskManagerModel::CompareValues(int row1, int row2, int col_id) const {
base::ProcessHandle TaskManagerModel::GetResourceProcessHandle(int index)
const {
- CHECK(index < ResourceCount());
+ CHECK_LT(index, ResourceCount());
return resources_[index]->GetProcess();
}
TaskManager::Resource::Type TaskManagerModel::GetResourceType(int index) const {
- CHECK(index < ResourceCount());
+ CHECK_LT(index, ResourceCount());
return resources_[index]->GetType();
}
TabContents* TaskManagerModel::GetResourceTabContents(int index) const {
- CHECK(index < ResourceCount());
+ CHECK_LT(index, ResourceCount());
return resources_[index]->GetTabContents();
}
const Extension* TaskManagerModel::GetResourceExtension(int index) const {
- CHECK(index < ResourceCount());
+ CHECK_LT(index, ResourceCount());
return resources_[index]->GetExtension();
}
@@ -611,7 +616,7 @@ void TaskManagerModel::AddResource(TaskManager::Resource* resource) {
resources_.end(),
(*group_entries)[group_entries->size() - 2]);
DCHECK(iter != resources_.end());
- new_entry_index = static_cast<int>(iter - resources_.begin());
+ new_entry_index = static_cast<int>(iter - resources_.begin()) + 1;
resources_.insert(++iter, resource);
}
@@ -715,6 +720,11 @@ void TaskManagerModel::Clear() {
}
}
+void TaskManagerModel::ModelChanged() {
+ // Notify the table that the contents have changed for it to redraw.
+ FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_, OnModelChanged());
+}
+
void TaskManagerModel::NotifyResourceTypeStats(
base::ProcessId renderer_id,
const WebKit::WebCache::ResourceTypeStats& stats) {
@@ -966,6 +976,10 @@ void TaskManager::OnWindowClosed() {
model_->StopUpdating();
}
+void TaskManager::ModelChanged() {
+ model_->ModelChanged();
+}
+
// static
TaskManager* TaskManager::GetInstance() {
return Singleton<TaskManager>::get();
diff --git a/chrome/browser/task_manager/task_manager.h b/chrome/browser/task_manager/task_manager.h
index cef241c..9d933e5 100644
--- a/chrome/browser/task_manager/task_manager.h
+++ b/chrome/browser/task_manager/task_manager.h
@@ -102,6 +102,10 @@ class TaskManager {
const WebKit::WebCache::ResourceTypeStats& stats) {}
virtual void NotifyV8HeapStats(size_t v8_memory_allocated,
size_t v8_memory_used) {}
+
+ // Returns true if this resource is not visible to the user because it lives
+ // in the background (e.g. extension background page, background contents).
+ virtual bool IsBackground() const { return false; }
};
// ResourceProviders are responsible for adding/removing resources to the task
@@ -156,6 +160,12 @@ class TaskManager {
void OnWindowClosed();
+ // Invoked when a change to a resource has occurred that should cause any
+ // observers to completely refresh themselves (for example, the creation of
+ // a background resource in a process). Results in all observers receiving
+ // OnModelChanged() events.
+ void ModelChanged();
+
// Returns the singleton instance (and initializes it if necessary).
static TaskManager* GetInstance();
@@ -259,6 +269,10 @@ class TaskManagerModel : public URLRequestJobTracker::JobObserver,
// rendered by the same process are groupped together).
bool IsResourceFirstInGroup(int index) const;
+ // Returns true if the resource runs in the background (not visible to the
+ // user, e.g. extension background pages and BackgroundContents).
+ bool IsBackgroundResource(int index) const;
+
// Returns icon to be used for resource (for example a favicon).
SkBitmap GetResourceIcon(int index) const;
@@ -300,6 +314,10 @@ class TaskManagerModel : public URLRequestJobTracker::JobObserver,
void Clear(); // Removes all items.
+ // Sends OnModelChanged() to all observers to inform them of significant
+ // changes to the model.
+ void ModelChanged();
+
void NotifyResourceTypeStats(
base::ProcessId renderer_id,
const WebKit::WebCache::ResourceTypeStats& stats);
diff --git a/chrome/browser/task_manager/task_manager_resource_providers.cc b/chrome/browser/task_manager/task_manager_resource_providers.cc
index 13cd82f..73476c9 100644
--- a/chrome/browser/task_manager/task_manager_resource_providers.cc
+++ b/chrome/browser/task_manager/task_manager_resource_providers.cc
@@ -382,6 +382,10 @@ SkBitmap TaskManagerBackgroundContentsResource::GetIcon() const {
return *default_icon_;
}
+bool TaskManagerBackgroundContentsResource::IsBackground() const {
+ return true;
+}
+
////////////////////////////////////////////////////////////////////////////////
// TaskManagerBackgroundContentsResourceProvider class
////////////////////////////////////////////////////////////////////////////////
@@ -550,6 +554,9 @@ void TaskManagerBackgroundContentsResourceProvider::Observe(
}
Add(Details<BackgroundContentsOpenedDetails>(details)->contents,
application_name);
+ // Opening a new BackgroundContents needs to force the display to refresh
+ // (applications may now be considered "background" that weren't before).
+ task_manager_->ModelChanged();
break;
}
case NotificationType::BACKGROUND_CONTENTS_NAVIGATED: {
@@ -565,6 +572,9 @@ void TaskManagerBackgroundContentsResourceProvider::Observe(
}
case NotificationType::BACKGROUND_CONTENTS_DELETED:
Remove(Details<BackgroundContents>(details).ptr());
+ // Closing a BackgroundContents needs to force the display to refresh
+ // (applications may now be considered "foreground" that weren't before).
+ task_manager_->ModelChanged();
break;
default:
NOTREACHED() << "Unexpected notification.";
@@ -847,6 +857,11 @@ const Extension* TaskManagerExtensionProcessResource::GetExtension() const {
return extension_host_->extension();
}
+bool TaskManagerExtensionProcessResource::IsBackground() const {
+ return extension_host_->GetRenderViewType() ==
+ ViewType::EXTENSION_BACKGROUND_PAGE;
+}
+
////////////////////////////////////////////////////////////////////////////////
// TaskManagerExtensionProcessResourceProvider class
////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/task_manager/task_manager_resource_providers.h b/chrome/browser/task_manager/task_manager_resource_providers.h
index 62fbb53..9c4e8c4 100644
--- a/chrome/browser/task_manager/task_manager_resource_providers.h
+++ b/chrome/browser/task_manager/task_manager_resource_providers.h
@@ -81,9 +81,9 @@ class TaskManagerTabContentsResource : public TaskManagerRendererResource {
~TaskManagerTabContentsResource();
// TaskManager::Resource methods:
- std::wstring GetTitle() const;
- SkBitmap GetIcon() const;
- TabContents* GetTabContents() const;
+ virtual std::wstring GetTitle() const;
+ virtual SkBitmap GetIcon() const;
+ virtual TabContents* GetTabContents() const;
private:
TabContents* tab_contents_;
@@ -141,10 +141,11 @@ class TaskManagerBackgroundContentsResource
~TaskManagerBackgroundContentsResource();
// TaskManager::Resource methods:
- std::wstring GetTitle() const;
- const std::wstring& application_name() const { return application_name_; }
- SkBitmap GetIcon() const;
+ virtual std::wstring GetTitle() const;
+ virtual SkBitmap GetIcon() const;
+ virtual bool IsBackground() const;
+ const std::wstring& application_name() const { return application_name_; }
private:
BackgroundContents* background_contents_;
@@ -309,6 +310,8 @@ class TaskManagerExtensionProcessResource : public TaskManager::Resource {
// Returns the pid of the extension process.
int process_id() const { return pid_; }
+ // Returns true if the associated extension has a background page.
+ bool IsBackground() const;
private:
// The icon painted for the extension process.
static SkBitmap* default_icon_;
diff --git a/chrome/browser/ui/views/hung_renderer_view.cc b/chrome/browser/ui/views/hung_renderer_view.cc
index 775623e..3482380 100644
--- a/chrome/browser/ui/views/hung_renderer_view.cc
+++ b/chrome/browser/ui/views/hung_renderer_view.cc
@@ -353,7 +353,7 @@ void HungRendererDialogView::Init() {
columns.push_back(TableColumn());
hung_pages_table_ = new views::GroupTableView(
hung_pages_table_model_.get(), columns, views::ICON_AND_TEXT, true,
- false, true);
+ false, true, false);
hung_pages_table_->SetPreferredSize(
gfx::Size(kTableViewWidth, kTableViewHeight));
diff --git a/chrome/browser/ui/views/task_manager_view.cc b/chrome/browser/ui/views/task_manager_view.cc
index f8432d4..4d7236a 100644
--- a/chrome/browser/ui/views/task_manager_view.cc
+++ b/chrome/browser/ui/views/task_manager_view.cc
@@ -37,6 +37,10 @@
static const int kDefaultWidth = 460;
static const int kDefaultHeight = 270;
+// The group IDs used to separate background pages from foreground tabs.
+static const int kBackgroundGroupId = 0;
+static const int kForegroundGroupId = 1;
+
namespace {
////////////////////////////////////////////////////////////////////////////////
@@ -60,9 +64,13 @@ class TaskManagerTableModel : public views::GroupTableModel,
int RowCount();
std::wstring GetText(int row, int column);
SkBitmap GetIcon(int row);
+ bool ShouldIndent(int row);
void GetGroupRangeForItem(int item, views::GroupRange* range);
void SetObserver(TableModelObserver* observer);
virtual int CompareValues(int row1, int row2, int column_id);
+ virtual Groups GetGroups();
+ virtual bool HasGroups();
+ virtual int GetGroupID(int row);
// TaskManagerModelObserver.
virtual void OnModelChanged();
@@ -150,6 +158,10 @@ SkBitmap TaskManagerTableModel::GetIcon(int row) {
return model_->GetResourceIcon(row);
}
+bool TaskManagerTableModel::ShouldIndent(int row) {
+ return !model_->IsResourceFirstInGroup(row);
+}
+
void TaskManagerTableModel::GetGroupRangeForItem(int item,
views::GroupRange* range) {
std::pair<int, int> range_pair = model_->GetGroupRangeForResource(item);
@@ -165,6 +177,41 @@ int TaskManagerTableModel::CompareValues(int row1, int row2, int column_id) {
return model_->CompareValues(row1, row2, column_id);
}
+bool TaskManagerTableModel::HasGroups() {
+ return true;
+}
+
+int TaskManagerTableModel::GetGroupID(int row) {
+ // If there are any background resources in the group range, put the whole
+ // range in the background group.
+ std::pair<int, int> range_pair = model_->GetGroupRangeForResource(row);
+ for (int i = range_pair.first;
+ i < range_pair.first + range_pair.second;
+ ++i) {
+ if (model_->IsBackgroundResource(i))
+ return kBackgroundGroupId;
+ }
+ return kForegroundGroupId;
+}
+
+TableModel::Groups TaskManagerTableModel::GetGroups() {
+ Groups groups;
+
+ Group background_group;
+ background_group.title =
+ l10n_util::GetString(IDS_TASK_MANAGER_BACKGROUND_SEPARATOR);
+ background_group.id = kBackgroundGroupId;
+ groups.push_back(background_group);
+
+ Group foreground_group;
+ foreground_group.title =
+ l10n_util::GetString(IDS_TASK_MANAGER_FOREGROUND_SEPARATOR);
+ foreground_group.id = kForegroundGroupId;
+ groups.push_back(foreground_group);
+
+ return groups;
+}
+
void TaskManagerTableModel::OnModelChanged() {
if (observer_)
observer_->OnModelChanged();
@@ -178,6 +225,11 @@ void TaskManagerTableModel::OnItemsChanged(int start, int length) {
void TaskManagerTableModel::OnItemsAdded(int start, int length) {
if (observer_)
observer_->OnItemsAdded(start, length);
+ // There's a bug in the Windows ListView where inserting items with groups
+ // enabled puts them in the wrong position, so we just rebuild the list view
+ // in this case.
+ // (see: http://connect.microsoft.com/VisualStudio/feedback/details/115345/)
+ OnModelChanged();
}
void TaskManagerTableModel::OnItemsRemoved(int start, int length) {
@@ -301,7 +353,8 @@ TaskManagerView::~TaskManagerView() {
void TaskManagerView::Init() {
table_model_.reset(new TaskManagerTableModel(model_));
- columns_.push_back(TableColumn(IDS_TASK_MANAGER_PAGE_COLUMN,
+ // Page column has no header label.
+ columns_.push_back(TableColumn(IDS_TASK_MANAGER_PAGE_COLUMN, L"",
TableColumn::LEFT, -1, 1));
columns_.back().sortable = true;
columns_.push_back(TableColumn(IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN,
@@ -341,7 +394,7 @@ void TaskManagerView::Init() {
tab_table_ = new views::GroupTableView(table_model_.get(), columns_,
views::ICON_AND_TEXT, false, true,
- true);
+ true, false);
// Hide some columns by default
tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_PROCESS_ID_COLUMN, false);
diff --git a/views/controls/table/group_table_view.cc b/views/controls/table/group_table_view.cc
index efef1a5..4d34c56 100644
--- a/views/controls/table/group_table_view.cc
+++ b/views/controls/table/group_table_view.cc
@@ -21,10 +21,12 @@ GroupTableView::GroupTableView(GroupTableModel* model,
TableTypes table_type,
bool single_selection,
bool resizable_columns,
- bool autosize_columns)
+ bool autosize_columns,
+ bool draw_group_separators)
: TableView(model, columns, table_type, false, resizable_columns,
autosize_columns),
model_(model),
+ draw_group_separators_(draw_group_separators),
ALLOW_THIS_IN_INITIALIZER_LIST(sync_selection_factory_(this)) {
}
@@ -168,6 +170,9 @@ void GroupTableView::OnSelectedStateChanged() {
// Draws the line separator betweens the groups.
void GroupTableView::PostPaint(int model_row, int column, bool selected,
const gfx::Rect& bounds, HDC hdc) {
+ if (!draw_group_separators_)
+ return;
+
GroupRange group_range;
model_->GetGroupRangeForItem(model_row, &group_range);
diff --git a/views/controls/table/group_table_view.h b/views/controls/table/group_table_view.h
index d4853cb..adf0bac 100644
--- a/views/controls/table/group_table_view.h
+++ b/views/controls/table/group_table_view.h
@@ -37,7 +37,8 @@ class GroupTableView : public TableView {
GroupTableView(GroupTableModel* model,
const std::vector<TableColumn>& columns,
TableTypes table_type, bool single_selection,
- bool resizable_columns, bool autosize_columns);
+ bool resizable_columns, bool autosize_columns,
+ bool draw_group_separators);
virtual ~GroupTableView();
virtual std::string GetClassName() const;
@@ -70,6 +71,9 @@ class GroupTableView : public TableView {
GroupTableModel* model_;
+ // If true, draw separators between groups.
+ bool draw_group_separators_;
+
// A factory to make the selection consistent among groups.
ScopedRunnableMethodFactory<GroupTableView> sync_selection_factory_;
diff --git a/views/controls/table/table_view.cc b/views/controls/table/table_view.cc
index 2eaab2b..cd7541a2 100644
--- a/views/controls/table/table_view.cc
+++ b/views/controls/table/table_view.cc
@@ -1406,11 +1406,15 @@ void TableView::UpdateListViewCache0(int start, int length, bool add) {
LVITEM item = {0};
if (add) {
const bool has_groups = model_->HasGroups();
- item.mask = has_groups ? (LVIF_GROUPID | LVIF_PARAM) : LVIF_PARAM;
for (int i = start; i < start + length; ++i) {
+ item.mask = has_groups ? (LVIF_GROUPID | LVIF_PARAM) : LVIF_PARAM;
item.iItem = i;
if (has_groups)
item.iGroupId = model_->GetGroupID(i);
+ if (model_->ShouldIndent(i)) {
+ item.mask |= LVIF_INDENT;
+ item.iIndent = 1;
+ }
item.lParam = i;
ListView_InsertItem(list_view_, &item);
}