diff options
author | atwilson@chromium.org <atwilson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-15 18:09:52 +0000 |
---|---|---|
committer | atwilson@chromium.org <atwilson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-15 18:09:52 +0000 |
commit | c43207ea2d894f09a4079d4d97ad8591e8267553 (patch) | |
tree | 727703d181dbcdb75c7102e0e34b0bbe93c7d883 | |
parent | a75965d3b1a1ed03ac54aac886d7b44726d7d164 (diff) | |
download | chromium_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.cc | 4 | ||||
-rw-r--r-- | app/table_model.h | 3 | ||||
-rw-r--r-- | chrome/app/generated_resources.grd | 6 | ||||
-rw-r--r-- | chrome/browser/task_manager/task_manager.cc | 58 | ||||
-rw-r--r-- | chrome/browser/task_manager/task_manager.h | 18 | ||||
-rw-r--r-- | chrome/browser/task_manager/task_manager_resource_providers.cc | 15 | ||||
-rw-r--r-- | chrome/browser/task_manager/task_manager_resource_providers.h | 15 | ||||
-rw-r--r-- | chrome/browser/ui/views/hung_renderer_view.cc | 2 | ||||
-rw-r--r-- | chrome/browser/ui/views/task_manager_view.cc | 57 | ||||
-rw-r--r-- | views/controls/table/group_table_view.cc | 7 | ||||
-rw-r--r-- | views/controls/table/group_table_view.h | 6 | ||||
-rw-r--r-- | views/controls/table/table_view.cc | 6 |
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); } |