blob: 16f51fd20ae054a285f4fe89d02c064d4688814d [file] [log] [blame]
Adam Powell696cba52011-03-29 10:38:16 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.view.menu;
18
19import android.content.Context;
20import android.view.LayoutInflater;
21import android.view.View;
22import android.view.ViewGroup;
23
24import java.util.ArrayList;
25
26/**
27 * Base class for MenuPresenters that have a consistent container view and item
28 * views. Behaves similarly to an AdapterView in that existing item views will
29 * be reused if possible when items change.
30 */
31public abstract class BaseMenuPresenter implements MenuPresenter {
32 protected Context mContext;
33 protected MenuBuilder mMenu;
34 protected LayoutInflater mInflater;
35 private Callback mCallback;
36
37 private int mMenuLayoutRes;
38 private int mItemLayoutRes;
39
40 protected MenuView mMenuView;
41
42 /**
43 * Construct a new BaseMenuPresenter.
44 *
45 * @param menuLayoutRes Layout resource ID for the menu container view
46 * @param itemLayoutRes Layout resource ID for a single item view
47 */
48 public BaseMenuPresenter(int menuLayoutRes, int itemLayoutRes) {
49 mMenuLayoutRes = menuLayoutRes;
50 mItemLayoutRes = itemLayoutRes;
51 }
52
53 @Override
54 public void initForMenu(Context context, MenuBuilder menu) {
55 mContext = context;
56 mInflater = LayoutInflater.from(mContext);
57 mMenu = menu;
58 }
59
60 @Override
61 public MenuView getMenuView(ViewGroup root) {
62 if (mMenuView == null) {
63 mMenuView = (MenuView) mInflater.inflate(mMenuLayoutRes, root, false);
64 mMenuView.initialize(mMenu);
65 updateMenuView(true);
66 }
67
68 return mMenuView;
69 }
70
71 /**
72 * Reuses item views when it can
73 */
74 public void updateMenuView(boolean cleared) {
75 mMenu.flagActionItems();
76 ArrayList<MenuItemImpl> visibleItems = mMenu.getVisibleItems();
77 final int itemCount = visibleItems.size();
78 final ViewGroup parent = (ViewGroup) mMenuView;
79 int childIndex = 0;
80 for (int i = 0; i < itemCount; i++) {
81 MenuItemImpl item = visibleItems.get(i);
82 if (shouldIncludeItem(childIndex, item)) {
83 final View convertView = parent.getChildAt(childIndex);
84 final View itemView = getItemView(item, convertView, parent);
85 if (itemView != convertView) {
86 addItemView(itemView, childIndex);
87 }
88 childIndex++;
89 }
90 }
91
92 // Remove leftover views.
93 while (childIndex < parent.getChildCount()) {
94 if (!filterLeftoverView(parent, childIndex)) {
95 childIndex++;
96 }
97 }
98 }
99
100 /**
101 * Add an item view at the given index.
102 *
103 * @param itemView View to add
104 * @param childIndex Index within the parent to insert at
105 */
106 protected void addItemView(View itemView, int childIndex) {
Adam Powell45c515b2011-04-21 18:50:20 -0700107 final ViewGroup currentParent = (ViewGroup) itemView.getParent();
108 if (currentParent != null) {
109 currentParent.removeView(itemView);
110 }
Adam Powell696cba52011-03-29 10:38:16 -0700111 ((ViewGroup) mMenuView).addView(itemView, childIndex);
112 }
113
114 /**
115 * Filter the child view at index and remove it if appropriate.
116 * @param parent Parent to filter from
117 * @param childIndex Index to filter
118 * @return true if the child view at index was removed
119 */
120 protected boolean filterLeftoverView(ViewGroup parent, int childIndex) {
121 parent.removeViewAt(childIndex);
122 return true;
123 }
124
125 public void setCallback(Callback cb) {
126 mCallback = cb;
127 }
128
129 /**
130 * Create a new item view that can be re-bound to other item data later.
131 *
132 * @return The new item view
133 */
134 public MenuView.ItemView createItemView(ViewGroup parent) {
135 return (MenuView.ItemView) mInflater.inflate(mItemLayoutRes, parent, false);
136 }
137
138 /**
139 * Prepare an item view for use. See AdapterView for the basic idea at work here.
140 * This may require creating a new item view, but well-behaved implementations will
141 * re-use the view passed as convertView if present. The returned view will be populated
142 * with data from the item parameter.
143 *
144 * @param item Item to present
145 * @param convertView Existing view to reuse
146 * @param parent Intended parent view - use for inflation.
147 * @return View that presents the requested menu item
148 */
149 public View getItemView(MenuItemImpl item, View convertView, ViewGroup parent) {
150 MenuView.ItemView itemView;
151 if (convertView instanceof MenuView.ItemView) {
152 itemView = (MenuView.ItemView) convertView;
153 } else {
154 itemView = createItemView(parent);
155 }
156 bindItemView(item, itemView);
157 return (View) itemView;
158 }
159
160 /**
161 * Bind item data to an existing item view.
162 *
163 * @param item Item to bind
164 * @param itemView View to populate with item data
165 */
166 public abstract void bindItemView(MenuItemImpl item, MenuView.ItemView itemView);
167
168 /**
169 * Filter item by child index and item data.
170 *
171 * @param childIndex Indended presentation index of this item
172 * @param item Item to present
173 * @return true if this item should be included in this menu presentation; false otherwise
174 */
175 public boolean shouldIncludeItem(int childIndex, MenuItemImpl item) {
176 return true;
177 }
178
179 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
180 if (mCallback != null) {
181 mCallback.onCloseMenu(menu, allMenusAreClosing);
182 }
183 }
184
185 public boolean onSubMenuSelected(SubMenuBuilder menu) {
186 if (mCallback != null) {
187 return mCallback.onOpenSubMenu(menu);
188 }
189 return false;
190 }
191
192 public boolean flagActionItems() {
193 return false;
194 }
195}