6da26f2ae78821135d7c5da95f6cad1b972f394e
[pub/Android/ownCloud.git] / actionbarsherlock / src / com / actionbarsherlock / internal / view / menu / BaseMenuPresenter.java
1 /*
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
17 package com.actionbarsherlock.internal.view.menu;
18
19 import java.util.ArrayList;
20 import android.content.Context;
21 import android.os.Build;
22 import android.view.LayoutInflater;
23 import android.view.View;
24 import android.view.ViewGroup;
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 */
31 public abstract class BaseMenuPresenter implements MenuPresenter {
32 private static final boolean IS_HONEYCOMB = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
33
34 protected Context mSystemContext;
35 protected Context mContext;
36 protected MenuBuilder mMenu;
37 protected LayoutInflater mSystemInflater;
38 protected LayoutInflater mInflater;
39 private Callback mCallback;
40
41 private int mMenuLayoutRes;
42 private int mItemLayoutRes;
43
44 protected MenuView mMenuView;
45
46 private int mId;
47
48 /**
49 * Construct a new BaseMenuPresenter.
50 *
51 * @param context Context for generating system-supplied views
52 * @param menuLayoutRes Layout resource ID for the menu container view
53 * @param itemLayoutRes Layout resource ID for a single item view
54 */
55 public BaseMenuPresenter(Context context, int menuLayoutRes, int itemLayoutRes) {
56 mSystemContext = context;
57 mSystemInflater = LayoutInflater.from(context);
58 mMenuLayoutRes = menuLayoutRes;
59 mItemLayoutRes = itemLayoutRes;
60 }
61
62 @Override
63 public void initForMenu(Context context, MenuBuilder menu) {
64 mContext = context;
65 mInflater = LayoutInflater.from(mContext);
66 mMenu = menu;
67 }
68
69 @Override
70 public MenuView getMenuView(ViewGroup root) {
71 if (mMenuView == null) {
72 mMenuView = (MenuView) mSystemInflater.inflate(mMenuLayoutRes, root, false);
73 mMenuView.initialize(mMenu);
74 updateMenuView(true);
75 }
76
77 return mMenuView;
78 }
79
80 /**
81 * Reuses item views when it can
82 */
83 public void updateMenuView(boolean cleared) {
84 final ViewGroup parent = (ViewGroup) mMenuView;
85 if (parent == null) return;
86
87 int childIndex = 0;
88 if (mMenu != null) {
89 mMenu.flagActionItems();
90 ArrayList<MenuItemImpl> visibleItems = mMenu.getVisibleItems();
91 final int itemCount = visibleItems.size();
92 for (int i = 0; i < itemCount; i++) {
93 MenuItemImpl item = visibleItems.get(i);
94 if (shouldIncludeItem(childIndex, item)) {
95 final View convertView = parent.getChildAt(childIndex);
96 final MenuItemImpl oldItem = convertView instanceof MenuView.ItemView ?
97 ((MenuView.ItemView) convertView).getItemData() : null;
98 final View itemView = getItemView(item, convertView, parent);
99 if (item != oldItem) {
100 // Don't let old states linger with new data.
101 itemView.setPressed(false);
102 if (IS_HONEYCOMB) itemView.jumpDrawablesToCurrentState();
103 }
104 if (itemView != convertView) {
105 addItemView(itemView, childIndex);
106 }
107 childIndex++;
108 }
109 }
110 }
111
112 // Remove leftover views.
113 while (childIndex < parent.getChildCount()) {
114 if (!filterLeftoverView(parent, childIndex)) {
115 childIndex++;
116 }
117 }
118 }
119
120 /**
121 * Add an item view at the given index.
122 *
123 * @param itemView View to add
124 * @param childIndex Index within the parent to insert at
125 */
126 protected void addItemView(View itemView, int childIndex) {
127 final ViewGroup currentParent = (ViewGroup) itemView.getParent();
128 if (currentParent != null) {
129 currentParent.removeView(itemView);
130 }
131 ((ViewGroup) mMenuView).addView(itemView, childIndex);
132 }
133
134 /**
135 * Filter the child view at index and remove it if appropriate.
136 * @param parent Parent to filter from
137 * @param childIndex Index to filter
138 * @return true if the child view at index was removed
139 */
140 protected boolean filterLeftoverView(ViewGroup parent, int childIndex) {
141 parent.removeViewAt(childIndex);
142 return true;
143 }
144
145 public void setCallback(Callback cb) {
146 mCallback = cb;
147 }
148
149 /**
150 * Create a new item view that can be re-bound to other item data later.
151 *
152 * @return The new item view
153 */
154 public MenuView.ItemView createItemView(ViewGroup parent) {
155 return (MenuView.ItemView) mSystemInflater.inflate(mItemLayoutRes, parent, false);
156 }
157
158 /**
159 * Prepare an item view for use. See AdapterView for the basic idea at work here.
160 * This may require creating a new item view, but well-behaved implementations will
161 * re-use the view passed as convertView if present. The returned view will be populated
162 * with data from the item parameter.
163 *
164 * @param item Item to present
165 * @param convertView Existing view to reuse
166 * @param parent Intended parent view - use for inflation.
167 * @return View that presents the requested menu item
168 */
169 public View getItemView(MenuItemImpl item, View convertView, ViewGroup parent) {
170 MenuView.ItemView itemView;
171 if (convertView instanceof MenuView.ItemView) {
172 itemView = (MenuView.ItemView) convertView;
173 } else {
174 itemView = createItemView(parent);
175 }
176 bindItemView(item, itemView);
177 return (View) itemView;
178 }
179
180 /**
181 * Bind item data to an existing item view.
182 *
183 * @param item Item to bind
184 * @param itemView View to populate with item data
185 */
186 public abstract void bindItemView(MenuItemImpl item, MenuView.ItemView itemView);
187
188 /**
189 * Filter item by child index and item data.
190 *
191 * @param childIndex Indended presentation index of this item
192 * @param item Item to present
193 * @return true if this item should be included in this menu presentation; false otherwise
194 */
195 public boolean shouldIncludeItem(int childIndex, MenuItemImpl item) {
196 return true;
197 }
198
199 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
200 if (mCallback != null) {
201 mCallback.onCloseMenu(menu, allMenusAreClosing);
202 }
203 }
204
205 public boolean onSubMenuSelected(SubMenuBuilder menu) {
206 if (mCallback != null) {
207 return mCallback.onOpenSubMenu(menu);
208 }
209 return false;
210 }
211
212 public boolean flagActionItems() {
213 return false;
214 }
215
216 public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
217 return false;
218 }
219
220 public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
221 return false;
222 }
223
224 public int getId() {
225 return mId;
226 }
227
228 public void setId(int id) {
229 mId = id;
230 }
231 }