diff options
author | tfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-23 03:02:57 +0000 |
---|---|---|
committer | tfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-23 03:02:57 +0000 |
commit | 7c51977e3019cda01bb9ecbf774fd04f64d8e80d (patch) | |
tree | b38af0933d736fa335659ddda9709923521439cf /views/controls/tree | |
parent | 203608769c146b687b883f1b1fb1b5a6aff998bf (diff) | |
download | chromium_src-7c51977e3019cda01bb9ecbf774fd04f64d8e80d.zip chromium_src-7c51977e3019cda01bb9ecbf774fd04f64d8e80d.tar.gz chromium_src-7c51977e3019cda01bb9ecbf774fd04f64d8e80d.tar.bz2 |
views: Move table and tree directories to ui/views/controls/.
BUG=104039
R=ben@chromium.org
Review URL: http://codereview.chromium.org/8655001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@111299 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views/controls/tree')
-rw-r--r-- | views/controls/tree/tree_view.cc | 811 | ||||
-rw-r--r-- | views/controls/tree/tree_view.h | 342 |
2 files changed, 0 insertions, 1153 deletions
diff --git a/views/controls/tree/tree_view.cc b/views/controls/tree/tree_view.cc deleted file mode 100644 index 77692b4..0000000 --- a/views/controls/tree/tree_view.cc +++ /dev/null @@ -1,811 +0,0 @@ -// Copyright (c) 2011 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 "views/controls/tree/tree_view.h" - -#include <vector> - -#include "base/i18n/rtl.h" -#include "base/logging.h" -#include "base/stl_util.h" -#include "base/win/win_util.h" -#include "grit/ui_resources.h" -#include "ui/base/accessibility/accessible_view_state.h" -#include "ui/base/keycodes/keyboard_code_conversion_win.h" -#include "ui/base/keycodes/keyboard_codes.h" -#include "ui/base/l10n/l10n_util_win.h" -#include "ui/base/models/accelerator.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/base/win/hwnd_util.h" -#include "ui/gfx/canvas_skia.h" -#include "ui/gfx/canvas_skia_paint.h" -#include "ui/gfx/favicon_size.h" -#include "ui/gfx/icon_util.h" -#include "ui/gfx/point.h" -#include "ui/views/focus/focus_manager.h" -#include "ui/views/widget/widget.h" - -using ui::TreeModel; -using ui::TreeModelNode; - -namespace views { - -TreeView::TreeView() - : tree_view_(NULL), - model_(NULL), - auto_expand_children_(false), - editable_(true), - next_id_(0), - controller_(NULL), - editing_node_(NULL), - root_shown_(true), - lines_at_root_(false), - process_enter_(false), - show_context_menu_only_when_node_selected_(true), - select_on_right_mouse_down_(true), - ALLOW_THIS_IN_INITIALIZER_LIST(wrapper_(this)), - original_handler_(NULL), - drag_enabled_(false), - observer_added_(false), - has_custom_icons_(false), - image_list_(NULL) { -} - -TreeView::~TreeView() { - Cleanup(); -} - -void TreeView::GetAccessibleState(ui::AccessibleViewState* state) { - state->role = ui::AccessibilityTypes::ROLE_OUTLINE; - state->state = ui::AccessibilityTypes::STATE_READONLY; -} - -void TreeView::SetModel(TreeModel* model) { - if (model == model_) - return; - if (model_ && tree_view_) - DeleteRootItems(); - - RemoveObserverFromModel(); - - model_ = model; - if (tree_view_ && model_) { - CreateRootItems(); - AddObserverToModel(); - HIMAGELIST last_image_list = image_list_; - image_list_ = CreateImageList(); - TreeView_SetImageList(tree_view_, image_list_, TVSIL_NORMAL); - if (last_image_list) - ImageList_Destroy(last_image_list); - } -} - -// Sets whether the user can edit the nodes. The default is true. -void TreeView::SetEditable(bool editable) { - if (editable == editable_) - return; - editable_ = editable; - if (!tree_view_) - return; - LONG_PTR style = GetWindowLongPtr(tree_view_, GWL_STYLE); - style &= ~TVS_EDITLABELS; - SetWindowLongPtr(tree_view_, GWL_STYLE, style); -} - -void TreeView::StartEditing(TreeModelNode* node) { - DCHECK(node && tree_view_); - // Cancel the current edit. - CancelEdit(); - // Make sure all ancestors are expanded. - if (model_->GetParent(node)) - Expand(model_->GetParent(node)); - const NodeDetails* details = GetNodeDetails(node); - // Tree needs focus for editing to work. - SetFocus(tree_view_); - // Select the node, else if the user commits the edit the selection reverts. - SetSelectedNode(node); - TreeView_EditLabel(tree_view_, details->tree_item); -} - -void TreeView::CancelEdit() { - DCHECK(tree_view_); - TreeView_EndEditLabelNow(tree_view_, TRUE); -} - -void TreeView::CommitEdit() { - DCHECK(tree_view_); - TreeView_EndEditLabelNow(tree_view_, FALSE); -} - -TreeModelNode* TreeView::GetEditingNode() { - // I couldn't find a way to dynamically query for this, so it is cached. - return editing_node_; -} - -void TreeView::SetSelectedNode(TreeModelNode* node) { - DCHECK(tree_view_); - if (!node) { - TreeView_SelectItem(tree_view_, NULL); - return; - } - if (node != model_->GetRoot()) - Expand(model_->GetParent(node)); - if (!root_shown_ && node == model_->GetRoot()) { - // If the root isn't shown, we can't select it, clear out the selection - // instead. - TreeView_SelectItem(tree_view_, NULL); - } else { - // Select the node and make sure it is visible. - TreeView_SelectItem(tree_view_, GetNodeDetails(node)->tree_item); - } -} - -TreeModelNode* TreeView::GetSelectedNode() { - if (!tree_view_) - return NULL; - HTREEITEM selected_item = TreeView_GetSelection(tree_view_); - if (!selected_item) - return NULL; - NodeDetails* details = GetNodeDetailsByTreeItem(selected_item); - DCHECK(details); - return details->node; -} - -void TreeView::Expand(TreeModelNode* node) { - DCHECK(model_ && node); - if (!root_shown_ && model_->GetRoot() == node) { - // Can only expand the root if it is showing. - return; - } - TreeModelNode* parent = model_->GetParent(node); - if (parent) { - // Make sure all the parents are expanded. - Expand(parent); - } - // And expand this item. - TreeView_Expand(tree_view_, GetNodeDetails(node)->tree_item, TVE_EXPAND); -} - -void TreeView::ExpandAll(TreeModelNode* node) { - DCHECK(node); - // Expand the node. - if (node != model_->GetRoot() || root_shown_) - TreeView_Expand(tree_view_, GetNodeDetails(node)->tree_item, TVE_EXPAND); - // And recursively expand all the children. - for (int i = model_->GetChildCount(node) - 1; i >= 0; --i) { - TreeModelNode* child = model_->GetChild(node, i); - ExpandAll(child); - } -} - -bool TreeView::IsExpanded(TreeModelNode* node) { - if (!tree_view_) - return false; - TreeModelNode* parent = model_->GetParent(node); - if (!parent) - return true; - if (!IsExpanded(parent)) - return false; - NodeDetails* details = GetNodeDetails(node); - return (TreeView_GetItemState(tree_view_, details->tree_item, TVIS_EXPANDED) & - TVIS_EXPANDED) != 0; -} - -void TreeView::SetRootShown(bool root_shown) { - if (root_shown_ == root_shown) - return; - root_shown_ = root_shown; - if (!model_ || !tree_view_) - return; - // Repopulate the tree. - DeleteRootItems(); - CreateRootItems(); -} - -void TreeView::TreeNodesAdded(TreeModel* model, - TreeModelNode* parent, - int start, - int count) { - DCHECK(parent && start >= 0 && count > 0); - if (node_to_details_map_.find(parent) == node_to_details_map_.end() && - (root_shown_ || parent != model_->GetRoot())) { - // User hasn't navigated to this entry yet. Ignore the change. - return; - } - HTREEITEM parent_tree_item = NULL; - if (root_shown_ || parent != model_->GetRoot()) { - const NodeDetails* details = GetNodeDetails(parent); - if (!details->loaded_children) { - if (count == model_->GetChildCount(parent)) { - // Reset the treeviews child count. This triggers the treeview to call - // us back. - TV_ITEM tv_item = {0}; - tv_item.mask = TVIF_CHILDREN; - tv_item.cChildren = count; - tv_item.hItem = details->tree_item; - TreeView_SetItem(tree_view_, &tv_item); - } - - // Ignore the change, we haven't actually created entries in the tree - // for the children. - return; - } - parent_tree_item = details->tree_item; - } - - // The user has expanded this node, add the items to it. - for (int i = 0; i < count; ++i) { - if (i == 0 && start == 0) { - CreateItem(parent_tree_item, TVI_FIRST, model_->GetChild(parent, 0)); - } else { - TreeModelNode* previous_sibling = model_->GetChild(parent, i + start - 1); - CreateItem(parent_tree_item, - GetNodeDetails(previous_sibling)->tree_item, - model_->GetChild(parent, i + start)); - } - } -} - -void TreeView::TreeNodesRemoved(TreeModel* model, - TreeModelNode* parent, - int start, - int count) { - DCHECK(parent && start >= 0 && count > 0); - - HTREEITEM tree_item; - if (!root_shown_ && parent == model->GetRoot()) { - // NOTE: we can't call GetTreeItemForNodeDuringMutation here as in this - // configuration the root has no treeitem. - tree_item = TreeView_GetRoot(tree_view_); - } else { - HTREEITEM parent_tree_item = GetTreeItemForNodeDuringMutation(parent); - if (!parent_tree_item) - return; - - tree_item = TreeView_GetChild(tree_view_, parent_tree_item); - } - - // Find the last item. Windows doesn't offer a convenient way to get the - // TREEITEM at a particular index, so we iterate. - for (int i = 0; i < (start + count - 1); ++i) { - tree_item = TreeView_GetNextSibling(tree_view_, tree_item); - } - - // NOTE: the direction doesn't matter here. I've made it backwards to - // reinforce we're deleting from the end forward. - for (int i = count - 1; i >= 0; --i) { - HTREEITEM previous = (start + i) > 0 ? - TreeView_GetPrevSibling(tree_view_, tree_item) : NULL; - RecursivelyDelete(GetNodeDetailsByTreeItem(tree_item)); - tree_item = previous; - } -} - -void TreeView::TreeNodeChanged(TreeModel* model, TreeModelNode* node) { - if (node_to_details_map_.find(node) == node_to_details_map_.end()) { - // User hasn't navigated to this entry yet. Ignore the change. - return; - } - const NodeDetails* details = GetNodeDetails(node); - TV_ITEM tv_item = {0}; - tv_item.mask = TVIF_TEXT; - tv_item.hItem = details->tree_item; - tv_item.pszText = LPSTR_TEXTCALLBACK; - TreeView_SetItem(tree_view_, &tv_item); -} - -gfx::Point TreeView::GetKeyboardContextMenuLocation() { - int y = height() / 2; - if (GetSelectedNode()) { - RECT bounds; - RECT client_rect; - if (TreeView_GetItemRect(tree_view_, - GetNodeDetails(GetSelectedNode())->tree_item, - &bounds, TRUE) && - GetClientRect(tree_view_, &client_rect) && - bounds.bottom >= 0 && bounds.bottom < client_rect.bottom) { - y = bounds.bottom; - } - } - gfx::Point screen_loc(0, y); - if (base::i18n::IsRTL()) - screen_loc.set_x(width()); - ConvertPointToScreen(this, &screen_loc); - return screen_loc; -} - -HWND TreeView::CreateNativeControl(HWND parent_container) { - int style = WS_CHILD | TVS_HASBUTTONS | TVS_HASLINES | TVS_SHOWSELALWAYS; - if (!drag_enabled_) - style |= TVS_DISABLEDRAGDROP; - if (editable_) - style |= TVS_EDITLABELS; - if (lines_at_root_) - style |= TVS_LINESATROOT; - tree_view_ = ::CreateWindowEx(WS_EX_CLIENTEDGE | GetAdditionalExStyle(), - WC_TREEVIEW, - L"", - style, - 0, 0, width(), height(), - parent_container, NULL, NULL, NULL); - ui::CheckWindowCreated(tree_view_); - SetWindowLongPtr(tree_view_, GWLP_USERDATA, - reinterpret_cast<LONG_PTR>(&wrapper_)); - original_handler_ = ui::SetWindowProc(tree_view_, &TreeWndProc); - l10n_util::AdjustUIFontForWindow(tree_view_); - - if (model_) { - CreateRootItems(); - AddObserverToModel(); - image_list_ = CreateImageList(); - TreeView_SetImageList(tree_view_, image_list_, TVSIL_NORMAL); - } - - // Bug 964884: detach the IME attached to this window. - // We should attach IMEs only when we need to input CJK strings. - ::ImmAssociateContextEx(tree_view_, NULL, 0); - return tree_view_; -} - -LRESULT TreeView::OnNotify(int w_param, LPNMHDR l_param) { - switch (l_param->code) { - case TVN_GETDISPINFO: { - // Windows is requesting more information about an item. - // WARNING: At the time this is called the tree_item of the NodeDetails - // in the maps is NULL. - DCHECK(model_); - NMTVDISPINFO* info = reinterpret_cast<NMTVDISPINFO*>(l_param); - - // WARNING: its possible for Windows to send a TVN_GETDISPINFO message - // after the WM_DESTROY time of the native control. Since the details - // map will be cleaned up on OnDestroy(), don't try to access it in - // this case. - if (!id_to_details_map_.empty()) { - const NodeDetails* details = - GetNodeDetailsByID(static_cast<int>(info->item.lParam)); - if (info->item.mask & TVIF_CHILDREN) - info->item.cChildren = model_->GetChildCount(details->node); - if (info->item.mask & TVIF_TEXT) { - DCHECK(info->item.cchTextMax); - - string16 text = details->node->GetTitle(); - // Adjust the string direction if such adjustment is required. - base::i18n::AdjustStringForLocaleDirection(&text); - - wcsncpy_s(info->item.pszText, info->item.cchTextMax, text.c_str(), - _TRUNCATE); - } - // Instructs windows to cache the values for this node. - info->item.mask |= TVIF_DI_SETITEM; - } else { - if (info->item.mask & TVIF_CHILDREN) - info->item.cChildren = 0; - - if (info->item.mask & TVIF_TEXT) - wcsncpy_s(info->item.pszText, info->item.cchTextMax, L"", _TRUNCATE); - } - - // Return value ignored. - return 0; - } - - case TVN_ITEMEXPANDING: { - // Notification that a node is expanding. If we haven't populated the - // tree view with the contents of the model, we do it here. - DCHECK(model_); - NMTREEVIEW* info = reinterpret_cast<NMTREEVIEW*>(l_param); - NodeDetails* details = - GetNodeDetailsByID(static_cast<int>(info->itemNew.lParam)); - if (!details->loaded_children) { - details->loaded_children = true; - for (int i = 0; i < model_->GetChildCount(details->node); ++i) { - CreateItem(details->tree_item, TVI_LAST, - model_->GetChild(details->node, i)); - if (auto_expand_children_) - Expand(model_->GetChild(details->node, i)); - } - } - // Return FALSE to allow the item to be expanded. - return FALSE; - } - - case TVN_SELCHANGED: - if (controller_) - controller_->OnTreeViewSelectionChanged(this); - break; - - case TVN_BEGINLABELEDIT: { - NMTVDISPINFO* info = reinterpret_cast<NMTVDISPINFO*>(l_param); - NodeDetails* details = - GetNodeDetailsByID(static_cast<int>(info->item.lParam)); - // Return FALSE to allow editing. - if (!controller_ || controller_->CanEdit(this, details->node)) { - editing_node_ = details->node; - return FALSE; - } - return TRUE; - } - - case TVN_ENDLABELEDIT: { - NMTVDISPINFO* info = reinterpret_cast<NMTVDISPINFO*>(l_param); - if (info->item.pszText) { - // User accepted edit. - NodeDetails* details = - GetNodeDetailsByID(static_cast<int>(info->item.lParam)); - model_->SetTitle(details->node, info->item.pszText); - editing_node_ = NULL; - // Return FALSE so that the tree item doesn't change its text (if the - // model changed the value, it should have sent out notification which - // will have updated the value). - return FALSE; - } - editing_node_ = NULL; - // Return value ignored. - return 0; - } - - case TVN_KEYDOWN: - if (controller_) { - NMTVKEYDOWN* key_down_message = - reinterpret_cast<NMTVKEYDOWN*>(l_param); - controller_->OnTreeViewKeyDown( - ui::KeyboardCodeForWindowsKeyCode(key_down_message->wVKey)); - } - break; - - default: - break; - } - return 0; -} - -void TreeView::OnDestroy() { - Cleanup(); -} - -bool TreeView::OnKeyDown(ui::KeyboardCode virtual_key_code) { - if (virtual_key_code == VK_F2) { - if (!GetEditingNode()) { - TreeModelNode* selected_node = GetSelectedNode(); - if (selected_node) - StartEditing(selected_node); - } - return true; - } else if (virtual_key_code == ui::VKEY_RETURN && !process_enter_) { - Widget* widget = GetWidget(); - DCHECK(widget); - ui::Accelerator accelerator(ui::Accelerator(virtual_key_code, - base::win::IsShiftPressed(), - base::win::IsCtrlPressed(), - base::win::IsAltPressed())); - GetFocusManager()->ProcessAccelerator(accelerator); - return true; - } - return false; -} - -void TreeView::OnContextMenu(const POINT& location) { - if (!context_menu_controller()) - return; - - if (location.x == -1 && location.y == -1) { - // Let NativeControl's implementation handle keyboard gesture. - NativeControl::OnContextMenu(location); - return; - } - - if (show_context_menu_only_when_node_selected_) { - if (!GetSelectedNode()) - return; - - // Make sure the mouse is over the selected node. - TVHITTESTINFO hit_info; - gfx::Point local_loc(location); - ConvertPointToView(NULL, this, &local_loc); - hit_info.pt = local_loc.ToPOINT(); - HTREEITEM hit_item = TreeView_HitTest(tree_view_, &hit_info); - if (!hit_item || - GetNodeDetails(GetSelectedNode())->tree_item != hit_item || - (hit_info.flags & (TVHT_ONITEM | TVHT_ONITEMRIGHT | - TVHT_ONITEMINDENT)) == 0) { - return; - } - } - ShowContextMenu(gfx::Point(location), true); -} - -TreeModelNode* TreeView::GetNodeForTreeItem(HTREEITEM tree_item) { - NodeDetails* details = GetNodeDetailsByTreeItem(tree_item); - return details ? details->node : NULL; -} - -HTREEITEM TreeView::GetTreeItemForNode(TreeModelNode* node) { - NodeDetails* details = GetNodeDetails(node); - return details ? details->tree_item : NULL; -} - -void TreeView::Cleanup() { - RemoveObserverFromModel(); - - // Both node_to_details_map_ and node_to_details_map_ have the same value, - // as such only need to delete from one. - STLDeleteContainerPairSecondPointers(id_to_details_map_.begin(), - id_to_details_map_.end()); - id_to_details_map_.clear(); - node_to_details_map_.clear(); - - if (image_list_) { - ImageList_Destroy(image_list_); - image_list_ = NULL; - } -} - -void TreeView::AddObserverToModel() { - if (model_ && !observer_added_) { - model_->AddObserver(this); - observer_added_ = true; - } -} - -void TreeView::RemoveObserverFromModel() { - if (model_ && observer_added_) { - model_->RemoveObserver(this); - observer_added_ = false; - } -} - -void TreeView::DeleteRootItems() { - HTREEITEM root = TreeView_GetRoot(tree_view_); - if (root) { - if (root_shown_) { - RecursivelyDelete(GetNodeDetailsByTreeItem(root)); - } else { - do { - RecursivelyDelete(GetNodeDetailsByTreeItem(root)); - } while ((root = TreeView_GetRoot(tree_view_))); - } - } -} - -void TreeView::CreateRootItems() { - DCHECK(model_); - DCHECK(tree_view_); - TreeModelNode* root = model_->GetRoot(); - if (root_shown_) { - CreateItem(NULL, TVI_LAST, root); - } else { - for (int i = 0; i < model_->GetChildCount(root); ++i) - CreateItem(NULL, TVI_LAST, model_->GetChild(root, i)); - } -} - -void TreeView::CreateItem(HTREEITEM parent_item, - HTREEITEM after, - TreeModelNode* node) { - DCHECK(node); - TVINSERTSTRUCT insert_struct = {0}; - insert_struct.hParent = parent_item; - insert_struct.hInsertAfter = after; - insert_struct.itemex.mask = TVIF_PARAM | TVIF_CHILDREN | TVIF_TEXT | - TVIF_SELECTEDIMAGE | TVIF_IMAGE; - // Call us back for the text. - insert_struct.itemex.pszText = LPSTR_TEXTCALLBACK; - // And the number of children. - insert_struct.itemex.cChildren = I_CHILDRENCALLBACK; - // Set the index of the icons to use. These are relative to the imagelist - // created in CreateImageList. - int icon_index = model_->GetIconIndex(node); - if (icon_index == -1) { - insert_struct.itemex.iImage = 0; - insert_struct.itemex.iSelectedImage = 1; - } else { - // The first two images are the default ones. - insert_struct.itemex.iImage = icon_index + 2; - insert_struct.itemex.iSelectedImage = icon_index + 2; - } - int node_id = next_id_++; - insert_struct.itemex.lParam = node_id; - - // Invoking TreeView_InsertItem triggers OnNotify to be called. As such, - // we set the map entries before adding the item. - NodeDetails* node_details = new NodeDetails(node_id, node); - - DCHECK(node_to_details_map_.count(node) == 0); - DCHECK(id_to_details_map_.count(node_id) == 0); - - node_to_details_map_[node] = node_details; - id_to_details_map_[node_id] = node_details; - - node_details->tree_item = TreeView_InsertItem(tree_view_, &insert_struct); -} - -void TreeView::RecursivelyDelete(NodeDetails* node) { - DCHECK(node); - HTREEITEM item = node->tree_item; - DCHECK(item); - - // Recurse through children. - for (HTREEITEM child = TreeView_GetChild(tree_view_, item); child ;) { - HTREEITEM next = TreeView_GetNextSibling(tree_view_, child); - RecursivelyDelete(GetNodeDetailsByTreeItem(child)); - child = next; - } - - TreeView_DeleteItem(tree_view_, item); - - // finally, it is safe to delete the data for this node. - id_to_details_map_.erase(node->id); - node_to_details_map_.erase(node->node); - delete node; -} - -TreeView::NodeDetails* TreeView::GetNodeDetails(TreeModelNode* node) { - DCHECK(node && - node_to_details_map_.find(node) != node_to_details_map_.end()); - return node_to_details_map_[node]; -} - -// Returns the NodeDetails by identifier (lparam of the HTREEITEM). -TreeView::NodeDetails* TreeView::GetNodeDetailsByID(int id) { - DCHECK(id_to_details_map_.find(id) != id_to_details_map_.end()); - return id_to_details_map_[id]; -} - -TreeView::NodeDetails* TreeView::GetNodeDetailsByTreeItem(HTREEITEM tree_item) { - DCHECK(tree_view_ && tree_item); - TV_ITEM tv_item = {0}; - tv_item.hItem = tree_item; - tv_item.mask = TVIF_PARAM; - if (TreeView_GetItem(tree_view_, &tv_item)) - return GetNodeDetailsByID(static_cast<int>(tv_item.lParam)); - return NULL; -} - -HIMAGELIST TreeView::CreateImageList() { - std::vector<SkBitmap> model_images; - model_->GetIcons(&model_images); - - bool rtl = base::i18n::IsRTL(); - // Creates the default image list used for trees. - SkBitmap* closed_icon = - ResourceBundle::GetSharedInstance().GetBitmapNamed( - (rtl ? IDR_FOLDER_CLOSED_RTL : IDR_FOLDER_CLOSED)); - SkBitmap* opened_icon = - ResourceBundle::GetSharedInstance().GetBitmapNamed( - (rtl ? IDR_FOLDER_OPEN_RTL : IDR_FOLDER_OPEN)); - int width = closed_icon->width(); - int height = closed_icon->height(); - DCHECK(opened_icon->width() == width && opened_icon->height() == height); - HIMAGELIST image_list = - ImageList_Create(width, height, ILC_COLOR32, model_images.size() + 2, - model_images.size() + 2); - if (image_list) { - // NOTE: the order the images are added in effects the selected - // image index when adding items to the tree. If you change the - // order you'll undoubtedly need to update itemex.iSelectedImage - // when the item is added. - HICON h_closed_icon = IconUtil::CreateHICONFromSkBitmap(*closed_icon); - HICON h_opened_icon = IconUtil::CreateHICONFromSkBitmap(*opened_icon); - ImageList_AddIcon(image_list, h_closed_icon); - ImageList_AddIcon(image_list, h_opened_icon); - DestroyIcon(h_closed_icon); - DestroyIcon(h_opened_icon); - for (size_t i = 0; i < model_images.size(); ++i) { - HICON model_icon; - - // Need to resize the provided icons to be the same size as - // IDR_FOLDER_CLOSED if they aren't already. - if (model_images[i].width() != width || - model_images[i].height() != height) { - gfx::CanvasSkia canvas(width, height, false); - // Make the background completely transparent. - canvas.sk_canvas()->drawColor(SK_ColorBLACK, SkXfermode::kClear_Mode); - - // Draw our icons into this canvas. - int height_offset = (height - model_images[i].height()) / 2; - int width_offset = (width - model_images[i].width()) / 2; - canvas.DrawBitmapInt(model_images[i], width_offset, height_offset); - model_icon = IconUtil::CreateHICONFromSkBitmap(canvas.ExtractBitmap()); - } else { - model_icon = IconUtil::CreateHICONFromSkBitmap(model_images[i]); - } - ImageList_AddIcon(image_list, model_icon); - DestroyIcon(model_icon); - } - } - return image_list; -} - -HTREEITEM TreeView::GetTreeItemForNodeDuringMutation(TreeModelNode* node) { - if (node_to_details_map_.find(node) == node_to_details_map_.end()) { - // User hasn't navigated to this entry yet. Ignore the change. - return NULL; - } - if (!root_shown_ || node != model_->GetRoot()) { - const NodeDetails* details = GetNodeDetails(node); - if (!details->loaded_children) - return NULL; - return details->tree_item; - } - return TreeView_GetRoot(tree_view_); -} - -LRESULT CALLBACK TreeView::TreeWndProc(HWND window, - UINT message, - WPARAM w_param, - LPARAM l_param) { - TreeViewWrapper* wrapper = reinterpret_cast<TreeViewWrapper*>( - GetWindowLongPtr(window, GWLP_USERDATA)); - DCHECK(wrapper); - TreeView* tree = wrapper->tree_view; - - // We handle the messages WM_ERASEBKGND and WM_PAINT such that we paint into - // a DIB first and then perform a BitBlt from the DIB into the underlying - // window's DC. This double buffering code prevents the tree view from - // flickering during resize. - switch (message) { - case WM_ERASEBKGND: - return 1; - - case WM_PAINT: { - gfx::CanvasSkiaPaint canvas(window); - if (canvas.isEmpty()) - return 0; - - HDC dc = skia::BeginPlatformPaint(canvas.sk_canvas()); - if (base::i18n::IsRTL()) { - // gfx::CanvasSkia ends up configuring the DC with a mode of - // GM_ADVANCED. For some reason a graphics mode of ADVANCED triggers - // all the text to be mirrored when RTL. Set the mode back to COMPATIBLE - // and explicitly set the layout. Additionally SetWorldTransform and - // COMPATIBLE don't play nicely together. We need to use - // SetViewportOrgEx when using a mode of COMPATIBLE. - // - // Reset the transform to the identify transform. Even though - // SetWorldTransform and COMPATIBLE don't play nicely, bits of the - // transform still carry over when we set the mode. - XFORM xform = {0}; - xform.eM11 = xform.eM22 = 1; - SetWorldTransform(dc, &xform); - - // Set the mode and layout. - SetGraphicsMode(dc, GM_COMPATIBLE); - SetLayout(dc, LAYOUT_RTL); - - // Transform the viewport such that the origin of the dc is that of - // the dirty region. This way when we invoke WM_PRINTCLIENT tree-view - // draws the dirty region at the origin of the DC so that when we - // copy the bits everything lines up nicely. Without this we end up - // copying the upper-left corner to the redraw region. - SetViewportOrgEx(dc, -canvas.paintStruct().rcPaint.left, - -canvas.paintStruct().rcPaint.top, NULL); - } - SendMessage(window, WM_PRINTCLIENT, reinterpret_cast<WPARAM>(dc), 0); - if (base::i18n::IsRTL()) { - // Reset the origin of the dc back to 0. This way when we copy the bits - // over we copy the right bits. - SetViewportOrgEx(dc, 0, 0, NULL); - } - skia::EndPlatformPaint(canvas.sk_canvas()); - return 0; - } - - case WM_RBUTTONDOWN: - if (tree->select_on_right_mouse_down_) { - TVHITTESTINFO hit_info; - hit_info.pt = gfx::Point(l_param).ToPOINT(); - HTREEITEM hit_item = TreeView_HitTest(window, &hit_info); - if (hit_item && (hit_info.flags & (TVHT_ONITEM | TVHT_ONITEMRIGHT | - TVHT_ONITEMINDENT)) != 0) - TreeView_SelectItem(tree->tree_view_, hit_item); - } - // Fall through and let the default handler process as well. - break; - } - WNDPROC handler = tree->original_handler_; - DCHECK(handler); - return CallWindowProc(handler, window, message, w_param, l_param); -} - -} // namespace views diff --git a/views/controls/tree/tree_view.h b/views/controls/tree/tree_view.h deleted file mode 100644 index dac2804..0000000 --- a/views/controls/tree/tree_view.h +++ /dev/null @@ -1,342 +0,0 @@ -// Copyright (c) 2011 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 VIEWS_CONTROLS_TREE_TREE_VIEW_H_ -#define VIEWS_CONTROLS_TREE_TREE_VIEW_H_ -#pragma once - -#include <windows.h> -#include <commctrl.h> - -#include <map> - -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "ui/base/keycodes/keyboard_codes.h" -#include "ui/base/models/tree_model.h" -#include "views/controls/native_control.h" - -namespace views { - -class TreeView; - -// TreeViewController --------------------------------------------------------- - -// Controller for the treeview. -class TreeViewController { - public: - // Notification that the selection of the tree view has changed. Use - // GetSelectedNode to find the current selection. - virtual void OnTreeViewSelectionChanged(TreeView* tree_view) = 0; - - // Returns true if the node can be edited. This is only used if the - // TreeView is editable. - virtual bool CanEdit(TreeView* tree_view, ui::TreeModelNode* node) { - return true; - } - - // Invoked when a key is pressed on the tree view. - virtual void OnTreeViewKeyDown(ui::KeyboardCode keycode) {} -}; - -// TreeView ------------------------------------------------------------------- - -// TreeView displays hierarchical data as returned from a TreeModel. The user -// can expand, collapse and edit the items. A Controller may be attached to -// receive notification of selection changes and restrict editing. -class VIEWS_EXPORT TreeView : public NativeControl, ui::TreeModelObserver { - public: - TreeView(); - virtual ~TreeView(); - - // Is dragging enabled? The default is false. - void set_drag_enabled(bool drag_enabled) { drag_enabled_ = drag_enabled; } - bool drag_enabled() const { return drag_enabled_; } - - // Sets the model. TreeView does not take ownership of the model. - void SetModel(ui::TreeModel* model); - ui::TreeModel* model() const { return model_; } - - // Sets whether to automatically expand children when a parent node is - // expanded. The default is false. If true, when a node in the tree is - // expanded for the first time, its children are also automatically expanded. - // If a node is subsequently collapsed and expanded again, the children - // will not be automatically expanded. - void set_auto_expand_children(bool auto_expand_children) { - auto_expand_children_ = auto_expand_children; - } - - // Sets whether the user can edit the nodes. The default is true. If true, - // the Controller is queried to determine if a particular node can be edited. - void SetEditable(bool editable); - - // Sets whether lines are drawn from the root node to child nodes (and - // whether plus boxes show up next to the root node.) The default is false. - // If root_shown_ is false, the children of the root act as the roots in the - // native control, and so this setting takes effect for them. - void set_lines_at_root(bool lines_at_root) { - lines_at_root_ = lines_at_root; - } - - // Overridden from View: - virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE; - - // Edits the specified node. This cancels the current edit and expands - // all parents of node. - void StartEditing(ui::TreeModelNode* node); - - // Cancels the current edit. Does nothing if not editing. - void CancelEdit(); - - // Commits the current edit. Does nothing if not editing. - void CommitEdit(); - - // If the user is editing a node, it is returned. If the user is not - // editing a node, NULL is returned. - ui::TreeModelNode* GetEditingNode(); - - // Selects the specified node. This expands all the parents of node. - void SetSelectedNode(ui::TreeModelNode* node); - - // Returns the selected node, or NULL if nothing is selected. - ui::TreeModelNode* GetSelectedNode(); - - // Make sure node and all its parents are expanded. - void Expand(ui::TreeModelNode* node); - - // Invoked from ExpandAll(). Expands the supplied node and recursively - // invokes itself with all children. - void ExpandAll(ui::TreeModelNode* node); - - // Returns true if the specified node is expanded. - bool IsExpanded(ui::TreeModelNode* node); - - // Sets whether the root is shown. If true, the root node of the tree is - // shown, if false only the children of the root are shown. The default is - // true. - void SetRootShown(bool root_visible); - - // Begin TreeModelObserver implementation. - // These methods shouldn't be called directly. The model is responsible for - // firing them. - virtual void TreeNodesAdded(ui::TreeModel* model, - ui::TreeModelNode* parent, - int start, - int count) OVERRIDE; - virtual void TreeNodesRemoved(ui::TreeModel* model, - ui::TreeModelNode* parent, - int start, - int count) OVERRIDE; - virtual void TreeNodeChanged(ui::TreeModel* model, - ui::TreeModelNode* node) OVERRIDE; - // End TreeModelObserver implementation. - - // Sets the controller, which may be null. TreeView does not take ownership - // of the controller. - void SetController(TreeViewController* controller) { - controller_ = controller; - } - - // Sets whether enter is processed when not editing. If true, enter will - // expand/collapse the node. If false, enter is passed to the focus manager - // so that an enter accelerator can be enabled. The default is false. - // - // NOTE: Changing this has no effect after the hwnd has been created. - void SetProcessesEnter(bool process_enter) { - process_enter_ = process_enter; - } - bool GetProcessedEnter() { return process_enter_; } - - // Sets when the ContextMenuController is notified. If true, the - // ContextMenuController is only notified when a node is selected and the - // mouse is over a node. The default is true. - void SetShowContextMenuOnlyWhenNodeSelected(bool value) { - show_context_menu_only_when_node_selected_ = value; - } - bool GetShowContextMenuOnlyWhenNodeSelected() { - return show_context_menu_only_when_node_selected_; - } - - // If true, a right click selects the node under the mouse. The default - // is true. - void SetSelectOnRightMouseDown(bool value) { - select_on_right_mouse_down_ = value; - } - bool GetSelectOnRightMouseDown() { return select_on_right_mouse_down_; } - - protected: - // Overriden to return a location based on the selected node. - virtual gfx::Point GetKeyboardContextMenuLocation(); - - // Creates and configures the tree_view. - virtual HWND CreateNativeControl(HWND parent_container); - - // Invoked when the native control sends a WM_NOTIFY message to its parent. - // Handles a variety of potential TreeView messages. - virtual LRESULT OnNotify(int w_param, LPNMHDR l_param); - - // Invoked when the native control send a WM_DESTROY message to its parent. - virtual void OnDestroy(); - - // We pay attention to key down for two reasons: to circumvent VK_ENTER from - // toggling the expaned state when processes_enter_ is false, and to have F2 - // start editting. - virtual bool OnKeyDown(ui::KeyboardCode virtual_key_code); - - virtual void OnContextMenu(const POINT& location); - - // Returns the TreeModelNode for |tree_item|. - ui::TreeModelNode* GetNodeForTreeItem(HTREEITEM tree_item); - - // Returns the tree item for |node|. - HTREEITEM GetTreeItemForNode(ui::TreeModelNode* node); - - private: - // See notes in TableView::TableViewWrapper for why this is needed. - struct TreeViewWrapper { - explicit TreeViewWrapper(TreeView* view) : tree_view(view) { } - TreeView* tree_view; - }; - - // Internally used to track the state of nodes. NodeDetails are lazily created - // as the user expands nodes. - struct NodeDetails { - NodeDetails(int id, ui::TreeModelNode* node) - : id(id), node(node), tree_item(NULL), loaded_children(false) {} - - // Unique identifier for the node. This corresponds to the lParam of - // the tree item. - const int id; - - // The node from the model. - ui::TreeModelNode* node; - - // From the native TreeView. - // - // This should be treated as const, but can't due to timing in creating the - // entry. - HTREEITEM tree_item; - - // Whether the children have been loaded. - bool loaded_children; - }; - - // Cleanup all resources used by treeview. - void Cleanup(); - - // Make sure the tree view is observing the tree model. - void AddObserverToModel(); - - // Make sure the tree view is no longer observing the tree model. - void RemoveObserverFromModel(); - - // Deletes the root items from the treeview. This is used when the model - // changes. - void DeleteRootItems(); - - // Creates the root items in the treeview from the model. This is used when - // the model changes. - void CreateRootItems(); - - // Creates and adds an item to the treeview. parent_item identifies the - // parent and is null for root items. after dictates where among the - // children of parent_item the item is to be created. node is the node from - // the model. - void CreateItem(HTREEITEM parent_item, HTREEITEM after, - ui::TreeModelNode* node); - - // Removes entries from the map for item. This method will also - // remove the items from the TreeView because the process of - // deleting an item will send an TVN_GETDISPINFO message, consulting - // our internal map data. - void RecursivelyDelete(NodeDetails* node); - - // Returns the NodeDetails by node from the model. - NodeDetails* GetNodeDetails(ui::TreeModelNode* node); - - // Returns the NodeDetails by identifier (lparam of the HTREEITEM). - NodeDetails* GetNodeDetailsByID(int id); - - // Returns the NodeDetails by HTREEITEM. - NodeDetails* GetNodeDetailsByTreeItem(HTREEITEM tree_item); - - // Creates the image list to use for the tree. - HIMAGELIST CreateImageList(); - - // Returns the HTREEITEM for |node|. This is intended to be called when a - // model mutation event occur with |node| as the parent. This returns null - // if the user has never expanded |node| or all of its parents. - HTREEITEM GetTreeItemForNodeDuringMutation(ui::TreeModelNode* node); - - // The window function installed on the treeview. - static LRESULT CALLBACK TreeWndProc(HWND window, - UINT message, - WPARAM w_param, - LPARAM l_param); - - // Handle to the tree window. - HWND tree_view_; - - // The model, may be null. - ui::TreeModel* model_; - - // Maps from id to NodeDetails. - std::map<int, NodeDetails*> id_to_details_map_; - - // Maps from model entry to NodeDetails. - std::map<ui::TreeModelNode*, NodeDetails*> node_to_details_map_; - - // Whether to automatically expand children when a parent node is expanded. - bool auto_expand_children_; - - // Whether the user can edit the items. - bool editable_; - - // Next id to create. Any time an item is added this is incremented by one. - int next_id_; - - // The controller. - TreeViewController* controller_; - - // Node being edited. If null, not editing. - ui::TreeModelNode* editing_node_; - - // Whether or not the root is shown in the tree. - bool root_shown_; - - // Whether lines are drawn from the root to the children. - bool lines_at_root_; - - // Whether enter should be processed by the tree when not editing. - bool process_enter_; - - // Whether we notify context menu controller only when mouse is over node - // and node is selected. - bool show_context_menu_only_when_node_selected_; - - // Whether the selection is changed on right mouse down. - bool select_on_right_mouse_down_; - - // A wrapper around 'this', used for subclassing the TreeView control. - TreeViewWrapper wrapper_; - - // Original handler installed on the TreeView. - WNDPROC original_handler_; - - bool drag_enabled_; - - // Has an observer been added to the model? - bool observer_added_; - - // Did the model return a non-empty set of icons from GetIcons? - bool has_custom_icons_; - - HIMAGELIST image_list_; - - DISALLOW_COPY_AND_ASSIGN(TreeView); -}; - -} // namespace views - -#endif // VIEWS_CONTROLS_TREE_TREE_VIEW_H_ |