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