com.actionbarsherlock.internal.view.MenuItemImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.actionbarsherlock.internal.view.MenuItemImpl.java

Source

/*
 * Copyright (C) 2006 The Android Open Source Project
 *               2011 Jake Wharton
 *
 * 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.actionbarsherlock.internal.view;

import java.lang.ref.WeakReference;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.support.v4.view.MenuItem;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;

/**
 * An implementation of the {@link android.view.MenuItem} interface for use in
 * inflating menu XML resources to be added to a third-party action bar. 
 * 
 * @author Jake Wharton <jakewharton@gmail.com>
 * @see <a href="http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=core/java/com/android/internal/view/menu/MenuItemImpl.java">com.android.internal.view.menu.MenuItemImpl</a>
 */
public final class MenuItemImpl implements MenuItem {
    private static final String TAG = "MenuItemImpl";

    private final MenuBuilder mMenu;

    private final int mItemId;
    private final int mGroupId;
    private final int mOrder;

    private Intent mIntent;
    private CharSequence mTitle;
    private CharSequence mTitleCondensed;
    private char mNumericalShortcut;
    private char mAlphabeticalShortcut;
    private int mShowAsAction;
    private SubMenuBuilder mSubMenu;
    private Runnable mItemCallback;
    private OnMenuItemClickListener mClickListener;
    private Drawable mIcon;
    private int mIconRes = View.NO_ID;
    private View mActionView;
    private int mActionViewRes = View.NO_ID;

    int mFlags = ENABLED;
    private static final int CHECKABLE = 0x01;
    private static final int CHECKED = 0x02;
    private static final int EXCLUSIVE = 0x04;
    private static final int HIDDEN = 0x08;
    private static final int ENABLED = 0x10;
    private static final int IS_ACTION = 0x20;

    private final WeakReference<MenuView.ItemView>[] mItemViews;

    /**
     * Create a new action bar menu item.
     * 
     * @param context Context used if resource resolution is required.
     * @param itemId A unique ID. Used in the activity callback.
     * @param groupId Group ID. Currently unused.
     * @param order Item order. Currently unused.
     * @param title Title of the item.
     */
    @SuppressWarnings("unchecked")
    MenuItemImpl(MenuBuilder menu, int itemId, int groupId, int order, CharSequence title) {
        mMenu = menu;

        mItemId = itemId;
        mGroupId = groupId;
        mOrder = order;
        mTitle = title;

        mItemViews = new WeakReference[MenuBuilder.NUM_TYPES];
    }

    public boolean invoke() {
        if (mClickListener != null && mClickListener.onMenuItemClick(this)) {
            return true;
        }

        MenuBuilder.Callback callback = mMenu.getCallback();
        if (callback != null && callback.onMenuItemSelected(mMenu.getRootMenu(), this)) {
            return true;
        }

        if (mItemCallback != null) {
            mItemCallback.run();
            return true;
        }

        if (mIntent != null) {
            try {
                mMenu.getContext().startActivity(mIntent);
                return true;
            } catch (ActivityNotFoundException e) {
                Log.e(TAG, "Can't find activity to handle intent; ignoring", e);
            }
        }

        return false;
    }

    private boolean hasItemView(int menuType) {
        return mItemViews[menuType] != null && mItemViews[menuType].get() != null;
    }

    public void setItemView(int type, MenuView.ItemView itemView) {
        mItemViews[type] = new WeakReference<MenuView.ItemView>(itemView);
    }

    public void addTo(android.view.Menu menu) {
        if (this.mSubMenu != null) {
            android.view.SubMenu subMenu = menu.addSubMenu(this.mGroupId, this.mItemId, this.mOrder, this.mTitle);
            if (mIconRes != View.NO_ID) {
                subMenu.setIcon(mIconRes);
            } else {
                subMenu.setIcon(mIcon);
            }

            for (MenuItemImpl item : this.mSubMenu.getItems()) {
                item.addTo(subMenu);
            }
        } else {
            android.view.MenuItem item = menu.add(this.mGroupId, this.mItemId, this.mOrder, this.mTitle)
                    .setAlphabeticShortcut(this.mAlphabeticalShortcut).setNumericShortcut(this.mNumericalShortcut)
                    .setVisible(this.isVisible()).setIntent(this.mIntent)
                    .setOnMenuItemClickListener(this.mClickListener);

            if (this.isExclusiveCheckable()) {
                menu.setGroupCheckable(this.mGroupId, true, true);
            }

            //Create and initialize a native itemview wrapper
            NativeMenuItemView nativeWrapper = new NativeMenuItemView(item);
            nativeWrapper.initialize(this, MenuBuilder.TYPE_NATIVE);

            //Associate the itemview to this so changes will be reflected
            setItemView(MenuBuilder.TYPE_NATIVE, nativeWrapper);
        }
    }

