1/*
2 * Copyright (C) 2006 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.graphics.drawable.Drawable;
21import android.support.annotation.RestrictTo;
22import android.support.v4.view.ViewCompat;
23import android.support.v7.appcompat.R;
24import android.support.v7.widget.TintTypedArray;
25import android.util.AttributeSet;
26import android.view.LayoutInflater;
27import android.view.View;
28import android.view.ViewGroup;
29import android.widget.CheckBox;
30import android.widget.CompoundButton;
31import android.widget.ImageView;
32import android.widget.LinearLayout;
33import android.widget.RadioButton;
34import android.widget.TextView;
35
36import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
37
38/**
39 * The item view for each item in the ListView-based MenuViews.
40 *
41 * @hide
42 */
43@RestrictTo(GROUP_ID)
44public class ListMenuItemView extends LinearLayout implements MenuView.ItemView {
45    private static final String TAG = "ListMenuItemView";
46    private MenuItemImpl mItemData;
47
48    private ImageView mIconView;
49    private RadioButton mRadioButton;
50    private TextView mTitleView;
51    private CheckBox mCheckBox;
52    private TextView mShortcutView;
53    private ImageView mSubMenuArrowView;
54
55    private Drawable mBackground;
56    private int mTextAppearance;
57    private Context mTextAppearanceContext;
58    private boolean mPreserveIconSpacing;
59    private Drawable mSubMenuArrow;
60
61    private int mMenuType;
62
63    private LayoutInflater mInflater;
64
65    private boolean mForceShowIcon;
66
67    public ListMenuItemView(Context context, AttributeSet attrs) {
68        this(context, attrs, R.attr.listMenuViewStyle);
69    }
70
71    public ListMenuItemView(Context context, AttributeSet attrs, int defStyleAttr) {
72        super(context, attrs);
73
74        final TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(),
75                attrs, R.styleable.MenuView, defStyleAttr, 0);
76
77        mBackground = a.getDrawable(R.styleable.MenuView_android_itemBackground);
78        mTextAppearance = a.getResourceId(R.styleable.
79                MenuView_android_itemTextAppearance, -1);
80        mPreserveIconSpacing = a.getBoolean(
81                R.styleable.MenuView_preserveIconSpacing, false);
82        mTextAppearanceContext = context;
83        mSubMenuArrow = a.getDrawable(R.styleable.MenuView_subMenuArrow);
84
85        a.recycle();
86    }
87
88    @Override
89    protected void onFinishInflate() {
90        super.onFinishInflate();
91
92        ViewCompat.setBackground(this, mBackground);
93
94        mTitleView = (TextView) findViewById(R.id.title);
95        if (mTextAppearance != -1) {
96            mTitleView.setTextAppearance(mTextAppearanceContext,
97                    mTextAppearance);
98        }
99
100        mShortcutView = (TextView) findViewById(R.id.shortcut);
101        mSubMenuArrowView = (ImageView) findViewById(R.id.submenuarrow);
102        if (mSubMenuArrowView != null) {
103            mSubMenuArrowView.setImageDrawable(mSubMenuArrow);
104        }
105    }
106
107    public void initialize(MenuItemImpl itemData, int menuType) {
108        mItemData = itemData;
109        mMenuType = menuType;
110
111        setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE);
112
113        setTitle(itemData.getTitleForItemView(this));
114        setCheckable(itemData.isCheckable());
115        setShortcut(itemData.shouldShowShortcut(), itemData.getShortcut());
116        setIcon(itemData.getIcon());
117        setEnabled(itemData.isEnabled());
118        setSubMenuArrowVisible(itemData.hasSubMenu());
119    }
120
121    public void setForceShowIcon(boolean forceShow) {
122        mPreserveIconSpacing = mForceShowIcon = forceShow;
123    }
124
125    public void setTitle(CharSequence title) {
126        if (title != null) {
127            mTitleView.setText(title);
128
129            if (mTitleView.getVisibility() != VISIBLE) mTitleView.setVisibility(VISIBLE);
130        } else {
131            if (mTitleView.getVisibility() != GONE) mTitleView.setVisibility(GONE);
132        }
133    }
134
135    public MenuItemImpl getItemData() {
136        return mItemData;
137    }
138
139    public void setCheckable(boolean checkable) {
140        if (!checkable && mRadioButton == null && mCheckBox == null) {
141            return;
142        }
143
144        // Depending on whether its exclusive check or not, the checkbox or
145        // radio button will be the one in use (and the other will be otherCompoundButton)
146        final CompoundButton compoundButton;
147        final CompoundButton otherCompoundButton;
148
149        if (mItemData.isExclusiveCheckable()) {
150            if (mRadioButton == null) {
151                insertRadioButton();
152            }
153            compoundButton = mRadioButton;
154            otherCompoundButton = mCheckBox;
155        } else {
156            if (mCheckBox == null) {
157                insertCheckBox();
158            }
159            compoundButton = mCheckBox;
160            otherCompoundButton = mRadioButton;
161        }
162
163        if (checkable) {
164            compoundButton.setChecked(mItemData.isChecked());
165
166            final int newVisibility = checkable ? VISIBLE : GONE;
167            if (compoundButton.getVisibility() != newVisibility) {
168                compoundButton.setVisibility(newVisibility);
169            }
170
171            // Make sure the other compound button isn't visible
172            if (otherCompoundButton != null && otherCompoundButton.getVisibility() != GONE) {
173                otherCompoundButton.setVisibility(GONE);
174            }
175        } else {
176            if (mCheckBox != null) {
177                mCheckBox.setVisibility(GONE);
178            }
179            if (mRadioButton != null) {
180                mRadioButton.setVisibility(GONE);
181            }
182        }
183    }
184
185    public void setChecked(boolean checked) {
186        CompoundButton compoundButton;
187
188        if (mItemData.isExclusiveCheckable()) {
189            if (mRadioButton == null) {
190                insertRadioButton();
191            }
192            compoundButton = mRadioButton;
193        } else {
194            if (mCheckBox == null) {
195                insertCheckBox();
196            }
197            compoundButton = mCheckBox;
198        }
199
200        compoundButton.setChecked(checked);
201    }
202
203    private void setSubMenuArrowVisible(boolean hasSubmenu) {
204        if (mSubMenuArrowView != null) {
205            mSubMenuArrowView.setVisibility(hasSubmenu ? View.VISIBLE : View.GONE);
206        }
207    }
208
209    public void setShortcut(boolean showShortcut, char shortcutKey) {
210        final int newVisibility = (showShortcut && mItemData.shouldShowShortcut())
211                ? VISIBLE : GONE;
212
213        if (newVisibility == VISIBLE) {
214            mShortcutView.setText(mItemData.getShortcutLabel());
215        }
216
217        if (mShortcutView.getVisibility() != newVisibility) {
218            mShortcutView.setVisibility(newVisibility);
219        }
220    }
221
222    public void setIcon(Drawable icon) {
223        final boolean showIcon = mItemData.shouldShowIcon() || mForceShowIcon;
224        if (!showIcon && !mPreserveIconSpacing) {
225            return;
226        }
227
228        if (mIconView == null && icon == null && !mPreserveIconSpacing) {
229            return;
230        }
231
232        if (mIconView == null) {
233            insertIconView();
234        }
235
236        if (icon != null || mPreserveIconSpacing) {
237            mIconView.setImageDrawable(showIcon ? icon : null);
238
239            if (mIconView.getVisibility() != VISIBLE) {
240                mIconView.setVisibility(VISIBLE);
241            }
242        } else {
243            mIconView.setVisibility(GONE);
244        }
245    }
246
247    @Override
248    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
249        if (mIconView != null && mPreserveIconSpacing) {
250            // Enforce minimum icon spacing
251            ViewGroup.LayoutParams lp = getLayoutParams();
252            LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
253            if (lp.height > 0 && iconLp.width <= 0) {
254                iconLp.width = lp.height;
255            }
256        }
257        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
258    }
259
260    private void insertIconView() {
261        LayoutInflater inflater = getInflater();
262        mIconView = (ImageView) inflater.inflate(R.layout.abc_list_menu_item_icon,
263                this, false);
264        addView(mIconView, 0);
265    }
266
267    private void insertRadioButton() {
268        LayoutInflater inflater = getInflater();
269        mRadioButton =
270                (RadioButton) inflater.inflate(R.layout.abc_list_menu_item_radio,
271                        this, false);
272        addView(mRadioButton);
273    }
274
275    private void insertCheckBox() {
276        LayoutInflater inflater = getInflater();
277        mCheckBox =
278                (CheckBox) inflater.inflate(R.layout.abc_list_menu_item_checkbox,
279                        this, false);
280        addView(mCheckBox);
281    }
282
283    public boolean prefersCondensedTitle() {
284        return false;
285    }
286
287    public boolean showsIcon() {
288        return mForceShowIcon;
289    }
290
291    private LayoutInflater getInflater() {
292        if (mInflater == null) {
293            mInflater = LayoutInflater.from(getContext());
294        }
295        return mInflater;
296    }
297}
298
299