blob: 16f51fd20ae054a285f4fe89d02c064d4688814d [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.view.menu;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
/**
* Base class for MenuPresenters that have a consistent container view and item
* views. Behaves similarly to an AdapterView in that existing item views will
* be reused if possible when items change.
*/
public abstract class BaseMenuPresenter implements MenuPresenter {
protected Context mContext;
protected MenuBuilder mMenu;
protected LayoutInflater mInflater;
private Callback mCallback;
private int mMenuLayoutRes;
private int mItemLayoutRes;
protected MenuView mMenuView;
/**
* Construct a new BaseMenuPresenter.
*
* @param menuLayoutRes Layout resource ID for the menu container view
* @param itemLayoutRes Layout resource ID for a single item view
*/
public BaseMenuPresenter(int menuLayoutRes, int itemLayoutRes) {
mMenuLayoutRes = menuLayoutRes;
mItemLayoutRes = itemLayoutRes;
}
@Override
public void initForMenu(Context context, MenuBuilder menu) {
mContext = context;
mInflater = LayoutInflater.from(mContext);
mMenu = menu;
}
@Override
public MenuView getMenuView(ViewGroup root) {
if (mMenuView == null) {
mMenuView = (MenuView) mInflater.inflate(mMenuLayoutRes, root, false);
mMenuView.initialize(mMenu);
updateMenuView(true);
}
return mMenuView;
}
/**
* Reuses item views when it can
*/
public void updateMenuView(boolean cleared) {
mMenu.flagActionItems();
ArrayList<MenuItemImpl> visibleItems = mMenu.getVisibleItems();
final int itemCount = visibleItems.size();
final ViewGroup parent = (ViewGroup) mMenuView;
int childIndex = 0;
for (int i = 0; i < itemCount; i++) {
MenuItemImpl item = visibleItems.get(i);
if (shouldIncludeItem(childIndex, item)) {
final View convertView = parent.getChildAt(childIndex);
final View itemView = getItemView(item, convertView, parent);
if (itemView != convertView) {
addItemView(itemView, childIndex);
}
childIndex++;
}
}
// Remove leftover views.
while (childIndex < parent.getChildCount()) {
if (!filterLeftoverView(parent, childIndex)) {
childIndex++;
}
}
}
/**
* Add an item view at the given index.
*
* @param itemView View to add
* @param childIndex Index within the parent to insert at
*/
protected void addItemView(View itemView, int childIndex) {
final ViewGroup currentParent = (ViewGroup) itemView.getParent();
if (currentParent != null) {
currentParent.removeView(itemView);
}
((ViewGroup) mMenuView).addView(itemView, childIndex);
}
/**
* Filter the child view at index and remove it if appropriate.
* @param parent Parent to filter from
* @param childIndex Index to filter
* @return true if the child view at index was removed
*/
protected boolean filterLeftoverView(ViewGroup parent, int childIndex) {
parent.removeViewAt(childIndex);
return true;
}
public void setCallback(Callback cb) {
mCallback = cb;
}
/**
* Create a new item view that can be re-bound to other item data later.
*
* @return The new item view
*/
public MenuView.ItemView createItemView(ViewGroup parent) {
return (MenuView.ItemView) mInflater.inflate(mItemLayoutRes, parent, false);
}
/**
* Prepare an item view for use. See AdapterView for the basic idea at work here.
* This may require creating a new item view, but well-behaved implementations will
* re-use the view passed as convertView if present. The returned view will be populated
* with data from the item parameter.
*
* @param item Item to present
* @param convertView Existing view to reuse
* @param parent Intended parent view - use for inflation.
* @return View that presents the requested menu item
*/
public View getItemView(MenuItemImpl item, View convertView, ViewGroup parent) {
MenuView.ItemView itemView;
if (convertView instanceof MenuView.ItemView) {
itemView = (MenuView.ItemView) convertView;
} else {
itemView = createItemView(parent);
}
bindItemView(item, itemView);
return (View) itemView;
}
/**
* Bind item data to an existing item view.
*
* @param item Item to bind
* @param itemView View to populate with item data
*/
public abstract void bindItemView(MenuItemImpl item, MenuView.ItemView itemView);
/**
* Filter item by child index and item data.
*
* @param childIndex Indended presentation index of this item
* @param item Item to present
* @return true if this item should be included in this menu presentation; false otherwise
*/
public boolean shouldIncludeItem(int childIndex, MenuItemImpl item) {
return true;
}
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
if (mCallback != null) {
mCallback.onCloseMenu(menu, allMenusAreClosing);
}
}
public boolean onSubMenuSelected(SubMenuBuilder menu) {
if (mCallback != null) {
return mCallback.onOpenSubMenu(menu);
}
return false;
}
public boolean flagActionItems() {
return false;
}
}