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