    /**
     * Get whether or not this item is being shown on the action bar.
     * 
     * @return {@code true} if shown, {@code false} otherwise.
     */
    public boolean isShownOnActionBar() {
        return (mFlags & IS_ACTION) == IS_ACTION;
    }

    /**
     * Denote whether or not this menu item is being shown on the action bar.
     * 
     * @param isShownOnActionBar {@code true} if shown or {@code false}.
     */
    public void setIsShownOnActionBar(boolean isShownOnActionBar) {
        mFlags = (mFlags & ~IS_ACTION) | (isShownOnActionBar ? IS_ACTION : 0);
    }

    @Override
    public Intent getIntent() {
        return this.mIntent;
    }

    @Override
    public int getItemId() {
        return this.mItemId;
    }

    @Override
    public CharSequence getTitle() {
        return this.mTitle;
    }

    @Override
    public boolean isEnabled() {
        return (mFlags & ENABLED) != 0;
    }

    @Override
    public boolean isVisible() {
        return (mFlags & HIDDEN) == 0;
    }

    @Override
    public MenuItem setEnabled(boolean enabled) {
        final boolean oldValue = isEnabled();
        mFlags = (mFlags & ~ENABLED) | (enabled ? ENABLED : 0);

        if (oldValue != enabled) {
            for (int i = MenuBuilder.NUM_TYPES - 1; i >= 0; i--) {
                if (hasItemView(i)) {
                    mItemViews[i].get().setEnabled(enabled);
                }
            }
        }

        return this;
    }

    @Override
    public MenuItem setIcon(int iconResourceId) {
        mIcon = null;
        mIconRes = iconResourceId;

        if (mIconRes != View.NO_ID) {
            setIconOnViews(mMenu.getContext().getResources().getDrawable(mIconRes));
        }

        return this;
    }

    @Override
    public MenuItem setIntent(Intent intent) {
        mIntent = intent;
        return this;
    }

    @Override
    public MenuItem setTitle(CharSequence title) {
        mTitle = title;
        return this;
    }

    @Override
    public MenuItem setTitle(int titleResourceId) {
        mTitle = mMenu.getContext().getResources().getString(titleResourceId);
        return this;
    }

    @Override
    public MenuItem setVisible(boolean visible) {
        final boolean oldValue = isVisible();
        mFlags = (mFlags & ~HIDDEN) | (visible ? 0 : HIDDEN);
        if (oldValue != visible) {
            //TODO?
        }
        return this;
    }

    @Override
    public boolean isChecked() {
        return (mFlags & CHECKED) == CHECKED;
    }

    @Override
    public MenuItem setChecked(boolean checked) {
        if ((mFlags & EXCLUSIVE) == EXCLUSIVE) {
            // Call the method on the Menu since it knows about the others in this
            // exclusive checkable group
            mMenu.setExclusiveItemChecked(this);
        } else {
            setCheckedInt(checked);
        }

        return this;
    }

    void setCheckedInt(boolean checked) {
        final boolean oldValue = isChecked();
        mFlags = (mFlags & ~CHECKED) | (checked ? CHECKED : 0);
        if (oldValue != checked) {
            for (int i = MenuBuilder.NUM_TYPES - 1; i >= 0; i--) {
                if (hasItemView(i)) {
                    mItemViews[i].get().setChecked(checked);
                }
            }
        }
    }

    @Override
    public boolean isCheckable() {
        return (mFlags & CHECKABLE) == CHECKABLE;
    }

    @Override
    public MenuItem setCheckable(boolean checkable) {
        final boolean oldValue = isCheckable();
        mFlags = (mFlags & ~CHECKABLE) | (checkable ? CHECKABLE : 0);
        if (oldValue != checkable) {
            for (int i = MenuBuilder.NUM_TYPES - 1; i >= 0; i--) {
                if (hasItemView(i)) {
                    mItemViews[i].get().setCheckable(checkable);
                }
            }
        }

        return this;
    }

    public void setExclusiveCheckable(boolean exclusive) {
        mFlags = (mFlags & ~EXCLUSIVE) | (exclusive ? EXCLUSIVE : 0);
    }

    public boolean isExclusiveCheckable() {
        return (mFlags & EXCLUSIVE) != 0;
    }

    @Override
    public CharSequence getTitleCondensed() {
        return mTitleCondensed;
    }

    @Override
    public MenuItem setTitleCondensed(CharSequence title) {
        mTitleCondensed = title;
        return this;
    }

    @Override
    public int getGroupId() {
        return mGroupId;
    }

    @Override
    public int getOrder() {
        return mOrder;
    }

    @Override
    public SubMenuBuilder getSubMenu() {
        return mSubMenu;
    }

    /**
     * Set the sub-menu of this item.
     * 
     * @param subMenu Sub-menu instance.
     * @return This Item so additional setters can be called. 
     */
    MenuItem setSubMenu(SubMenuBuilder subMenu) {
        mSubMenu = subMenu;
        return this;
    }

