[go: nahoru, domu]

1/*
2 * Copyright (C) 2013 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 android.support.v7.view.menu;
18
19import android.content.Context;
20import android.os.Bundle;
21import android.os.Parcelable;
22import android.support.v7.appcompat.R;
23import android.util.SparseArray;
24import android.view.ContextThemeWrapper;
25import android.view.LayoutInflater;
26import android.view.View;
27import android.view.ViewGroup;
28import android.widget.AdapterView;
29import android.widget.BaseAdapter;
30import android.widget.ListAdapter;
31
32import java.util.ArrayList;
33
34/**
35 * MenuPresenter for list-style menus.
36 *
37 * @hide
38 */
39public class ListMenuPresenter implements MenuPresenter, AdapterView.OnItemClickListener {
40    private static final String TAG = "ListMenuPresenter";
41
42    Context mContext;
43    LayoutInflater mInflater;
44    MenuBuilder mMenu;
45
46    ExpandedMenuView mMenuView;
47
48    private int mItemIndexOffset;
49    int mThemeRes;
50    int mItemLayoutRes;
51
52    private Callback mCallback;
53    MenuAdapter mAdapter;
54
55    private int mId;
56
57    public static final String VIEWS_TAG = "android:menu:list";
58
59    /**
60     * Construct a new ListMenuPresenter.
61     * @param context Context to use for theming. This will supersede the context provided
62     *                to initForMenu when this presenter is added.
63     * @param itemLayoutRes Layout resource for individual item views.
64     */
65    public ListMenuPresenter(Context context, int itemLayoutRes) {
66        this(itemLayoutRes, 0);
67        mContext = context;
68        mInflater = LayoutInflater.from(mContext);
69    }
70
71    /**
72     * Construct a new ListMenuPresenter.
73     * @param itemLayoutRes Layout resource for individual item views.
74     * @param themeRes Resource ID of a theme to use for views.
75     */
76    public ListMenuPresenter(int itemLayoutRes, int themeRes) {
77        mItemLayoutRes = itemLayoutRes;
78        mThemeRes = themeRes;
79    }
80
81    @Override
82    public void initForMenu(Context context, MenuBuilder menu) {
83        if (mThemeRes != 0) {
84            mContext = new ContextThemeWrapper(context, mThemeRes);
85            mInflater = LayoutInflater.from(mContext);
86        } else if (mContext != null) {
87            mContext = context;
88            if (mInflater == null) {
89                mInflater = LayoutInflater.from(mContext);
90            }
91        }
92        mMenu = menu;
93        if (mAdapter != null) {
94            mAdapter.notifyDataSetChanged();
95        }
96    }
97
98    @Override
99    public MenuView getMenuView(ViewGroup root) {
100        if (mMenuView == null) {
101            mMenuView = (ExpandedMenuView) mInflater.inflate(
102                    R.layout.abc_expanded_menu_layout, root, false);
103            if (mAdapter == null) {
104                mAdapter = new MenuAdapter();
105            }
106            mMenuView.setAdapter(mAdapter);
107            mMenuView.setOnItemClickListener(this);
108        }
109        return mMenuView;
110    }
111
112    /**
113     * Call this instead of getMenuView if you want to manage your own ListView.
114     * For proper operation, the ListView hosting this adapter should add
115     * this presenter as an OnItemClickListener.
116     *
117     * @return A ListAdapter containing the items in the menu.
118     */
119    public ListAdapter getAdapter() {
120        if (mAdapter == null) {
121            mAdapter = new MenuAdapter();
122        }
123        return mAdapter;
124    }
125
126    @Override
127    public void updateMenuView(boolean cleared) {
128        if (mAdapter != null) mAdapter.notifyDataSetChanged();
129    }
130
131    @Override
132    public void setCallback(Callback cb) {
133        mCallback = cb;
134    }
135
136    @Override
137    public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
138        if (!subMenu.hasVisibleItems()) return false;
139
140        // The window manager will give us a token.
141        new MenuDialogHelper(subMenu).show(null);
142        if (mCallback != null) {
143            mCallback.onOpenSubMenu(subMenu);
144        }
145        return true;
146    }
147
148    @Override
149    public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
150        if (mCallback != null) {
151            mCallback.onCloseMenu(menu, allMenusAreClosing);
152        }
153    }
154
155    int getItemIndexOffset() {
156        return mItemIndexOffset;
157    }
158
159    public void setItemIndexOffset(int offset) {
160        mItemIndexOffset = offset;
161        if (mMenuView != null) {
162            updateMenuView(false);
163        }
164    }
165
166    @Override
167    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
168        mMenu.performItemAction(mAdapter.getItem(position), this, 0);
169    }
170
171    @Override
172    public boolean flagActionItems() {
173        return false;
174    }
175
176    public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
177        return false;
178    }
179
180    public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
181        return false;
182    }
183
184    public void saveHierarchyState(Bundle outState) {
185        SparseArray<Parcelable> viewStates = new SparseArray<Parcelable>();
186        if (mMenuView != null) {
187            ((View) mMenuView).saveHierarchyState(viewStates);
188        }
189        outState.putSparseParcelableArray(VIEWS_TAG, viewStates);
190    }
191
192    public void restoreHierarchyState(Bundle inState) {
193        SparseArray<Parcelable> viewStates = inState.getSparseParcelableArray(VIEWS_TAG);
194        if (viewStates != null) {
195            ((View) mMenuView).restoreHierarchyState(viewStates);
196        }
197    }
198
199    public void setId(int id) {
200        mId = id;
201    }
202
203    @Override
204    public int getId() {
205        return mId;
206    }
207
208    @Override
209    public Parcelable onSaveInstanceState() {
210        if (mMenuView == null) {
211            return null;
212        }
213
214        Bundle state = new Bundle();
215        saveHierarchyState(state);
216        return state;
217    }
218
219    @Override
220    public void onRestoreInstanceState(Parcelable state) {
221        restoreHierarchyState((Bundle) state);
222    }
223
224    private class MenuAdapter extends BaseAdapter {
225        private int mExpandedIndex = -1;
226
227        public MenuAdapter() {
228            findExpandedIndex();
229        }
230
231        public int getCount() {
232            ArrayList<MenuItemImpl> items = mMenu.getNonActionItems();
233            int count = items.size() - mItemIndexOffset;
234            if (mExpandedIndex < 0) {
235                return count;
236            }
237            return count - 1;
238        }
239
240        public MenuItemImpl getItem(int position) {
241            ArrayList<MenuItemImpl> items = mMenu.getNonActionItems();
242            position += mItemIndexOffset;
243            if (mExpandedIndex >= 0 && position >= mExpandedIndex) {
244                position++;
245            }
246            return items.get(position);
247        }
248
249        public long getItemId(int position) {
250            // Since a menu item's ID is optional, we'll use the position as an
251            // ID for the item in the AdapterView
252            return position;
253        }
254
255        public View getView(int position, View convertView, ViewGroup parent) {
256            if (convertView == null) {
257                convertView = mInflater.inflate(mItemLayoutRes, parent, false);
258            }
259
260            MenuView.ItemView itemView = (MenuView.ItemView) convertView;
261            itemView.initialize(getItem(position), 0);
262            return convertView;
263        }
264
265        void findExpandedIndex() {
266            final MenuItemImpl expandedItem = mMenu.getExpandedItem();
267            if (expandedItem != null) {
268                final ArrayList<MenuItemImpl> items = mMenu.getNonActionItems();
269                final int count = items.size();
270                for (int i = 0; i < count; i++) {
271                    final MenuItemImpl item = items.get(i);
272                    if (item == expandedItem) {
273                        mExpandedIndex = i;
274                        return;
275                    }
276                }
277            }
278            mExpandedIndex = -1;
279        }
280
281        @Override
282        public void notifyDataSetChanged() {
283            findExpandedIndex();
284            super.notifyDataSetChanged();
285        }
286    }
287}
288