    @Override
    public boolean hasSubMenu() {
        return (mSubMenu != null) && (mSubMenu.size() > 0);
    }

    @Override
    public char getAlphabeticShortcut() {
        return mAlphabeticalShortcut;
    }

    @Override
    public char getNumericShortcut() {
        return mNumericalShortcut;
    }

    @Override
    public MenuItem setAlphabeticShortcut(char alphaChar) {
        mAlphabeticalShortcut = Character.toLowerCase(alphaChar);
        return this;
    }

    @Override
    public MenuItem setNumericShortcut(char numericChar) {
        mNumericalShortcut = numericChar;
        return this;
    }

    @Override
    public MenuItem setShortcut(char numericChar, char alphaChar) {
        setNumericShortcut(numericChar);
        setAlphabeticShortcut(alphaChar);
        return this;
    }

    @Override
    public void setShowAsAction(int actionEnum) {
        mShowAsAction = actionEnum;
    }

    public int getShowAsAction() {
        return mShowAsAction;
    }

    @Override
    public View getActionView() {
        if (mActionView != null) {
            return mActionView;
        }
        if (mActionViewRes != View.NO_ID) {
            return LayoutInflater.from(mMenu.getContext()).inflate(mActionViewRes, null, false);
        }
        return null;
    }

    @Override
    public Drawable getIcon() {
        if (mIcon != null) {
            return mIcon;
        }
        if (mIconRes != View.NO_ID) {
            return mMenu.getContext().getResources().getDrawable(mIconRes);
        }
        return null;
    }

    @Override
    public ContextMenuInfo getMenuInfo() {
        throw new RuntimeException("Method not supported.");
    }

    @Override
    public MenuItem setActionView(View view) {
        mActionView = view;
        mActionViewRes = View.NO_ID;
        setActionViewOnViews(mActionView);
        return this;
    }

    @Override
    public MenuItem setActionView(int resId) {
        mActionView = null;
        mActionViewRes = resId;

        if (mActionViewRes != View.NO_ID) {
            setActionViewOnViews(LayoutInflater.from(mMenu.getContext()).inflate(mActionViewRes, null, false));
        }

        return this;
    }

    void setActionViewOnViews(View view) {
        for (int i = MenuBuilder.NUM_TYPES - 1; i >= 0; i--) {
            if (hasItemView(i)) {
                mItemViews[i].get().setActionView(view);
            }
        }
    }

    @Override
    public MenuItem setIcon(Drawable icon) {
        mIcon = icon;
        mIconRes = View.NO_ID;
        setIconOnViews(icon);
        return this;
    }

    void setIconOnViews(Drawable icon) {
        for (int i = MenuBuilder.NUM_TYPES - 1; i >= 0; i--) {
            if (hasItemView(i)) {
                mItemViews[i].get().setIcon(icon);
            }
        }
    }

    @Override
    public android.view.MenuItem setOnMenuItemClickListener(
            final android.view.MenuItem.OnMenuItemClickListener menuItemClickListener) {
        return this.setOnMenuItemClickListener(new OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                return menuItemClickListener.onMenuItemClick(new MenuItemWrapper(item));
            }
        });
    }

    @Override
    public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) {
        mClickListener = menuItemClickListener;
        return this;
    }

    /**
     * Returns the currently set menu click listener for this item.
     * 
     * @return Click listener or {@code null}.
     */
    public OnMenuItemClickListener getOnMenuItemClickListener() {
        return mClickListener;
    }

    public static final class NativeMenuItemView implements MenuView.ItemView {
        private final android.view.MenuItem mItem;

        public NativeMenuItemView(android.view.MenuItem item) {
            mItem = item;
        }

        @Override
        public MenuItemImpl getItemData() {
            return null;
        }

        @Override
        public void initialize(MenuItemImpl itemData, int menuType) {
            setIcon(itemData.getIcon());
            setTitle(itemData.getTitle());
            setEnabled(itemData.isEnabled());
            setCheckable(itemData.isCheckable());
            setChecked(itemData.isChecked());
            setActionView(itemData.getActionView());
        }

        @Override
        public boolean prefersCondensedTitle() {
            return true;
        }

        @Override
        public void setCheckable(boolean checkable) {
            mItem.setCheckable(checkable);
        }

        @Override
        public void setChecked(boolean checked) {
            mItem.setChecked(checked);
        }

        @Override
        public void setEnabled(boolean enabled) {
            mItem.setEnabled(enabled);
        }

        @Override
        public void setIcon(Drawable icon) {
            mItem.setIcon(icon);
        }

        @Override
        public void setShortcut(boolean showShortcut, char shortcutKey) {
            //Not supported
        }

        @Override
        public void setTitle(CharSequence title) {
            mItem.setTitle(title);
        }

        @Override
        public boolean showsIcon() {
            return true;
        }

        @Override
        public void setActionView(View actionView) {
            //Not supported
        }
    }
}