Started using ActionBarSherlock
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
package com.actionbarsherlock.internal.view;
|
||||
|
||||
import com.actionbarsherlock.internal.view.menu.SubMenuWrapper;
|
||||
import com.actionbarsherlock.view.ActionProvider;
|
||||
import android.view.View;
|
||||
|
||||
public class ActionProviderWrapper extends android.view.ActionProvider {
|
||||
private final ActionProvider mProvider;
|
||||
|
||||
|
||||
public ActionProviderWrapper(ActionProvider provider) {
|
||||
super(null/*TODO*/); //XXX this *should* be unused
|
||||
mProvider = provider;
|
||||
}
|
||||
|
||||
|
||||
public ActionProvider unwrap() {
|
||||
return mProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateActionView() {
|
||||
return mProvider.onCreateActionView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSubMenu() {
|
||||
return mProvider.hasSubMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPerformDefaultAction() {
|
||||
return mProvider.onPerformDefaultAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareSubMenu(android.view.SubMenu subMenu) {
|
||||
mProvider.onPrepareSubMenu(new SubMenuWrapper(subMenu));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* 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 android.content.Context;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import com.actionbarsherlock.internal.view.menu.MenuBuilder;
|
||||
import com.actionbarsherlock.internal.view.menu.MenuPopupHelper;
|
||||
import com.actionbarsherlock.internal.view.menu.SubMenuBuilder;
|
||||
import com.actionbarsherlock.internal.widget.ActionBarContextView;
|
||||
import com.actionbarsherlock.view.ActionMode;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
public class StandaloneActionMode extends ActionMode implements MenuBuilder.Callback {
|
||||
private Context mContext;
|
||||
private ActionBarContextView mContextView;
|
||||
private ActionMode.Callback mCallback;
|
||||
private WeakReference<View> mCustomView;
|
||||
private boolean mFinished;
|
||||
private boolean mFocusable;
|
||||
|
||||
private MenuBuilder mMenu;
|
||||
|
||||
public StandaloneActionMode(Context context, ActionBarContextView view,
|
||||
ActionMode.Callback callback, boolean isFocusable) {
|
||||
mContext = context;
|
||||
mContextView = view;
|
||||
mCallback = callback;
|
||||
|
||||
mMenu = new MenuBuilder(context).setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
||||
mMenu.setCallback(this);
|
||||
mFocusable = isFocusable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(CharSequence title) {
|
||||
mContextView.setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSubtitle(CharSequence subtitle) {
|
||||
mContextView.setSubtitle(subtitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(int resId) {
|
||||
setTitle(mContext.getString(resId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSubtitle(int resId) {
|
||||
setSubtitle(mContext.getString(resId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomView(View view) {
|
||||
mContextView.setCustomView(view);
|
||||
mCustomView = view != null ? new WeakReference<View>(view) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
mCallback.onPrepareActionMode(this, mMenu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
if (mFinished) {
|
||||
return;
|
||||
}
|
||||
mFinished = true;
|
||||
|
||||
mContextView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
|
||||
mCallback.onDestroyActionMode(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Menu getMenu() {
|
||||
return mMenu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTitle() {
|
||||
return mContextView.getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSubtitle() {
|
||||
return mContextView.getSubtitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getCustomView() {
|
||||
return mCustomView != null ? mCustomView.get() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuInflater getMenuInflater() {
|
||||
return new MenuInflater(mContext);
|
||||
}
|
||||
|
||||
public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
|
||||
return mCallback.onActionItemClicked(this, item);
|
||||
}
|
||||
|
||||
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
|
||||
}
|
||||
|
||||
public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
|
||||
if (!subMenu.hasVisibleItems()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
new MenuPopupHelper(mContext, subMenu).show();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onCloseSubMenu(SubMenuBuilder menu) {
|
||||
}
|
||||
|
||||
public void onMenuModeChange(MenuBuilder menu) {
|
||||
invalidate();
|
||||
mContextView.showOverflowMenu();
|
||||
}
|
||||
|
||||
public boolean isUiFocusable() {
|
||||
return mFocusable;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.actionbarsherlock.internal.view;
|
||||
|
||||
public interface View_HasStateListenerSupport {
|
||||
void addOnAttachStateChangeListener(View_OnAttachStateChangeListener listener);
|
||||
void removeOnAttachStateChangeListener(View_OnAttachStateChangeListener listener);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.actionbarsherlock.internal.view;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
public interface View_OnAttachStateChangeListener {
|
||||
void onViewAttachedToWindow(View v);
|
||||
void onViewDetachedFromWindow(View v);
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* 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.menu;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import com.actionbarsherlock.view.SubMenu;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ActionMenu implements Menu {
|
||||
private Context mContext;
|
||||
|
||||
private boolean mIsQwerty;
|
||||
|
||||
private ArrayList<ActionMenuItem> mItems;
|
||||
|
||||
public ActionMenu(Context context) {
|
||||
mContext = context;
|
||||
mItems = new ArrayList<ActionMenuItem>();
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
public MenuItem add(CharSequence title) {
|
||||
return add(0, 0, 0, title);
|
||||
}
|
||||
|
||||
public MenuItem add(int titleRes) {
|
||||
return add(0, 0, 0, titleRes);
|
||||
}
|
||||
|
||||
public MenuItem add(int groupId, int itemId, int order, int titleRes) {
|
||||
return add(groupId, itemId, order, mContext.getResources().getString(titleRes));
|
||||
}
|
||||
|
||||
public MenuItem add(int groupId, int itemId, int order, CharSequence title) {
|
||||
ActionMenuItem item = new ActionMenuItem(getContext(),
|
||||
groupId, itemId, 0, order, title);
|
||||
mItems.add(order, item);
|
||||
return item;
|
||||
}
|
||||
|
||||
public int addIntentOptions(int groupId, int itemId, int order,
|
||||
ComponentName caller, Intent[] specifics, Intent intent, int flags,
|
||||
MenuItem[] outSpecificItems) {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
final List<ResolveInfo> lri =
|
||||
pm.queryIntentActivityOptions(caller, specifics, intent, 0);
|
||||
final int N = lri != null ? lri.size() : 0;
|
||||
|
||||
if ((flags & FLAG_APPEND_TO_GROUP) == 0) {
|
||||
removeGroup(groupId);
|
||||
}
|
||||
|
||||
for (int i=0; i<N; i++) {
|
||||
final ResolveInfo ri = lri.get(i);
|
||||
Intent rintent = new Intent(
|
||||
ri.specificIndex < 0 ? intent : specifics[ri.specificIndex]);
|
||||
rintent.setComponent(new ComponentName(
|
||||
ri.activityInfo.applicationInfo.packageName,
|
||||
ri.activityInfo.name));
|
||||
final MenuItem item = add(groupId, itemId, order, ri.loadLabel(pm))
|
||||
.setIcon(ri.loadIcon(pm))
|
||||
.setIntent(rintent);
|
||||
if (outSpecificItems != null && ri.specificIndex >= 0) {
|
||||
outSpecificItems[ri.specificIndex] = item;
|
||||
}
|
||||
}
|
||||
|
||||
return N;
|
||||
}
|
||||
|
||||
public SubMenu addSubMenu(CharSequence title) {
|
||||
// TODO Implement submenus
|
||||
return null;
|
||||
}
|
||||
|
||||
public SubMenu addSubMenu(int titleRes) {
|
||||
// TODO Implement submenus
|
||||
return null;
|
||||
}
|
||||
|
||||
public SubMenu addSubMenu(int groupId, int itemId, int order,
|
||||
CharSequence title) {
|
||||
// TODO Implement submenus
|
||||
return null;
|
||||
}
|
||||
|
||||
public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) {
|
||||
// TODO Implement submenus
|
||||
return null;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
mItems.clear();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
}
|
||||
|
||||
private int findItemIndex(int id) {
|
||||
final ArrayList<ActionMenuItem> items = mItems;
|
||||
final int itemCount = items.size();
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
if (items.get(i).getItemId() == id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public MenuItem findItem(int id) {
|
||||
return mItems.get(findItemIndex(id));
|
||||
}
|
||||
|
||||
public MenuItem getItem(int index) {
|
||||
return mItems.get(index);
|
||||
}
|
||||
|
||||
public boolean hasVisibleItems() {
|
||||
final ArrayList<ActionMenuItem> items = mItems;
|
||||
final int itemCount = items.size();
|
||||
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
if (items.get(i).isVisible()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private ActionMenuItem findItemWithShortcut(int keyCode, KeyEvent event) {
|
||||
// TODO Make this smarter.
|
||||
final boolean qwerty = mIsQwerty;
|
||||
final ArrayList<ActionMenuItem> items = mItems;
|
||||
final int itemCount = items.size();
|
||||
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
ActionMenuItem item = items.get(i);
|
||||
final char shortcut = qwerty ? item.getAlphabeticShortcut() :
|
||||
item.getNumericShortcut();
|
||||
if (keyCode == shortcut) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isShortcutKey(int keyCode, KeyEvent event) {
|
||||
return findItemWithShortcut(keyCode, event) != null;
|
||||
}
|
||||
|
||||
public boolean performIdentifierAction(int id, int flags) {
|
||||
final int index = findItemIndex(id);
|
||||
if (index < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return mItems.get(index).invoke();
|
||||
}
|
||||
|
||||
public boolean performShortcut(int keyCode, KeyEvent event, int flags) {
|
||||
ActionMenuItem item = findItemWithShortcut(keyCode, event);
|
||||
if (item == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return item.invoke();
|
||||
}
|
||||
|
||||
public void removeGroup(int groupId) {
|
||||
final ArrayList<ActionMenuItem> items = mItems;
|
||||
int itemCount = items.size();
|
||||
int i = 0;
|
||||
while (i < itemCount) {
|
||||
if (items.get(i).getGroupId() == groupId) {
|
||||
items.remove(i);
|
||||
itemCount--;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeItem(int id) {
|
||||
mItems.remove(findItemIndex(id));
|
||||
}
|
||||
|
||||
public void setGroupCheckable(int group, boolean checkable,
|
||||
boolean exclusive) {
|
||||
final ArrayList<ActionMenuItem> items = mItems;
|
||||
final int itemCount = items.size();
|
||||
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
ActionMenuItem item = items.get(i);
|
||||
if (item.getGroupId() == group) {
|
||||
item.setCheckable(checkable);
|
||||
item.setExclusiveCheckable(exclusive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setGroupEnabled(int group, boolean enabled) {
|
||||
final ArrayList<ActionMenuItem> items = mItems;
|
||||
final int itemCount = items.size();
|
||||
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
ActionMenuItem item = items.get(i);
|
||||
if (item.getGroupId() == group) {
|
||||
item.setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setGroupVisible(int group, boolean visible) {
|
||||
final ArrayList<ActionMenuItem> items = mItems;
|
||||
final int itemCount = items.size();
|
||||
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
ActionMenuItem item = items.get(i);
|
||||
if (item.getGroupId() == group) {
|
||||
item.setVisible(visible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setQwertyMode(boolean isQwerty) {
|
||||
mIsQwerty = isQwerty;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return mItems.size();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* 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.menu;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.View;
|
||||
|
||||
import com.actionbarsherlock.view.ActionProvider;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import com.actionbarsherlock.view.SubMenu;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ActionMenuItem implements MenuItem {
|
||||
private final int mId;
|
||||
private final int mGroup;
|
||||
//UNUSED private final int mCategoryOrder;
|
||||
private final int mOrdering;
|
||||
|
||||
private CharSequence mTitle;
|
||||
private CharSequence mTitleCondensed;
|
||||
private Intent mIntent;
|
||||
private char mShortcutNumericChar;
|
||||
private char mShortcutAlphabeticChar;
|
||||
|
||||
private Drawable mIconDrawable;
|
||||
//UNUSED private int mIconResId = NO_ICON;
|
||||
|
||||
private Context mContext;
|
||||
|
||||
private MenuItem.OnMenuItemClickListener mClickListener;
|
||||
|
||||
//UNUSED private static final int NO_ICON = 0;
|
||||
|
||||
private int mFlags = ENABLED;
|
||||
private static final int CHECKABLE = 0x00000001;
|
||||
private static final int CHECKED = 0x00000002;
|
||||
private static final int EXCLUSIVE = 0x00000004;
|
||||
private static final int HIDDEN = 0x00000008;
|
||||
private static final int ENABLED = 0x00000010;
|
||||
|
||||
public ActionMenuItem(Context context, int group, int id, int categoryOrder, int ordering,
|
||||
CharSequence title) {
|
||||
mContext = context;
|
||||
mId = id;
|
||||
mGroup = group;
|
||||
//UNUSED mCategoryOrder = categoryOrder;
|
||||
mOrdering = ordering;
|
||||
mTitle = title;
|
||||
}
|
||||
|
||||
public char getAlphabeticShortcut() {
|
||||
return mShortcutAlphabeticChar;
|
||||
}
|
||||
|
||||
public int getGroupId() {
|
||||
return mGroup;
|
||||
}
|
||||
|
||||
public Drawable getIcon() {
|
||||
return mIconDrawable;
|
||||
}
|
||||
|
||||
public Intent getIntent() {
|
||||
return mIntent;
|
||||
}
|
||||
|
||||
public int getItemId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
public ContextMenuInfo getMenuInfo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public char getNumericShortcut() {
|
||||
return mShortcutNumericChar;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return mOrdering;
|
||||
}
|
||||
|
||||
public SubMenu getSubMenu() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public CharSequence getTitle() {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
public CharSequence getTitleCondensed() {
|
||||
return mTitleCondensed;
|
||||
}
|
||||
|
||||
public boolean hasSubMenu() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isCheckable() {
|
||||
return (mFlags & CHECKABLE) != 0;
|
||||
}
|
||||
|
||||
public boolean isChecked() {
|
||||
return (mFlags & CHECKED) != 0;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return (mFlags & ENABLED) != 0;
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return (mFlags & HIDDEN) == 0;
|
||||
}
|
||||
|
||||
public MenuItem setAlphabeticShortcut(char alphaChar) {
|
||||
mShortcutAlphabeticChar = alphaChar;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setCheckable(boolean checkable) {
|
||||
mFlags = (mFlags & ~CHECKABLE) | (checkable ? CHECKABLE : 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ActionMenuItem setExclusiveCheckable(boolean exclusive) {
|
||||
mFlags = (mFlags & ~EXCLUSIVE) | (exclusive ? EXCLUSIVE : 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setChecked(boolean checked) {
|
||||
mFlags = (mFlags & ~CHECKED) | (checked ? CHECKED : 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setEnabled(boolean enabled) {
|
||||
mFlags = (mFlags & ~ENABLED) | (enabled ? ENABLED : 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setIcon(Drawable icon) {
|
||||
mIconDrawable = icon;
|
||||
//UNUSED mIconResId = NO_ICON;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setIcon(int iconRes) {
|
||||
//UNUSED mIconResId = iconRes;
|
||||
mIconDrawable = mContext.getResources().getDrawable(iconRes);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setIntent(Intent intent) {
|
||||
mIntent = intent;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setNumericShortcut(char numericChar) {
|
||||
mShortcutNumericChar = numericChar;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) {
|
||||
mClickListener = menuItemClickListener;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setShortcut(char numericChar, char alphaChar) {
|
||||
mShortcutNumericChar = numericChar;
|
||||
mShortcutAlphabeticChar = alphaChar;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setTitle(CharSequence title) {
|
||||
mTitle = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setTitle(int title) {
|
||||
mTitle = mContext.getResources().getString(title);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setTitleCondensed(CharSequence title) {
|
||||
mTitleCondensed = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setVisible(boolean visible) {
|
||||
mFlags = (mFlags & HIDDEN) | (visible ? 0 : HIDDEN);
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean invoke() {
|
||||
if (mClickListener != null && mClickListener.onMenuItemClick(this)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mIntent != null) {
|
||||
mContext.startActivity(mIntent);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setShowAsAction(int show) {
|
||||
// Do nothing. ActionMenuItems always show as action buttons.
|
||||
}
|
||||
|
||||
public MenuItem setActionView(View actionView) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public View getActionView() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setActionView(int resId) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionProvider getActionProvider() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setActionProvider(ActionProvider actionProvider) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setShowAsActionFlags(int actionEnum) {
|
||||
setShowAsAction(actionEnum);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean expandActionView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collapseActionView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActionViewExpanded() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setOnActionExpandListener(OnActionExpandListener listener) {
|
||||
// No need to save the listener; ActionMenuItem does not support collapsing items.
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* 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.menu;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.actionbarsherlock.R;
|
||||
import com.actionbarsherlock.internal.view.View_HasStateListenerSupport;
|
||||
import com.actionbarsherlock.internal.view.View_OnAttachStateChangeListener;
|
||||
import com.actionbarsherlock.internal.widget.CapitalizingButton;
|
||||
|
||||
import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getBoolean;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ActionMenuItemView extends LinearLayout
|
||||
implements MenuView.ItemView, View.OnClickListener, View.OnLongClickListener,
|
||||
ActionMenuView.ActionMenuChildView, View_HasStateListenerSupport {
|
||||
//UNUSED private static final String TAG = "ActionMenuItemView";
|
||||
|
||||
private MenuItemImpl mItemData;
|
||||
private CharSequence mTitle;
|
||||
private MenuBuilder.ItemInvoker mItemInvoker;
|
||||
|
||||
private ImageButton mImageButton;
|
||||
private CapitalizingButton mTextButton;
|
||||
private boolean mAllowTextWithIcon;
|
||||
private boolean mExpandedFormat;
|
||||
private int mMinWidth;
|
||||
|
||||
private final Set<View_OnAttachStateChangeListener> mListeners = new HashSet<View_OnAttachStateChangeListener>();
|
||||
|
||||
public ActionMenuItemView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public ActionMenuItemView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public ActionMenuItemView(Context context, AttributeSet attrs, int defStyle) {
|
||||
//TODO super(context, attrs, defStyle);
|
||||
super(context, attrs);
|
||||
mAllowTextWithIcon = getResources_getBoolean(context,
|
||||
R.bool.abs__config_allowActionMenuItemTextWithIcon);
|
||||
TypedArray a = context.obtainStyledAttributes(attrs,
|
||||
R.styleable.SherlockActionMenuItemView, 0, 0);
|
||||
mMinWidth = a.getDimensionPixelSize(
|
||||
R.styleable.SherlockActionMenuItemView_android_minWidth, 0);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOnAttachStateChangeListener(View_OnAttachStateChangeListener listener) {
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeOnAttachStateChangeListener(View_OnAttachStateChangeListener listener) {
|
||||
mListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
for (View_OnAttachStateChangeListener listener : mListeners) {
|
||||
listener.onViewAttachedToWindow(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
for (View_OnAttachStateChangeListener listener : mListeners) {
|
||||
listener.onViewDetachedFromWindow(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishInflate() {
|
||||
|
||||
mImageButton = (ImageButton) findViewById(R.id.abs__imageButton);
|
||||
mTextButton = (CapitalizingButton) findViewById(R.id.abs__textButton);
|
||||
mImageButton.setOnClickListener(this);
|
||||
mTextButton.setOnClickListener(this);
|
||||
mImageButton.setOnLongClickListener(this);
|
||||
setOnClickListener(this);
|
||||
setOnLongClickListener(this);
|
||||
}
|
||||
|
||||
public MenuItemImpl getItemData() {
|
||||
return mItemData;
|
||||
}
|
||||
|
||||
public void initialize(MenuItemImpl itemData, int menuType) {
|
||||
mItemData = itemData;
|
||||
|
||||
setIcon(itemData.getIcon());
|
||||
setTitle(itemData.getTitleForItemView(this)); // Title only takes effect if there is no icon
|
||||
setId(itemData.getItemId());
|
||||
|
||||
setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE);
|
||||
setEnabled(itemData.isEnabled());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
super.setEnabled(enabled);
|
||||
mImageButton.setEnabled(enabled);
|
||||
mTextButton.setEnabled(enabled);
|
||||
}
|
||||
|
||||
public void onClick(View v) {
|
||||
if (mItemInvoker != null) {
|
||||
mItemInvoker.invokeItem(mItemData);
|
||||
}
|
||||
}
|
||||
|
||||
public void setItemInvoker(MenuBuilder.ItemInvoker invoker) {
|
||||
mItemInvoker = invoker;
|
||||
}
|
||||
|
||||
public boolean prefersCondensedTitle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setCheckable(boolean checkable) {
|
||||
// TODO Support checkable action items
|
||||
}
|
||||
|
||||
public void setChecked(boolean checked) {
|
||||
// TODO Support checkable action items
|
||||
}
|
||||
|
||||
public void setExpandedFormat(boolean expandedFormat) {
|
||||
if (mExpandedFormat != expandedFormat) {
|
||||
mExpandedFormat = expandedFormat;
|
||||
if (mItemData != null) {
|
||||
mItemData.actionFormatChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTextButtonVisibility() {
|
||||
boolean visible = !TextUtils.isEmpty(mTextButton.getText());
|
||||
visible &= mImageButton.getDrawable() == null ||
|
||||
(mItemData.showsTextAsAction() && (mAllowTextWithIcon || mExpandedFormat));
|
||||
|
||||
mTextButton.setVisibility(visible ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
public void setIcon(Drawable icon) {
|
||||
mImageButton.setImageDrawable(icon);
|
||||
if (icon != null) {
|
||||
mImageButton.setVisibility(VISIBLE);
|
||||
} else {
|
||||
mImageButton.setVisibility(GONE);
|
||||
}
|
||||
|
||||
updateTextButtonVisibility();
|
||||
}
|
||||
|
||||
public boolean hasText() {
|
||||
return mTextButton.getVisibility() != GONE;
|
||||
}
|
||||
|
||||
public void setShortcut(boolean showShortcut, char shortcutKey) {
|
||||
// Action buttons don't show text for shortcut keys.
|
||||
}
|
||||
|
||||
public void setTitle(CharSequence title) {
|
||||
mTitle = title;
|
||||
|
||||
mTextButton.setTextCompat(mTitle);
|
||||
|
||||
setContentDescription(mTitle);
|
||||
updateTextButtonVisibility();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
|
||||
onPopulateAccessibilityEvent(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
super.onPopulateAccessibilityEvent(event);
|
||||
}
|
||||
final CharSequence cdesc = getContentDescription();
|
||||
if (!TextUtils.isEmpty(cdesc)) {
|
||||
event.getText().add(cdesc);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchHoverEvent(MotionEvent event) {
|
||||
// Don't allow children to hover; we want this to be treated as a single component.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
return onHoverEvent(event);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean showsIcon() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean needsDividerBefore() {
|
||||
return hasText() && mItemData.getIcon() == null;
|
||||
}
|
||||
|
||||
public boolean needsDividerAfter() {
|
||||
return hasText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
if (hasText()) {
|
||||
// Don't show the cheat sheet for items that already show text.
|
||||
return false;
|
||||
}
|
||||
|
||||
final int[] screenPos = new int[2];
|
||||
final Rect displayFrame = new Rect();
|
||||
getLocationOnScreen(screenPos);
|
||||
getWindowVisibleDisplayFrame(displayFrame);
|
||||
|
||||
final Context context = getContext();
|
||||
final int width = getWidth();
|
||||
final int height = getHeight();
|
||||
final int midy = screenPos[1] + height / 2;
|
||||
final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
|
||||
|
||||
Toast cheatSheet = Toast.makeText(context, mItemData.getTitle(), Toast.LENGTH_SHORT);
|
||||
if (midy < displayFrame.height()) {
|
||||
// Show along the top; follow action buttons
|
||||
cheatSheet.setGravity(Gravity.TOP | Gravity.RIGHT,
|
||||
screenWidth - screenPos[0] - width / 2, height);
|
||||
} else {
|
||||
// Show along the bottom center
|
||||
cheatSheet.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height);
|
||||
}
|
||||
cheatSheet.show();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
|
||||
final int specSize = MeasureSpec.getSize(widthMeasureSpec);
|
||||
final int oldMeasuredWidth = getMeasuredWidth();
|
||||
final int targetWidth = widthMode == MeasureSpec.AT_MOST ? Math.min(specSize, mMinWidth)
|
||||
: mMinWidth;
|
||||
|
||||
if (widthMode != MeasureSpec.EXACTLY && mMinWidth > 0 && oldMeasuredWidth < targetWidth) {
|
||||
// Remeasure at exactly the minimum width.
|
||||
super.onMeasure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY),
|
||||
heightMeasureSpec);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,715 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* 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.menu;
|
||||
|
||||
import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Build;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.view.SoundEffectConstants;
|
||||
import android.view.View;
|
||||
import android.view.View.MeasureSpec;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageButton;
|
||||
import com.actionbarsherlock.R;
|
||||
import com.actionbarsherlock.internal.view.View_HasStateListenerSupport;
|
||||
import com.actionbarsherlock.internal.view.View_OnAttachStateChangeListener;
|
||||
import com.actionbarsherlock.internal.view.menu.ActionMenuView.ActionMenuChildView;
|
||||
import com.actionbarsherlock.view.ActionProvider;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
/**
|
||||
* MenuPresenter for building action menus as seen in the action bar and action modes.
|
||||
*/
|
||||
public class ActionMenuPresenter extends BaseMenuPresenter
|
||||
implements ActionProvider.SubUiVisibilityListener {
|
||||
//UNUSED private static final String TAG = "ActionMenuPresenter";
|
||||
|
||||
private View mOverflowButton;
|
||||
private boolean mReserveOverflow;
|
||||
private boolean mReserveOverflowSet;
|
||||
private int mWidthLimit;
|
||||
private int mActionItemWidthLimit;
|
||||
private int mMaxItems;
|
||||
private boolean mMaxItemsSet;
|
||||
private boolean mStrictWidthLimit;
|
||||
private boolean mWidthLimitSet;
|
||||
private boolean mExpandedActionViewsExclusive;
|
||||
|
||||
private int mMinCellSize;
|
||||
|
||||
// Group IDs that have been added as actions - used temporarily, allocated here for reuse.
|
||||
private final SparseBooleanArray mActionButtonGroups = new SparseBooleanArray();
|
||||
|
||||
private View mScrapActionButtonView;
|
||||
|
||||
private OverflowPopup mOverflowPopup;
|
||||
private ActionButtonSubmenu mActionButtonPopup;
|
||||
|
||||
private OpenOverflowRunnable mPostedOpenRunnable;
|
||||
|
||||
final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback();
|
||||
int mOpenSubMenuId;
|
||||
|
||||
public ActionMenuPresenter(Context context) {
|
||||
super(context, R.layout.abs__action_menu_layout,
|
||||
R.layout.abs__action_menu_item_layout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initForMenu(Context context, MenuBuilder menu) {
|
||||
super.initForMenu(context, menu);
|
||||
|
||||
final Resources res = context.getResources();
|
||||
|
||||
if (!mReserveOverflowSet) {
|
||||
mReserveOverflow = reserveOverflow(mContext);
|
||||
}
|
||||
|
||||
if (!mWidthLimitSet) {
|
||||
mWidthLimit = res.getDisplayMetrics().widthPixels / 2;
|
||||
}
|
||||
|
||||
// Measure for initial configuration
|
||||
if (!mMaxItemsSet) {
|
||||
mMaxItems = getResources_getInteger(context, R.integer.abs__max_action_buttons);
|
||||
}
|
||||
|
||||
int width = mWidthLimit;
|
||||
if (mReserveOverflow) {
|
||||
if (mOverflowButton == null) {
|
||||
mOverflowButton = new OverflowMenuButton(mSystemContext);
|
||||
final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
mOverflowButton.measure(spec, spec);
|
||||
}
|
||||
width -= mOverflowButton.getMeasuredWidth();
|
||||
} else {
|
||||
mOverflowButton = null;
|
||||
}
|
||||
|
||||
mActionItemWidthLimit = width;
|
||||
|
||||
mMinCellSize = (int) (ActionMenuView.MIN_CELL_SIZE * res.getDisplayMetrics().density);
|
||||
|
||||
// Drop a scrap view as it may no longer reflect the proper context/config.
|
||||
mScrapActionButtonView = null;
|
||||
}
|
||||
|
||||
public static boolean reserveOverflow(Context context) {
|
||||
//Check for theme-forced overflow action item
|
||||
TypedArray a = context.getTheme().obtainStyledAttributes(R.styleable.SherlockTheme);
|
||||
boolean result = a.getBoolean(R.styleable.SherlockTheme_absForceOverflow, false);
|
||||
a.recycle();
|
||||
if (result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB);
|
||||
} else {
|
||||
return !ViewConfiguration.get(context).hasPermanentMenuKey();
|
||||
}
|
||||
}
|
||||
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
if (!mMaxItemsSet) {
|
||||
mMaxItems = getResources_getInteger(mContext,
|
||||
R.integer.abs__max_action_buttons);
|
||||
if (mMenu != null) {
|
||||
mMenu.onItemsChanged(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setWidthLimit(int width, boolean strict) {
|
||||
mWidthLimit = width;
|
||||
mStrictWidthLimit = strict;
|
||||
mWidthLimitSet = true;
|
||||
}
|
||||
|
||||
public void setReserveOverflow(boolean reserveOverflow) {
|
||||
mReserveOverflow = reserveOverflow;
|
||||
mReserveOverflowSet = true;
|
||||
}
|
||||
|
||||
public void setItemLimit(int itemCount) {
|
||||
mMaxItems = itemCount;
|
||||
mMaxItemsSet = true;
|
||||
}
|
||||
|
||||
public void setExpandedActionViewsExclusive(boolean isExclusive) {
|
||||
mExpandedActionViewsExclusive = isExclusive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuView getMenuView(ViewGroup root) {
|
||||
MenuView result = super.getMenuView(root);
|
||||
((ActionMenuView) result).setPresenter(this);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getItemView(MenuItemImpl item, View convertView, ViewGroup parent) {
|
||||
View actionView = item.getActionView();
|
||||
if (actionView == null || item.hasCollapsibleActionView()) {
|
||||
if (!(convertView instanceof ActionMenuItemView)) {
|
||||
convertView = null;
|
||||
}
|
||||
actionView = super.getItemView(item, convertView, parent);
|
||||
}
|
||||
actionView.setVisibility(item.isActionViewExpanded() ? View.GONE : View.VISIBLE);
|
||||
|
||||
final ActionMenuView menuParent = (ActionMenuView) parent;
|
||||
final ViewGroup.LayoutParams lp = actionView.getLayoutParams();
|
||||
if (!menuParent.checkLayoutParams(lp)) {
|
||||
actionView.setLayoutParams(menuParent.generateLayoutParams(lp));
|
||||
}
|
||||
return actionView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItemView(MenuItemImpl item, MenuView.ItemView itemView) {
|
||||
itemView.initialize(item, 0);
|
||||
|
||||
final ActionMenuView menuView = (ActionMenuView) mMenuView;
|
||||
ActionMenuItemView actionItemView = (ActionMenuItemView) itemView;
|
||||
actionItemView.setItemInvoker(menuView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldIncludeItem(int childIndex, MenuItemImpl item) {
|
||||
return item.isActionButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateMenuView(boolean cleared) {
|
||||
super.updateMenuView(cleared);
|
||||
|
||||
if (mMenu != null) {
|
||||
final ArrayList<MenuItemImpl> actionItems = mMenu.getActionItems();
|
||||
final int count = actionItems.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final ActionProvider provider = actionItems.get(i).getActionProvider();
|
||||
if (provider != null) {
|
||||
provider.setSubUiVisibilityListener(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final ArrayList<MenuItemImpl> nonActionItems = mMenu != null ?
|
||||
mMenu.getNonActionItems() : null;
|
||||
|
||||
boolean hasOverflow = false;
|
||||
if (mReserveOverflow && nonActionItems != null) {
|
||||
final int count = nonActionItems.size();
|
||||
if (count == 1) {
|
||||
hasOverflow = !nonActionItems.get(0).isActionViewExpanded();
|
||||
} else {
|
||||
hasOverflow = count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasOverflow) {
|
||||
if (mOverflowButton == null) {
|
||||
mOverflowButton = new OverflowMenuButton(mSystemContext);
|
||||
}
|
||||
ViewGroup parent = (ViewGroup) mOverflowButton.getParent();
|
||||
if (parent != mMenuView) {
|
||||
if (parent != null) {
|
||||
parent.removeView(mOverflowButton);
|
||||
}
|
||||
ActionMenuView menuView = (ActionMenuView) mMenuView;
|
||||
menuView.addView(mOverflowButton, menuView.generateOverflowButtonLayoutParams());
|
||||
}
|
||||
} else if (mOverflowButton != null && mOverflowButton.getParent() == mMenuView) {
|
||||
((ViewGroup) mMenuView).removeView(mOverflowButton);
|
||||
}
|
||||
|
||||
((ActionMenuView) mMenuView).setOverflowReserved(mReserveOverflow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean filterLeftoverView(ViewGroup parent, int childIndex) {
|
||||
if (parent.getChildAt(childIndex) == mOverflowButton) return false;
|
||||
return super.filterLeftoverView(parent, childIndex);
|
||||
}
|
||||
|
||||
public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
|
||||
if (!subMenu.hasVisibleItems()) return false;
|
||||
|
||||
SubMenuBuilder topSubMenu = subMenu;
|
||||
while (topSubMenu.getParentMenu() != mMenu) {
|
||||
topSubMenu = (SubMenuBuilder) topSubMenu.getParentMenu();
|
||||
}
|
||||
View anchor = findViewForItem(topSubMenu.getItem());
|
||||
if (anchor == null) {
|
||||
if (mOverflowButton == null) return false;
|
||||
anchor = mOverflowButton;
|
||||
}
|
||||
|
||||
mOpenSubMenuId = subMenu.getItem().getItemId();
|
||||
mActionButtonPopup = new ActionButtonSubmenu(mContext, subMenu);
|
||||
mActionButtonPopup.setAnchorView(anchor);
|
||||
mActionButtonPopup.show();
|
||||
super.onSubMenuSelected(subMenu);
|
||||
return true;
|
||||
}
|
||||
|
||||
private View findViewForItem(MenuItem item) {
|
||||
final ViewGroup parent = (ViewGroup) mMenuView;
|
||||
if (parent == null) return null;
|
||||
|
||||
final int count = parent.getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = parent.getChildAt(i);
|
||||
if (child instanceof MenuView.ItemView &&
|
||||
((MenuView.ItemView) child).getItemData() == item) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the overflow menu if one is present.
|
||||
* @return true if the overflow menu was shown, false otherwise.
|
||||
*/
|
||||
public boolean showOverflowMenu() {
|
||||
if (mReserveOverflow && !isOverflowMenuShowing() && mMenu != null && mMenuView != null &&
|
||||
mPostedOpenRunnable == null) {
|
||||
OverflowPopup popup = new OverflowPopup(mContext, mMenu, mOverflowButton, true);
|
||||
mPostedOpenRunnable = new OpenOverflowRunnable(popup);
|
||||
// Post this for later; we might still need a layout for the anchor to be right.
|
||||
((View) mMenuView).post(mPostedOpenRunnable);
|
||||
|
||||
// ActionMenuPresenter uses null as a callback argument here
|
||||
// to indicate overflow is opening.
|
||||
super.onSubMenuSelected(null);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the overflow menu if it is currently showing.
|
||||
*
|
||||
* @return true if the overflow menu was hidden, false otherwise.
|
||||
*/
|
||||
public boolean hideOverflowMenu() {
|
||||
if (mPostedOpenRunnable != null && mMenuView != null) {
|
||||
((View) mMenuView).removeCallbacks(mPostedOpenRunnable);
|
||||
mPostedOpenRunnable = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
MenuPopupHelper popup = mOverflowPopup;
|
||||
if (popup != null) {
|
||||
popup.dismiss();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismiss all popup menus - overflow and submenus.
|
||||
* @return true if popups were dismissed, false otherwise. (This can be because none were open.)
|
||||
*/
|
||||
public boolean dismissPopupMenus() {
|
||||
boolean result = hideOverflowMenu();
|
||||
result |= hideSubMenus();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismiss all submenu popups.
|
||||
*
|
||||
* @return true if popups were dismissed, false otherwise. (This can be because none were open.)
|
||||
*/
|
||||
public boolean hideSubMenus() {
|
||||
if (mActionButtonPopup != null) {
|
||||
mActionButtonPopup.dismiss();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the overflow menu is currently showing
|
||||
*/
|
||||
public boolean isOverflowMenuShowing() {
|
||||
return mOverflowPopup != null && mOverflowPopup.isShowing();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if space has been reserved in the action menu for an overflow item.
|
||||
*/
|
||||
public boolean isOverflowReserved() {
|
||||
return mReserveOverflow;
|
||||
}
|
||||
|
||||
public boolean flagActionItems() {
|
||||
final ArrayList<MenuItemImpl> visibleItems = mMenu.getVisibleItems();
|
||||
final int itemsSize = visibleItems.size();
|
||||
int maxActions = mMaxItems;
|
||||
int widthLimit = mActionItemWidthLimit;
|
||||
final int querySpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
final ViewGroup parent = (ViewGroup) mMenuView;
|
||||
|
||||
int requiredItems = 0;
|
||||
int requestedItems = 0;
|
||||
int firstActionWidth = 0;
|
||||
boolean hasOverflow = false;
|
||||
for (int i = 0; i < itemsSize; i++) {
|
||||
MenuItemImpl item = visibleItems.get(i);
|
||||
if (item.requiresActionButton()) {
|
||||
requiredItems++;
|
||||
} else if (item.requestsActionButton()) {
|
||||
requestedItems++;
|
||||
} else {
|
||||
hasOverflow = true;
|
||||
}
|
||||
if (mExpandedActionViewsExclusive && item.isActionViewExpanded()) {
|
||||
// Overflow everything if we have an expanded action view and we're
|
||||
// space constrained.
|
||||
maxActions = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Reserve a spot for the overflow item if needed.
|
||||
if (mReserveOverflow &&
|
||||
(hasOverflow || requiredItems + requestedItems > maxActions)) {
|
||||
maxActions--;
|
||||
}
|
||||
maxActions -= requiredItems;
|
||||
|
||||
final SparseBooleanArray seenGroups = mActionButtonGroups;
|
||||
seenGroups.clear();
|
||||
|
||||
int cellSize = 0;
|
||||
int cellsRemaining = 0;
|
||||
if (mStrictWidthLimit) {
|
||||
cellsRemaining = widthLimit / mMinCellSize;
|
||||
final int cellSizeRemaining = widthLimit % mMinCellSize;
|
||||
cellSize = mMinCellSize + cellSizeRemaining / cellsRemaining;
|
||||
}
|
||||
|
||||
// Flag as many more requested items as will fit.
|
||||
for (int i = 0; i < itemsSize; i++) {
|
||||
MenuItemImpl item = visibleItems.get(i);
|
||||
|
||||
if (item.requiresActionButton()) {
|
||||
View v = getItemView(item, mScrapActionButtonView, parent);
|
||||
if (mScrapActionButtonView == null) {
|
||||
mScrapActionButtonView = v;
|
||||
}
|
||||
if (mStrictWidthLimit) {
|
||||
cellsRemaining -= ActionMenuView.measureChildForCells(v,
|
||||
cellSize, cellsRemaining, querySpec, 0);
|
||||
} else {
|
||||
v.measure(querySpec, querySpec);
|
||||
}
|
||||
final int measuredWidth = v.getMeasuredWidth();
|
||||
widthLimit -= measuredWidth;
|
||||
if (firstActionWidth == 0) {
|
||||
firstActionWidth = measuredWidth;
|
||||
}
|
||||
final int groupId = item.getGroupId();
|
||||
if (groupId != 0) {
|
||||
seenGroups.put(groupId, true);
|
||||
}
|
||||
item.setIsActionButton(true);
|
||||
} else if (item.requestsActionButton()) {
|
||||
// Items in a group with other items that already have an action slot
|
||||
// can break the max actions rule, but not the width limit.
|
||||
final int groupId = item.getGroupId();
|
||||
final boolean inGroup = seenGroups.get(groupId);
|
||||
boolean isAction = (maxActions > 0 || inGroup) && widthLimit > 0 &&
|
||||
(!mStrictWidthLimit || cellsRemaining > 0);
|
||||
|
||||
if (isAction) {
|
||||
View v = getItemView(item, mScrapActionButtonView, parent);
|
||||
if (mScrapActionButtonView == null) {
|
||||
mScrapActionButtonView = v;
|
||||
}
|
||||
if (mStrictWidthLimit) {
|
||||
final int cells = ActionMenuView.measureChildForCells(v,
|
||||
cellSize, cellsRemaining, querySpec, 0);
|
||||
cellsRemaining -= cells;
|
||||
if (cells == 0) {
|
||||
isAction = false;
|
||||
}
|
||||
} else {
|
||||
v.measure(querySpec, querySpec);
|
||||
}
|
||||
final int measuredWidth = v.getMeasuredWidth();
|
||||
widthLimit -= measuredWidth;
|
||||
if (firstActionWidth == 0) {
|
||||
firstActionWidth = measuredWidth;
|
||||
}
|
||||
|
||||
if (mStrictWidthLimit) {
|
||||
isAction &= widthLimit >= 0;
|
||||
} else {
|
||||
// Did this push the entire first item past the limit?
|
||||
isAction &= widthLimit + firstActionWidth > 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (isAction && groupId != 0) {
|
||||
seenGroups.put(groupId, true);
|
||||
} else if (inGroup) {
|
||||
// We broke the width limit. Demote the whole group, they all overflow now.
|
||||
seenGroups.put(groupId, false);
|
||||
for (int j = 0; j < i; j++) {
|
||||
MenuItemImpl areYouMyGroupie = visibleItems.get(j);
|
||||
if (areYouMyGroupie.getGroupId() == groupId) {
|
||||
// Give back the action slot
|
||||
if (areYouMyGroupie.isActionButton()) maxActions++;
|
||||
areYouMyGroupie.setIsActionButton(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isAction) maxActions--;
|
||||
|
||||
item.setIsActionButton(isAction);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
|
||||
dismissPopupMenus();
|
||||
super.onCloseMenu(menu, allMenusAreClosing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parcelable onSaveInstanceState() {
|
||||
SavedState state = new SavedState();
|
||||
state.openSubMenuId = mOpenSubMenuId;
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreInstanceState(Parcelable state) {
|
||||
SavedState saved = (SavedState) state;
|
||||
if (saved.openSubMenuId > 0) {
|
||||
MenuItem item = mMenu.findItem(saved.openSubMenuId);
|
||||
if (item != null) {
|
||||
SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
|
||||
onSubMenuSelected(subMenu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSubUiVisibilityChanged(boolean isVisible) {
|
||||
if (isVisible) {
|
||||
// Not a submenu, but treat it like one.
|
||||
super.onSubMenuSelected(null);
|
||||
} else {
|
||||
mMenu.close(false);
|
||||
}
|
||||
}
|
||||
|
||||
private static class SavedState implements Parcelable {
|
||||
public int openSubMenuId;
|
||||
|
||||
SavedState() {
|
||||
}
|
||||
|
||||
SavedState(Parcel in) {
|
||||
openSubMenuId = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(openSubMenuId);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static final Parcelable.Creator<SavedState> CREATOR
|
||||
= new Parcelable.Creator<SavedState>() {
|
||||
public SavedState createFromParcel(Parcel in) {
|
||||
return new SavedState(in);
|
||||
}
|
||||
|
||||
public SavedState[] newArray(int size) {
|
||||
return new SavedState[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private class OverflowMenuButton extends ImageButton implements ActionMenuChildView, View_HasStateListenerSupport {
|
||||
private final Set<View_OnAttachStateChangeListener> mListeners = new HashSet<View_OnAttachStateChangeListener>();
|
||||
|
||||
public OverflowMenuButton(Context context) {
|
||||
super(context, null, R.attr.actionOverflowButtonStyle);
|
||||
|
||||
setClickable(true);
|
||||
setFocusable(true);
|
||||
setVisibility(VISIBLE);
|
||||
setEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performClick() {
|
||||
if (super.performClick()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
playSoundEffect(SoundEffectConstants.CLICK);
|
||||
showOverflowMenu();
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean needsDividerBefore() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean needsDividerAfter() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
for (View_OnAttachStateChangeListener listener : mListeners) {
|
||||
listener.onViewAttachedToWindow(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
for (View_OnAttachStateChangeListener listener : mListeners) {
|
||||
listener.onViewDetachedFromWindow(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOnAttachStateChangeListener(View_OnAttachStateChangeListener listener) {
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeOnAttachStateChangeListener(View_OnAttachStateChangeListener listener) {
|
||||
mListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
private class OverflowPopup extends MenuPopupHelper {
|
||||
public OverflowPopup(Context context, MenuBuilder menu, View anchorView,
|
||||
boolean overflowOnly) {
|
||||
super(context, menu, anchorView, overflowOnly);
|
||||
setCallback(mPopupPresenterCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss() {
|
||||
super.onDismiss();
|
||||
mMenu.close();
|
||||
mOverflowPopup = null;
|
||||
}
|
||||
}
|
||||
|
||||
private class ActionButtonSubmenu extends MenuPopupHelper {
|
||||
//UNUSED private SubMenuBuilder mSubMenu;
|
||||
|
||||
public ActionButtonSubmenu(Context context, SubMenuBuilder subMenu) {
|
||||
super(context, subMenu);
|
||||
//UNUSED mSubMenu = subMenu;
|
||||
|
||||
MenuItemImpl item = (MenuItemImpl) subMenu.getItem();
|
||||
if (!item.isActionButton()) {
|
||||
// Give a reasonable anchor to nested submenus.
|
||||
setAnchorView(mOverflowButton == null ? (View) mMenuView : mOverflowButton);
|
||||
}
|
||||
|
||||
setCallback(mPopupPresenterCallback);
|
||||
|
||||
boolean preserveIconSpacing = false;
|
||||
final int count = subMenu.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
MenuItem childItem = subMenu.getItem(i);
|
||||
if (childItem.isVisible() && childItem.getIcon() != null) {
|
||||
preserveIconSpacing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
setForceShowIcon(preserveIconSpacing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss() {
|
||||
super.onDismiss();
|
||||
mActionButtonPopup = null;
|
||||
mOpenSubMenuId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private class PopupPresenterCallback implements MenuPresenter.Callback {
|
||||
|
||||
@Override
|
||||
public boolean onOpenSubMenu(MenuBuilder subMenu) {
|
||||
if (subMenu == null) return false;
|
||||
|
||||
mOpenSubMenuId = ((SubMenuBuilder) subMenu).getItem().getItemId();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
|
||||
if (menu instanceof SubMenuBuilder) {
|
||||
((SubMenuBuilder) menu).getRootMenu().close(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class OpenOverflowRunnable implements Runnable {
|
||||
private OverflowPopup mPopup;
|
||||
|
||||
public OpenOverflowRunnable(OverflowPopup popup) {
|
||||
mPopup = popup;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
mMenu.changeMenuMode();
|
||||
final View menuView = (View) mMenuView;
|
||||
if (menuView != null && menuView.getWindowToken() != null && mPopup.tryShow()) {
|
||||
mOverflowPopup = mPopup;
|
||||
}
|
||||
mPostedOpenRunnable = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,572 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* 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.menu;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Canvas;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.widget.LinearLayout;
|
||||
import com.actionbarsherlock.internal.widget.IcsLinearLayout;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ActionMenuView extends IcsLinearLayout implements MenuBuilder.ItemInvoker, MenuView {
|
||||
//UNUSED private static final String TAG = "ActionMenuView";
|
||||
private static final boolean IS_FROYO = Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO;
|
||||
|
||||
static final int MIN_CELL_SIZE = 56; // dips
|
||||
static final int GENERATED_ITEM_PADDING = 4; // dips
|
||||
|
||||
private MenuBuilder mMenu;
|
||||
|
||||
private boolean mReserveOverflow;
|
||||
private ActionMenuPresenter mPresenter;
|
||||
private boolean mFormatItems;
|
||||
private int mFormatItemsWidth;
|
||||
private int mMinCellSize;
|
||||
private int mGeneratedItemPadding;
|
||||
//UNUSED private int mMeasuredExtraWidth;
|
||||
|
||||
private boolean mFirst = true;
|
||||
|
||||
public ActionMenuView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public ActionMenuView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
setBaselineAligned(false);
|
||||
final float density = context.getResources().getDisplayMetrics().density;
|
||||
mMinCellSize = (int) (MIN_CELL_SIZE * density);
|
||||
mGeneratedItemPadding = (int) (GENERATED_ITEM_PADDING * density);
|
||||
}
|
||||
|
||||
public void setPresenter(ActionMenuPresenter presenter) {
|
||||
mPresenter = presenter;
|
||||
}
|
||||
|
||||
public boolean isExpandedFormat() {
|
||||
return mFormatItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
if (IS_FROYO) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
}
|
||||
mPresenter.updateMenuView(false);
|
||||
|
||||
if (mPresenter != null && mPresenter.isOverflowMenuShowing()) {
|
||||
mPresenter.hideOverflowMenu();
|
||||
mPresenter.showOverflowMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
//Need to trigger a relayout since we may have been added extremely
|
||||
//late in the initial rendering (e.g., when contained in a ViewPager).
|
||||
//See: https://github.com/JakeWharton/ActionBarSherlock/issues/272
|
||||
if (!IS_FROYO && mFirst) {
|
||||
mFirst = false;
|
||||
requestLayout();
|
||||
return;
|
||||
}
|
||||
super.onDraw(canvas);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
// If we've been given an exact size to match, apply special formatting during layout.
|
||||
final boolean wasFormatted = mFormatItems;
|
||||
mFormatItems = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY;
|
||||
|
||||
if (wasFormatted != mFormatItems) {
|
||||
mFormatItemsWidth = 0; // Reset this when switching modes
|
||||
}
|
||||
|
||||
// Special formatting can change whether items can fit as action buttons.
|
||||
// Kick the menu and update presenters when this changes.
|
||||
final int widthSize = MeasureSpec.getMode(widthMeasureSpec);
|
||||
if (mFormatItems && mMenu != null && widthSize != mFormatItemsWidth) {
|
||||
mFormatItemsWidth = widthSize;
|
||||
mMenu.onItemsChanged(true);
|
||||
}
|
||||
|
||||
if (mFormatItems) {
|
||||
onMeasureExactFormat(widthMeasureSpec, heightMeasureSpec);
|
||||
} else {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
}
|
||||
|
||||
private void onMeasureExactFormat(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
// We already know the width mode is EXACTLY if we're here.
|
||||
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
|
||||
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
|
||||
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
|
||||
|
||||
final int widthPadding = getPaddingLeft() + getPaddingRight();
|
||||
final int heightPadding = getPaddingTop() + getPaddingBottom();
|
||||
|
||||
widthSize -= widthPadding;
|
||||
|
||||
// Divide the view into cells.
|
||||
final int cellCount = widthSize / mMinCellSize;
|
||||
final int cellSizeRemaining = widthSize % mMinCellSize;
|
||||
|
||||
if (cellCount == 0) {
|
||||
// Give up, nothing fits.
|
||||
setMeasuredDimension(widthSize, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
final int cellSize = mMinCellSize + cellSizeRemaining / cellCount;
|
||||
|
||||
int cellsRemaining = cellCount;
|
||||
int maxChildHeight = 0;
|
||||
int maxCellsUsed = 0;
|
||||
int expandableItemCount = 0;
|
||||
int visibleItemCount = 0;
|
||||
boolean hasOverflow = false;
|
||||
|
||||
// This is used as a bitfield to locate the smallest items present. Assumes childCount < 64.
|
||||
long smallestItemsAt = 0;
|
||||
|
||||
final int childCount = getChildCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() == GONE) continue;
|
||||
|
||||
final boolean isGeneratedItem = child instanceof ActionMenuItemView;
|
||||
visibleItemCount++;
|
||||
|
||||
if (isGeneratedItem) {
|
||||
// Reset padding for generated menu item views; it may change below
|
||||
// and views are recycled.
|
||||
child.setPadding(mGeneratedItemPadding, 0, mGeneratedItemPadding, 0);
|
||||
}
|
||||
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
lp.expanded = false;
|
||||
lp.extraPixels = 0;
|
||||
lp.cellsUsed = 0;
|
||||
lp.expandable = false;
|
||||
lp.leftMargin = 0;
|
||||
lp.rightMargin = 0;
|
||||
lp.preventEdgeOffset = isGeneratedItem && ((ActionMenuItemView) child).hasText();
|
||||
|
||||
// Overflow always gets 1 cell. No more, no less.
|
||||
final int cellsAvailable = lp.isOverflowButton ? 1 : cellsRemaining;
|
||||
|
||||
final int cellsUsed = measureChildForCells(child, cellSize, cellsAvailable,
|
||||
heightMeasureSpec, heightPadding);
|
||||
|
||||
maxCellsUsed = Math.max(maxCellsUsed, cellsUsed);
|
||||
if (lp.expandable) expandableItemCount++;
|
||||
if (lp.isOverflowButton) hasOverflow = true;
|
||||
|
||||
cellsRemaining -= cellsUsed;
|
||||
maxChildHeight = Math.max(maxChildHeight, child.getMeasuredHeight());
|
||||
if (cellsUsed == 1) smallestItemsAt |= (1 << i);
|
||||
}
|
||||
|
||||
// When we have overflow and a single expanded (text) item, we want to try centering it
|
||||
// visually in the available space even though overflow consumes some of it.
|
||||
final boolean centerSingleExpandedItem = hasOverflow && visibleItemCount == 2;
|
||||
|
||||
// Divide space for remaining cells if we have items that can expand.
|
||||
// Try distributing whole leftover cells to smaller items first.
|
||||
|
||||
boolean needsExpansion = false;
|
||||
while (expandableItemCount > 0 && cellsRemaining > 0) {
|
||||
int minCells = Integer.MAX_VALUE;
|
||||
long minCellsAt = 0; // Bit locations are indices of relevant child views
|
||||
int minCellsItemCount = 0;
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = getChildAt(i);
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
|
||||
// Don't try to expand items that shouldn't.
|
||||
if (!lp.expandable) continue;
|
||||
|
||||
// Mark indices of children that can receive an extra cell.
|
||||
if (lp.cellsUsed < minCells) {
|
||||
minCells = lp.cellsUsed;
|
||||
minCellsAt = 1 << i;
|
||||
minCellsItemCount = 1;
|
||||
} else if (lp.cellsUsed == minCells) {
|
||||
minCellsAt |= 1 << i;
|
||||
minCellsItemCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Items that get expanded will always be in the set of smallest items when we're done.
|
||||
smallestItemsAt |= minCellsAt;
|
||||
|
||||
if (minCellsItemCount > cellsRemaining) break; // Couldn't expand anything evenly. Stop.
|
||||
|
||||
// We have enough cells, all minimum size items will be incremented.
|
||||
minCells++;
|
||||
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = getChildAt(i);
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
if ((minCellsAt & (1 << i)) == 0) {
|
||||
// If this item is already at our small item count, mark it for later.
|
||||
if (lp.cellsUsed == minCells) smallestItemsAt |= 1 << i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (centerSingleExpandedItem && lp.preventEdgeOffset && cellsRemaining == 1) {
|
||||
// Add padding to this item such that it centers.
|
||||
child.setPadding(mGeneratedItemPadding + cellSize, 0, mGeneratedItemPadding, 0);
|
||||
}
|
||||
lp.cellsUsed++;
|
||||
lp.expanded = true;
|
||||
cellsRemaining--;
|
||||
}
|
||||
|
||||
needsExpansion = true;
|
||||
}
|
||||
|
||||
// Divide any space left that wouldn't divide along cell boundaries
|
||||
// evenly among the smallest items
|
||||
|
||||
final boolean singleItem = !hasOverflow && visibleItemCount == 1;
|
||||
if (cellsRemaining > 0 && smallestItemsAt != 0 &&
|
||||
(cellsRemaining < visibleItemCount - 1 || singleItem || maxCellsUsed > 1)) {
|
||||
float expandCount = Long.bitCount(smallestItemsAt);
|
||||
|
||||
if (!singleItem) {
|
||||
// The items at the far edges may only expand by half in order to pin to either side.
|
||||
if ((smallestItemsAt & 1) != 0) {
|
||||
LayoutParams lp = (LayoutParams) getChildAt(0).getLayoutParams();
|
||||
if (!lp.preventEdgeOffset) expandCount -= 0.5f;
|
||||
}
|
||||
if ((smallestItemsAt & (1 << (childCount - 1))) != 0) {
|
||||
LayoutParams lp = ((LayoutParams) getChildAt(childCount - 1).getLayoutParams());
|
||||
if (!lp.preventEdgeOffset) expandCount -= 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
final int extraPixels = expandCount > 0 ?
|
||||
(int) (cellsRemaining * cellSize / expandCount) : 0;
|
||||
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
if ((smallestItemsAt & (1 << i)) == 0) continue;
|
||||
|
||||
final View child = getChildAt(i);
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
if (child instanceof ActionMenuItemView) {
|
||||
// If this is one of our views, expand and measure at the larger size.
|
||||
lp.extraPixels = extraPixels;
|
||||
lp.expanded = true;
|
||||
if (i == 0 && !lp.preventEdgeOffset) {
|
||||
// First item gets part of its new padding pushed out of sight.
|
||||
// The last item will get this implicitly from layout.
|
||||
lp.leftMargin = -extraPixels / 2;
|
||||
}
|
||||
needsExpansion = true;
|
||||
} else if (lp.isOverflowButton) {
|
||||
lp.extraPixels = extraPixels;
|
||||
lp.expanded = true;
|
||||
lp.rightMargin = -extraPixels / 2;
|
||||
needsExpansion = true;
|
||||
} else {
|
||||
// If we don't know what it is, give it some margins instead
|
||||
// and let it center within its space. We still want to pin
|
||||
// against the edges.
|
||||
if (i != 0) {
|
||||
lp.leftMargin = extraPixels / 2;
|
||||
}
|
||||
if (i != childCount - 1) {
|
||||
lp.rightMargin = extraPixels / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cellsRemaining = 0;
|
||||
}
|
||||
|
||||
// Remeasure any items that have had extra space allocated to them.
|
||||
if (needsExpansion) {
|
||||
int heightSpec = MeasureSpec.makeMeasureSpec(heightSize - heightPadding, heightMode);
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = getChildAt(i);
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
|
||||
if (!lp.expanded) continue;
|
||||
|
||||
final int width = lp.cellsUsed * cellSize + lp.extraPixels;
|
||||
child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), heightSpec);
|
||||
}
|
||||
}
|
||||
|
||||
if (heightMode != MeasureSpec.EXACTLY) {
|
||||
heightSize = maxChildHeight;
|
||||
}
|
||||
|
||||
setMeasuredDimension(widthSize, heightSize);
|
||||
//UNUSED mMeasuredExtraWidth = cellsRemaining * cellSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Measure a child view to fit within cell-based formatting. The child's width
|
||||
* will be measured to a whole multiple of cellSize.
|
||||
*
|
||||
* <p>Sets the expandable and cellsUsed fields of LayoutParams.
|
||||
*
|
||||
* @param child Child to measure
|
||||
* @param cellSize Size of one cell
|
||||
* @param cellsRemaining Number of cells remaining that this view can expand to fill
|
||||
* @param parentHeightMeasureSpec MeasureSpec used by the parent view
|
||||
* @param parentHeightPadding Padding present in the parent view
|
||||
* @return Number of cells this child was measured to occupy
|
||||
*/
|
||||
static int measureChildForCells(View child, int cellSize, int cellsRemaining,
|
||||
int parentHeightMeasureSpec, int parentHeightPadding) {
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
|
||||
final int childHeightSize = MeasureSpec.getSize(parentHeightMeasureSpec) -
|
||||
parentHeightPadding;
|
||||
final int childHeightMode = MeasureSpec.getMode(parentHeightMeasureSpec);
|
||||
final int childHeightSpec = MeasureSpec.makeMeasureSpec(childHeightSize, childHeightMode);
|
||||
|
||||
int cellsUsed = 0;
|
||||
if (cellsRemaining > 0) {
|
||||
final int childWidthSpec = MeasureSpec.makeMeasureSpec(
|
||||
cellSize * cellsRemaining, MeasureSpec.AT_MOST);
|
||||
child.measure(childWidthSpec, childHeightSpec);
|
||||
|
||||
final int measuredWidth = child.getMeasuredWidth();
|
||||
cellsUsed = measuredWidth / cellSize;
|
||||
if (measuredWidth % cellSize != 0) cellsUsed++;
|
||||
}
|
||||
|
||||
final ActionMenuItemView itemView = child instanceof ActionMenuItemView ?
|
||||
(ActionMenuItemView) child : null;
|
||||
final boolean expandable = !lp.isOverflowButton && itemView != null && itemView.hasText();
|
||||
lp.expandable = expandable;
|
||||
|
||||
lp.cellsUsed = cellsUsed;
|
||||
final int targetWidth = cellsUsed * cellSize;
|
||||
child.measure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY),
|
||||
childHeightSpec);
|
||||
return cellsUsed;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
if (!mFormatItems) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
return;
|
||||
}
|
||||
|
||||
final int childCount = getChildCount();
|
||||
final int midVertical = (top + bottom) / 2;
|
||||
final int dividerWidth = 0;//getDividerWidth();
|
||||
int overflowWidth = 0;
|
||||
//UNUSED int nonOverflowWidth = 0;
|
||||
int nonOverflowCount = 0;
|
||||
int widthRemaining = right - left - getPaddingRight() - getPaddingLeft();
|
||||
boolean hasOverflow = false;
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View v = getChildAt(i);
|
||||
if (v.getVisibility() == GONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LayoutParams p = (LayoutParams) v.getLayoutParams();
|
||||
if (p.isOverflowButton) {
|
||||
overflowWidth = v.getMeasuredWidth();
|
||||
if (hasDividerBeforeChildAt(i)) {
|
||||
overflowWidth += dividerWidth;
|
||||
}
|
||||
|
||||
int height = v.getMeasuredHeight();
|
||||
int r = getWidth() - getPaddingRight() - p.rightMargin;
|
||||
int l = r - overflowWidth;
|
||||
int t = midVertical - (height / 2);
|
||||
int b = t + height;
|
||||
v.layout(l, t, r, b);
|
||||
|
||||
widthRemaining -= overflowWidth;
|
||||
hasOverflow = true;
|
||||
} else {
|
||||
final int size = v.getMeasuredWidth() + p.leftMargin + p.rightMargin;
|
||||
//UNUSED nonOverflowWidth += size;
|
||||
widthRemaining -= size;
|
||||
if (hasDividerBeforeChildAt(i)) {
|
||||
//UNUSED nonOverflowWidth += dividerWidth;
|
||||
}
|
||||
nonOverflowCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (childCount == 1 && !hasOverflow) {
|
||||
// Center a single child
|
||||
final View v = getChildAt(0);
|
||||
final int width = v.getMeasuredWidth();
|
||||
final int height = v.getMeasuredHeight();
|
||||
final int midHorizontal = (right - left) / 2;
|
||||
final int l = midHorizontal - width / 2;
|
||||
final int t = midVertical - height / 2;
|
||||
v.layout(l, t, l + width, t + height);
|
||||
return;
|
||||
}
|
||||
|
||||
final int spacerCount = nonOverflowCount - (hasOverflow ? 0 : 1);
|
||||
final int spacerSize = Math.max(0, spacerCount > 0 ? widthRemaining / spacerCount : 0);
|
||||
|
||||
int startLeft = getPaddingLeft();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View v = getChildAt(i);
|
||||
final LayoutParams lp = (LayoutParams) v.getLayoutParams();
|
||||
if (v.getVisibility() == GONE || lp.isOverflowButton) {
|
||||
continue;
|
||||
}
|
||||
|
||||
startLeft += lp.leftMargin;
|
||||
int width = v.getMeasuredWidth();
|
||||
int height = v.getMeasuredHeight();
|
||||
int t = midVertical - height / 2;
|
||||
v.layout(startLeft, t, startLeft + width, t + height);
|
||||
startLeft += width + lp.rightMargin + spacerSize;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
mPresenter.dismissPopupMenus();
|
||||
}
|
||||
|
||||
public boolean isOverflowReserved() {
|
||||
return mReserveOverflow;
|
||||
}
|
||||
|
||||
public void setOverflowReserved(boolean reserveOverflow) {
|
||||
mReserveOverflow = reserveOverflow;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LayoutParams generateDefaultLayoutParams() {
|
||||
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
|
||||
LayoutParams.WRAP_CONTENT);
|
||||
params.gravity = Gravity.CENTER_VERTICAL;
|
||||
return params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LayoutParams generateLayoutParams(AttributeSet attrs) {
|
||||
return new LayoutParams(getContext(), attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
|
||||
if (p instanceof LayoutParams) {
|
||||
LayoutParams result = new LayoutParams((LayoutParams) p);
|
||||
if (result.gravity <= Gravity.NO_GRAVITY) {
|
||||
result.gravity = Gravity.CENTER_VERTICAL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return generateDefaultLayoutParams();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
|
||||
return p != null && p instanceof LayoutParams;
|
||||
}
|
||||
|
||||
public LayoutParams generateOverflowButtonLayoutParams() {
|
||||
LayoutParams result = generateDefaultLayoutParams();
|
||||
result.isOverflowButton = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean invokeItem(MenuItemImpl item) {
|
||||
return mMenu.performItemAction(item, 0);
|
||||
}
|
||||
|
||||
public int getWindowAnimations() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void initialize(MenuBuilder menu) {
|
||||
mMenu = menu;
|
||||
}
|
||||
|
||||
//@Override
|
||||
protected boolean hasDividerBeforeChildAt(int childIndex) {
|
||||
final View childBefore = getChildAt(childIndex - 1);
|
||||
final View child = getChildAt(childIndex);
|
||||
boolean result = false;
|
||||
if (childIndex < getChildCount() && childBefore instanceof ActionMenuChildView) {
|
||||
result |= ((ActionMenuChildView) childBefore).needsDividerAfter();
|
||||
}
|
||||
if (childIndex > 0 && child instanceof ActionMenuChildView) {
|
||||
result |= ((ActionMenuChildView) child).needsDividerBefore();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public interface ActionMenuChildView {
|
||||
public boolean needsDividerBefore();
|
||||
public boolean needsDividerAfter();
|
||||
}
|
||||
|
||||
public static class LayoutParams extends LinearLayout.LayoutParams {
|
||||
public boolean isOverflowButton;
|
||||
public int cellsUsed;
|
||||
public int extraPixels;
|
||||
public boolean expandable;
|
||||
public boolean preventEdgeOffset;
|
||||
|
||||
public boolean expanded;
|
||||
|
||||
public LayoutParams(Context c, AttributeSet attrs) {
|
||||
super(c, attrs);
|
||||
}
|
||||
|
||||
public LayoutParams(LayoutParams other) {
|
||||
super((LinearLayout.LayoutParams) other);
|
||||
isOverflowButton = other.isOverflowButton;
|
||||
}
|
||||
|
||||
public LayoutParams(int width, int height) {
|
||||
super(width, height);
|
||||
isOverflowButton = false;
|
||||
}
|
||||
|
||||
public LayoutParams(int width, int height, boolean isOverflowButton) {
|
||||
super(width, height);
|
||||
this.isOverflowButton = isOverflowButton;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* 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.menu;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* Base class for MenuPresenters that have a consistent container view and item
|
||||
* views. Behaves similarly to an AdapterView in that existing item views will
|
||||
* be reused if possible when items change.
|
||||
*/
|
||||
public abstract class BaseMenuPresenter implements MenuPresenter {
|
||||
private static final boolean IS_HONEYCOMB = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
|
||||
|
||||
protected Context mSystemContext;
|
||||
protected Context mContext;
|
||||
protected MenuBuilder mMenu;
|
||||
protected LayoutInflater mSystemInflater;
|
||||
protected LayoutInflater mInflater;
|
||||
private Callback mCallback;
|
||||
|
||||
private int mMenuLayoutRes;
|
||||
private int mItemLayoutRes;
|
||||
|
||||
protected MenuView mMenuView;
|
||||
|
||||
private int mId;
|
||||
|
||||
/**
|
||||
* Construct a new BaseMenuPresenter.
|
||||
*
|
||||
* @param context Context for generating system-supplied views
|
||||
* @param menuLayoutRes Layout resource ID for the menu container view
|
||||
* @param itemLayoutRes Layout resource ID for a single item view
|
||||
*/
|
||||
public BaseMenuPresenter(Context context, int menuLayoutRes, int itemLayoutRes) {
|
||||
mSystemContext = context;
|
||||
mSystemInflater = LayoutInflater.from(context);
|
||||
mMenuLayoutRes = menuLayoutRes;
|
||||
mItemLayoutRes = itemLayoutRes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initForMenu(Context context, MenuBuilder menu) {
|
||||
mContext = context;
|
||||
mInflater = LayoutInflater.from(mContext);
|
||||
mMenu = menu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuView getMenuView(ViewGroup root) {
|
||||
if (mMenuView == null) {
|
||||
mMenuView = (MenuView) mSystemInflater.inflate(mMenuLayoutRes, root, false);
|
||||
mMenuView.initialize(mMenu);
|
||||
updateMenuView(true);
|
||||
}
|
||||
|
||||
return mMenuView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reuses item views when it can
|
||||
*/
|
||||
public void updateMenuView(boolean cleared) {
|
||||
final ViewGroup parent = (ViewGroup) mMenuView;
|
||||
if (parent == null) return;
|
||||
|
||||
int childIndex = 0;
|
||||
if (mMenu != null) {
|
||||
mMenu.flagActionItems();
|
||||
ArrayList<MenuItemImpl> visibleItems = mMenu.getVisibleItems();
|
||||
final int itemCount = visibleItems.size();
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
MenuItemImpl item = visibleItems.get(i);
|
||||
if (shouldIncludeItem(childIndex, item)) {
|
||||
final View convertView = parent.getChildAt(childIndex);
|
||||
final MenuItemImpl oldItem = convertView instanceof MenuView.ItemView ?
|
||||
((MenuView.ItemView) convertView).getItemData() : null;
|
||||
final View itemView = getItemView(item, convertView, parent);
|
||||
if (item != oldItem) {
|
||||
// Don't let old states linger with new data.
|
||||
itemView.setPressed(false);
|
||||
if (IS_HONEYCOMB) itemView.jumpDrawablesToCurrentState();
|
||||
}
|
||||
if (itemView != convertView) {
|
||||
addItemView(itemView, childIndex);
|
||||
}
|
||||
childIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove leftover views.
|
||||
while (childIndex < parent.getChildCount()) {
|
||||
if (!filterLeftoverView(parent, childIndex)) {
|
||||
childIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an item view at the given index.
|
||||
*
|
||||
* @param itemView View to add
|
||||
* @param childIndex Index within the parent to insert at
|
||||
*/
|
||||
protected void addItemView(View itemView, int childIndex) {
|
||||
final ViewGroup currentParent = (ViewGroup) itemView.getParent();
|
||||
if (currentParent != null) {
|
||||
currentParent.removeView(itemView);
|
||||
}
|
||||
((ViewGroup) mMenuView).addView(itemView, childIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the child view at index and remove it if appropriate.
|
||||
* @param parent Parent to filter from
|
||||
* @param childIndex Index to filter
|
||||
* @return true if the child view at index was removed
|
||||
*/
|
||||
protected boolean filterLeftoverView(ViewGroup parent, int childIndex) {
|
||||
parent.removeViewAt(childIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setCallback(Callback cb) {
|
||||
mCallback = cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new item view that can be re-bound to other item data later.
|
||||
*
|
||||
* @return The new item view
|
||||
*/
|
||||
public MenuView.ItemView createItemView(ViewGroup parent) {
|
||||
return (MenuView.ItemView) mSystemInflater.inflate(mItemLayoutRes, parent, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an item view for use. See AdapterView for the basic idea at work here.
|
||||
* This may require creating a new item view, but well-behaved implementations will
|
||||
* re-use the view passed as convertView if present. The returned view will be populated
|
||||
* with data from the item parameter.
|
||||
*
|
||||
* @param item Item to present
|
||||
* @param convertView Existing view to reuse
|
||||
* @param parent Intended parent view - use for inflation.
|
||||
* @return View that presents the requested menu item
|
||||
*/
|
||||
public View getItemView(MenuItemImpl item, View convertView, ViewGroup parent) {
|
||||
MenuView.ItemView itemView;
|
||||
if (convertView instanceof MenuView.ItemView) {
|
||||
itemView = (MenuView.ItemView) convertView;
|
||||
} else {
|
||||
itemView = createItemView(parent);
|
||||
}
|
||||
bindItemView(item, itemView);
|
||||
return (View) itemView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind item data to an existing item view.
|
||||
*
|
||||
* @param item Item to bind
|
||||
* @param itemView View to populate with item data
|
||||
*/
|
||||
public abstract void bindItemView(MenuItemImpl item, MenuView.ItemView itemView);
|
||||
|
||||
/**
|
||||
* Filter item by child index and item data.
|
||||
*
|
||||
* @param childIndex Indended presentation index of this item
|
||||
* @param item Item to present
|
||||
* @return true if this item should be included in this menu presentation; false otherwise
|
||||
*/
|
||||
public boolean shouldIncludeItem(int childIndex, MenuItemImpl item) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
|
||||
if (mCallback != null) {
|
||||
mCallback.onCloseMenu(menu, allMenusAreClosing);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onSubMenuSelected(SubMenuBuilder menu) {
|
||||
if (mCallback != null) {
|
||||
return mCallback.onOpenSubMenu(menu);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean flagActionItems() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
mId = id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* 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.menu;
|
||||
|
||||
import com.actionbarsherlock.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* The item view for each item in the ListView-based MenuViews.
|
||||
*/
|
||||
public class ListMenuItemView extends LinearLayout implements MenuView.ItemView {
|
||||
private MenuItemImpl mItemData;
|
||||
|
||||
private ImageView mIconView;
|
||||
private RadioButton mRadioButton;
|
||||
private TextView mTitleView;
|
||||
private CheckBox mCheckBox;
|
||||
private TextView mShortcutView;
|
||||
|
||||
private Drawable mBackground;
|
||||
private int mTextAppearance;
|
||||
private Context mTextAppearanceContext;
|
||||
private boolean mPreserveIconSpacing;
|
||||
|
||||
//UNUSED private int mMenuType;
|
||||
|
||||
private LayoutInflater mInflater;
|
||||
|
||||
private boolean mForceShowIcon;
|
||||
|
||||
final Context mContext;
|
||||
|
||||
public ListMenuItemView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs);
|
||||
mContext = context;
|
||||
|
||||
TypedArray a =
|
||||
context.obtainStyledAttributes(
|
||||
attrs, R.styleable.SherlockMenuView, defStyle, 0);
|
||||
|
||||
mBackground = a.getDrawable(R.styleable.SherlockMenuView_itemBackground);
|
||||
mTextAppearance = a.getResourceId(R.styleable.
|
||||
SherlockMenuView_itemTextAppearance, -1);
|
||||
mPreserveIconSpacing = a.getBoolean(
|
||||
R.styleable.SherlockMenuView_preserveIconSpacing, false);
|
||||
mTextAppearanceContext = context;
|
||||
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
public ListMenuItemView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
||||
setBackgroundDrawable(mBackground);
|
||||
|
||||
mTitleView = (TextView) findViewById(R.id.abs__title);
|
||||
if (mTextAppearance != -1) {
|
||||
mTitleView.setTextAppearance(mTextAppearanceContext,
|
||||
mTextAppearance);
|
||||
}
|
||||
|
||||
mShortcutView = (TextView) findViewById(R.id.abs__shortcut);
|
||||
}
|
||||
|
||||
public void initialize(MenuItemImpl itemData, int menuType) {
|
||||
mItemData = itemData;
|
||||
//UNUSED mMenuType = menuType;
|
||||
|
||||
setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE);
|
||||
|
||||
setTitle(itemData.getTitleForItemView(this));
|
||||
setCheckable(itemData.isCheckable());
|
||||
setShortcut(itemData.shouldShowShortcut(), itemData.getShortcut());
|
||||
setIcon(itemData.getIcon());
|
||||
setEnabled(itemData.isEnabled());
|
||||
}
|
||||
|
||||
public void setForceShowIcon(boolean forceShow) {
|
||||
mPreserveIconSpacing = mForceShowIcon = forceShow;
|
||||
}
|
||||
|
||||
public void setTitle(CharSequence title) {
|
||||
if (title != null) {
|
||||
mTitleView.setText(title);
|
||||
|
||||
if (mTitleView.getVisibility() != VISIBLE) mTitleView.setVisibility(VISIBLE);
|
||||
} else {
|
||||
if (mTitleView.getVisibility() != GONE) mTitleView.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
public MenuItemImpl getItemData() {
|
||||
return mItemData;
|
||||
}
|
||||
|
||||
public void setCheckable(boolean checkable) {
|
||||
|
||||
if (!checkable && mRadioButton == null && mCheckBox == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mRadioButton == null) {
|
||||
insertRadioButton();
|
||||
}
|
||||
if (mCheckBox == null) {
|
||||
insertCheckBox();
|
||||
}
|
||||
|
||||
// Depending on whether its exclusive check or not, the checkbox or
|
||||
// radio button will be the one in use (and the other will be otherCompoundButton)
|
||||
final CompoundButton compoundButton;
|
||||
final CompoundButton otherCompoundButton;
|
||||
|
||||
if (mItemData.isExclusiveCheckable()) {
|
||||
compoundButton = mRadioButton;
|
||||
otherCompoundButton = mCheckBox;
|
||||
} else {
|
||||
compoundButton = mCheckBox;
|
||||
otherCompoundButton = mRadioButton;
|
||||
}
|
||||
|
||||
if (checkable) {
|
||||
compoundButton.setChecked(mItemData.isChecked());
|
||||
|
||||
final int newVisibility = checkable ? VISIBLE : GONE;
|
||||
if (compoundButton.getVisibility() != newVisibility) {
|
||||
compoundButton.setVisibility(newVisibility);
|
||||
}
|
||||
|
||||
// Make sure the other compound button isn't visible
|
||||
if (otherCompoundButton.getVisibility() != GONE) {
|
||||
otherCompoundButton.setVisibility(GONE);
|
||||
}
|
||||
} else {
|
||||
mCheckBox.setVisibility(GONE);
|
||||
mRadioButton.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
public void setChecked(boolean checked) {
|
||||
CompoundButton compoundButton;
|
||||
|
||||
if (mItemData.isExclusiveCheckable()) {
|
||||
if (mRadioButton == null) {
|
||||
insertRadioButton();
|
||||
}
|
||||
compoundButton = mRadioButton;
|
||||
} else {
|
||||
if (mCheckBox == null) {
|
||||
insertCheckBox();
|
||||
}
|
||||
compoundButton = mCheckBox;
|
||||
}
|
||||
|
||||
compoundButton.setChecked(checked);
|
||||
}
|
||||
|
||||
public void setShortcut(boolean showShortcut, char shortcutKey) {
|
||||
final int newVisibility = (showShortcut && mItemData.shouldShowShortcut())
|
||||
? VISIBLE : GONE;
|
||||
|
||||
if (newVisibility == VISIBLE) {
|
||||
mShortcutView.setText(mItemData.getShortcutLabel());
|
||||
}
|
||||
|
||||
if (mShortcutView.getVisibility() != newVisibility) {
|
||||
mShortcutView.setVisibility(newVisibility);
|
||||
}
|
||||
}
|
||||
|
||||
public void setIcon(Drawable icon) {
|
||||
final boolean showIcon = mItemData.shouldShowIcon() || mForceShowIcon;
|
||||
if (!showIcon && !mPreserveIconSpacing) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIconView == null && icon == null && !mPreserveIconSpacing) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIconView == null) {
|
||||
insertIconView();
|
||||
}
|
||||
|
||||
if (icon != null || mPreserveIconSpacing) {
|
||||
mIconView.setImageDrawable(showIcon ? icon : null);
|
||||
|
||||
if (mIconView.getVisibility() != VISIBLE) {
|
||||
mIconView.setVisibility(VISIBLE);
|
||||
}
|
||||
} else {
|
||||
mIconView.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
if (mIconView != null && mPreserveIconSpacing) {
|
||||
// Enforce minimum icon spacing
|
||||
ViewGroup.LayoutParams lp = getLayoutParams();
|
||||
LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
|
||||
if (lp.height > 0 && iconLp.width <= 0) {
|
||||
iconLp.width = lp.height;
|
||||
}
|
||||
}
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
|
||||
private void insertIconView() {
|
||||
LayoutInflater inflater = getInflater();
|
||||
mIconView = (ImageView) inflater.inflate(R.layout.abs__list_menu_item_icon,
|
||||
this, false);
|
||||
addView(mIconView, 0);
|
||||
}
|
||||
|
||||
private void insertRadioButton() {
|
||||
LayoutInflater inflater = getInflater();
|
||||
mRadioButton =
|
||||
(RadioButton) inflater.inflate(R.layout.abs__list_menu_item_radio,
|
||||
this, false);
|
||||
addView(mRadioButton);
|
||||
}
|
||||
|
||||
private void insertCheckBox() {
|
||||
LayoutInflater inflater = getInflater();
|
||||
mCheckBox =
|
||||
(CheckBox) inflater.inflate(R.layout.abs__list_menu_item_checkbox,
|
||||
this, false);
|
||||
addView(mCheckBox);
|
||||
}
|
||||
|
||||
public boolean prefersCondensedTitle() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean showsIcon() {
|
||||
return mForceShowIcon;
|
||||
}
|
||||
|
||||
private LayoutInflater getInflater() {
|
||||
if (mInflater == null) {
|
||||
mInflater = LayoutInflater.from(mContext);
|
||||
}
|
||||
return mInflater;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,647 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* 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.menu;
|
||||
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewDebug;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.actionbarsherlock.view.ActionProvider;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import com.actionbarsherlock.view.SubMenu;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public final class MenuItemImpl implements MenuItem {
|
||||
private static final String TAG = "MenuItemImpl";
|
||||
|
||||
private static final int SHOW_AS_ACTION_MASK = SHOW_AS_ACTION_NEVER |
|
||||
SHOW_AS_ACTION_IF_ROOM |
|
||||
SHOW_AS_ACTION_ALWAYS;
|
||||
|
||||
private final int mId;
|
||||
private final int mGroup;
|
||||
private final int mCategoryOrder;
|
||||
private final int mOrdering;
|
||||
private CharSequence mTitle;
|
||||
private CharSequence mTitleCondensed;
|
||||
private Intent mIntent;
|
||||
private char mShortcutNumericChar;
|
||||
private char mShortcutAlphabeticChar;
|
||||
|
||||
/** The icon's drawable which is only created as needed */
|
||||
private Drawable mIconDrawable;
|
||||
/**
|
||||
* The icon's resource ID which is used to get the Drawable when it is
|
||||
* needed (if the Drawable isn't already obtained--only one of the two is
|
||||
* needed).
|
||||
*/
|
||||
private int mIconResId = NO_ICON;
|
||||
|
||||
/** The menu to which this item belongs */
|
||||
private MenuBuilder mMenu;
|
||||
/** If this item should launch a sub menu, this is the sub menu to launch */
|
||||
private SubMenuBuilder mSubMenu;
|
||||
|
||||
private Runnable mItemCallback;
|
||||
private MenuItem.OnMenuItemClickListener mClickListener;
|
||||
|
||||
private int mFlags = ENABLED;
|
||||
private static final int CHECKABLE = 0x00000001;
|
||||
private static final int CHECKED = 0x00000002;
|
||||
private static final int EXCLUSIVE = 0x00000004;
|
||||
private static final int HIDDEN = 0x00000008;
|
||||
private static final int ENABLED = 0x00000010;
|
||||
private static final int IS_ACTION = 0x00000020;
|
||||
|
||||
private int mShowAsAction = SHOW_AS_ACTION_NEVER;
|
||||
|
||||
private View mActionView;
|
||||
private ActionProvider mActionProvider;
|
||||
private OnActionExpandListener mOnActionExpandListener;
|
||||
private boolean mIsActionViewExpanded = false;
|
||||
|
||||
/** Used for the icon resource ID if this item does not have an icon */
|
||||
static final int NO_ICON = 0;
|
||||
|
||||
/**
|
||||
* Current use case is for context menu: Extra information linked to the
|
||||
* View that added this item to the context menu.
|
||||
*/
|
||||
private ContextMenuInfo mMenuInfo;
|
||||
|
||||
private static String sPrependShortcutLabel;
|
||||
private static String sEnterShortcutLabel;
|
||||
private static String sDeleteShortcutLabel;
|
||||
private static String sSpaceShortcutLabel;
|
||||
|
||||
|
||||
/**
|
||||
* Instantiates this menu item.
|
||||
*
|
||||
* @param menu
|
||||
* @param group Item ordering grouping control. The item will be added after
|
||||
* all other items whose order is <= this number, and before any
|
||||
* that are larger than it. This can also be used to define
|
||||
* groups of items for batch state changes. Normally use 0.
|
||||
* @param id Unique item ID. Use 0 if you do not need a unique ID.
|
||||
* @param categoryOrder The ordering for this item.
|
||||
* @param title The text to display for the item.
|
||||
*/
|
||||
MenuItemImpl(MenuBuilder menu, int group, int id, int categoryOrder, int ordering,
|
||||
CharSequence title, int showAsAction) {
|
||||
|
||||
/* TODO if (sPrependShortcutLabel == null) {
|
||||
// This is instantiated from the UI thread, so no chance of sync issues
|
||||
sPrependShortcutLabel = menu.getContext().getResources().getString(
|
||||
com.android.internal.R.string.prepend_shortcut_label);
|
||||
sEnterShortcutLabel = menu.getContext().getResources().getString(
|
||||
com.android.internal.R.string.menu_enter_shortcut_label);
|
||||
sDeleteShortcutLabel = menu.getContext().getResources().getString(
|
||||
com.android.internal.R.string.menu_delete_shortcut_label);
|
||||
sSpaceShortcutLabel = menu.getContext().getResources().getString(
|
||||
com.android.internal.R.string.menu_space_shortcut_label);
|
||||
}*/
|
||||
|
||||
mMenu = menu;
|
||||
mId = id;
|
||||
mGroup = group;
|
||||
mCategoryOrder = categoryOrder;
|
||||
mOrdering = ordering;
|
||||
mTitle = title;
|
||||
mShowAsAction = showAsAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the item by calling various listeners or callbacks.
|
||||
*
|
||||
* @return true if the invocation was handled, false otherwise
|
||||
*/
|
||||
public boolean invoke() {
|
||||
if (mClickListener != null &&
|
||||
mClickListener.onMenuItemClick(this)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mMenu.dispatchMenuItemSelected(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);
|
||||
}
|
||||
}
|
||||
|
||||
if (mActionProvider != null && mActionProvider.onPerformDefaultAction()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return (mFlags & ENABLED) != 0;
|
||||
}
|
||||
|
||||
public MenuItem setEnabled(boolean enabled) {
|
||||
if (enabled) {
|
||||
mFlags |= ENABLED;
|
||||
} else {
|
||||
mFlags &= ~ENABLED;
|
||||
}
|
||||
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getGroupId() {
|
||||
return mGroup;
|
||||
}
|
||||
|
||||
@ViewDebug.CapturedViewProperty
|
||||
public int getItemId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return mCategoryOrder;
|
||||
}
|
||||
|
||||
public int getOrdering() {
|
||||
return mOrdering;
|
||||
}
|
||||
|
||||
public Intent getIntent() {
|
||||
return mIntent;
|
||||
}
|
||||
|
||||
public MenuItem setIntent(Intent intent) {
|
||||
mIntent = intent;
|
||||
return this;
|
||||
}
|
||||
|
||||
Runnable getCallback() {
|
||||
return mItemCallback;
|
||||
}
|
||||
|
||||
public MenuItem setCallback(Runnable callback) {
|
||||
mItemCallback = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
public char getAlphabeticShortcut() {
|
||||
return mShortcutAlphabeticChar;
|
||||
}
|
||||
|
||||
public MenuItem setAlphabeticShortcut(char alphaChar) {
|
||||
if (mShortcutAlphabeticChar == alphaChar) return this;
|
||||
|
||||
mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
|
||||
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public char getNumericShortcut() {
|
||||
return mShortcutNumericChar;
|
||||
}
|
||||
|
||||
public MenuItem setNumericShortcut(char numericChar) {
|
||||
if (mShortcutNumericChar == numericChar) return this;
|
||||
|
||||
mShortcutNumericChar = numericChar;
|
||||
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setShortcut(char numericChar, char alphaChar) {
|
||||
mShortcutNumericChar = numericChar;
|
||||
mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
|
||||
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The active shortcut (based on QWERTY-mode of the menu).
|
||||
*/
|
||||
char getShortcut() {
|
||||
return (mMenu.isQwertyMode() ? mShortcutAlphabeticChar : mShortcutNumericChar);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The label to show for the shortcut. This includes the chording
|
||||
* key (for example 'Menu+a'). Also, any non-human readable
|
||||
* characters should be human readable (for example 'Menu+enter').
|
||||
*/
|
||||
String getShortcutLabel() {
|
||||
|
||||
char shortcut = getShortcut();
|
||||
if (shortcut == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder(sPrependShortcutLabel);
|
||||
switch (shortcut) {
|
||||
|
||||
case '\n':
|
||||
sb.append(sEnterShortcutLabel);
|
||||
break;
|
||||
|
||||
case '\b':
|
||||
sb.append(sDeleteShortcutLabel);
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
sb.append(sSpaceShortcutLabel);
|
||||
break;
|
||||
|
||||
default:
|
||||
sb.append(shortcut);
|
||||
break;
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether this menu item should be showing shortcuts (depends on
|
||||
* whether the menu should show shortcuts and whether this item has
|
||||
* a shortcut defined)
|
||||
*/
|
||||
boolean shouldShowShortcut() {
|
||||
// Show shortcuts if the menu is supposed to show shortcuts AND this item has a shortcut
|
||||
return mMenu.isShortcutsVisible() && (getShortcut() != 0);
|
||||
}
|
||||
|
||||
public SubMenu getSubMenu() {
|
||||
return mSubMenu;
|
||||
}
|
||||
|
||||
public boolean hasSubMenu() {
|
||||
return mSubMenu != null;
|
||||
}
|
||||
|
||||
void setSubMenu(SubMenuBuilder subMenu) {
|
||||
mSubMenu = subMenu;
|
||||
|
||||
subMenu.setHeaderTitle(getTitle());
|
||||
}
|
||||
|
||||
@ViewDebug.CapturedViewProperty
|
||||
public CharSequence getTitle() {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the title for a particular {@link ItemView}
|
||||
*
|
||||
* @param itemView The ItemView that is receiving the title
|
||||
* @return Either the title or condensed title based on what the ItemView
|
||||
* prefers
|
||||
*/
|
||||
CharSequence getTitleForItemView(MenuView.ItemView itemView) {
|
||||
return ((itemView != null) && itemView.prefersCondensedTitle())
|
||||
? getTitleCondensed()
|
||||
: getTitle();
|
||||
}
|
||||
|
||||
public MenuItem setTitle(CharSequence title) {
|
||||
mTitle = title;
|
||||
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
if (mSubMenu != null) {
|
||||
mSubMenu.setHeaderTitle(title);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setTitle(int title) {
|
||||
return setTitle(mMenu.getContext().getString(title));
|
||||
}
|
||||
|
||||
public CharSequence getTitleCondensed() {
|
||||
return mTitleCondensed != null ? mTitleCondensed : mTitle;
|
||||
}
|
||||
|
||||
public MenuItem setTitleCondensed(CharSequence title) {
|
||||
mTitleCondensed = title;
|
||||
|
||||
// Could use getTitle() in the loop below, but just cache what it would do here
|
||||
if (title == null) {
|
||||
title = mTitle;
|
||||
}
|
||||
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Drawable getIcon() {
|
||||
if (mIconDrawable != null) {
|
||||
return mIconDrawable;
|
||||
}
|
||||
|
||||
if (mIconResId != NO_ICON) {
|
||||
return mMenu.getResources().getDrawable(mIconResId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public MenuItem setIcon(Drawable icon) {
|
||||
mIconResId = NO_ICON;
|
||||
mIconDrawable = icon;
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setIcon(int iconResId) {
|
||||
mIconDrawable = null;
|
||||
mIconResId = iconResId;
|
||||
|
||||
// If we have a view, we need to push the Drawable to them
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isCheckable() {
|
||||
return (mFlags & CHECKABLE) == CHECKABLE;
|
||||
}
|
||||
|
||||
public MenuItem setCheckable(boolean checkable) {
|
||||
final int oldFlags = mFlags;
|
||||
mFlags = (mFlags & ~CHECKABLE) | (checkable ? CHECKABLE : 0);
|
||||
if (oldFlags != mFlags) {
|
||||
mMenu.onItemsChanged(false);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setExclusiveCheckable(boolean exclusive) {
|
||||
mFlags = (mFlags & ~EXCLUSIVE) | (exclusive ? EXCLUSIVE : 0);
|
||||
}
|
||||
|
||||
public boolean isExclusiveCheckable() {
|
||||
return (mFlags & EXCLUSIVE) != 0;
|
||||
}
|
||||
|
||||
public boolean isChecked() {
|
||||
return (mFlags & CHECKED) == CHECKED;
|
||||
}
|
||||
|
||||
public MenuItem setChecked(boolean checked) {
|
||||
if ((mFlags & EXCLUSIVE) != 0) {
|
||||
// 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 int oldFlags = mFlags;
|
||||
mFlags = (mFlags & ~CHECKED) | (checked ? CHECKED : 0);
|
||||
if (oldFlags != mFlags) {
|
||||
mMenu.onItemsChanged(false);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return (mFlags & HIDDEN) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the visibility of the item. This method DOES NOT notify the
|
||||
* parent menu of a change in this item, so this should only be called from
|
||||
* methods that will eventually trigger this change. If unsure, use {@link #setVisible(boolean)}
|
||||
* instead.
|
||||
*
|
||||
* @param shown Whether to show (true) or hide (false).
|
||||
* @return Whether the item's shown state was changed
|
||||
*/
|
||||
boolean setVisibleInt(boolean shown) {
|
||||
final int oldFlags = mFlags;
|
||||
mFlags = (mFlags & ~HIDDEN) | (shown ? 0 : HIDDEN);
|
||||
return oldFlags != mFlags;
|
||||
}
|
||||
|
||||
public MenuItem setVisible(boolean shown) {
|
||||
// Try to set the shown state to the given state. If the shown state was changed
|
||||
// (i.e. the previous state isn't the same as given state), notify the parent menu that
|
||||
// the shown state has changed for this item
|
||||
if (setVisibleInt(shown)) mMenu.onItemVisibleChanged(this);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener clickListener) {
|
||||
mClickListener = clickListener;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mTitle.toString();
|
||||
}
|
||||
|
||||
void setMenuInfo(ContextMenuInfo menuInfo) {
|
||||
mMenuInfo = menuInfo;
|
||||
}
|
||||
|
||||
public ContextMenuInfo getMenuInfo() {
|
||||
return mMenuInfo;
|
||||
}
|
||||
|
||||
public void actionFormatChanged() {
|
||||
mMenu.onItemActionRequestChanged(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether the menu should show icons for menu items.
|
||||
*/
|
||||
public boolean shouldShowIcon() {
|
||||
return mMenu.getOptionalIconsVisible();
|
||||
}
|
||||
|
||||
public boolean isActionButton() {
|
||||
return (mFlags & IS_ACTION) == IS_ACTION;
|
||||
}
|
||||
|
||||
public boolean requestsActionButton() {
|
||||
return (mShowAsAction & SHOW_AS_ACTION_IF_ROOM) == SHOW_AS_ACTION_IF_ROOM;
|
||||
}
|
||||
|
||||
public boolean requiresActionButton() {
|
||||
return (mShowAsAction & SHOW_AS_ACTION_ALWAYS) == SHOW_AS_ACTION_ALWAYS;
|
||||
}
|
||||
|
||||
public void setIsActionButton(boolean isActionButton) {
|
||||
if (isActionButton) {
|
||||
mFlags |= IS_ACTION;
|
||||
} else {
|
||||
mFlags &= ~IS_ACTION;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean showsTextAsAction() {
|
||||
return (mShowAsAction & SHOW_AS_ACTION_WITH_TEXT) == SHOW_AS_ACTION_WITH_TEXT;
|
||||
}
|
||||
|
||||
public void setShowAsAction(int actionEnum) {
|
||||
switch (actionEnum & SHOW_AS_ACTION_MASK) {
|
||||
case SHOW_AS_ACTION_ALWAYS:
|
||||
case SHOW_AS_ACTION_IF_ROOM:
|
||||
case SHOW_AS_ACTION_NEVER:
|
||||
// Looks good!
|
||||
break;
|
||||
|
||||
default:
|
||||
// Mutually exclusive options selected!
|
||||
throw new IllegalArgumentException("SHOW_AS_ACTION_ALWAYS, SHOW_AS_ACTION_IF_ROOM,"
|
||||
+ " and SHOW_AS_ACTION_NEVER are mutually exclusive.");
|
||||
}
|
||||
mShowAsAction = actionEnum;
|
||||
mMenu.onItemActionRequestChanged(this);
|
||||
}
|
||||
|
||||
public MenuItem setActionView(View view) {
|
||||
mActionView = view;
|
||||
mActionProvider = null;
|
||||
if (view != null && view.getId() == View.NO_ID && mId > 0) {
|
||||
view.setId(mId);
|
||||
}
|
||||
mMenu.onItemActionRequestChanged(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setActionView(int resId) {
|
||||
final Context context = mMenu.getContext();
|
||||
final LayoutInflater inflater = LayoutInflater.from(context);
|
||||
setActionView(inflater.inflate(resId, new LinearLayout(context), false));
|
||||
return this;
|
||||
}
|
||||
|
||||
public View getActionView() {
|
||||
if (mActionView != null) {
|
||||
return mActionView;
|
||||
} else if (mActionProvider != null) {
|
||||
mActionView = mActionProvider.onCreateActionView();
|
||||
return mActionView;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ActionProvider getActionProvider() {
|
||||
return mActionProvider;
|
||||
}
|
||||
|
||||
public MenuItem setActionProvider(ActionProvider actionProvider) {
|
||||
mActionView = null;
|
||||
mActionProvider = actionProvider;
|
||||
mMenu.onItemsChanged(true); // Measurement can be changed
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setShowAsActionFlags(int actionEnum) {
|
||||
setShowAsAction(actionEnum);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean expandActionView() {
|
||||
if ((mShowAsAction & SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW) == 0 || mActionView == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mOnActionExpandListener == null ||
|
||||
mOnActionExpandListener.onMenuItemActionExpand(this)) {
|
||||
return mMenu.expandItemActionView(this);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collapseActionView() {
|
||||
if ((mShowAsAction & SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW) == 0) {
|
||||
return false;
|
||||
}
|
||||
if (mActionView == null) {
|
||||
// We're already collapsed if we have no action view.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mOnActionExpandListener == null ||
|
||||
mOnActionExpandListener.onMenuItemActionCollapse(this)) {
|
||||
return mMenu.collapseItemActionView(this);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setOnActionExpandListener(OnActionExpandListener listener) {
|
||||
mOnActionExpandListener = listener;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean hasCollapsibleActionView() {
|
||||
return (mShowAsAction & SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW) != 0 && mActionView != null;
|
||||
}
|
||||
|
||||
public void setActionViewExpanded(boolean isExpanded) {
|
||||
mIsActionViewExpanded = isExpanded;
|
||||
mMenu.onItemsChanged(false);
|
||||
}
|
||||
|
||||
public boolean isActionViewExpanded() {
|
||||
return mIsActionViewExpanded;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.ActionProvider;
|
||||
import android.view.MenuItem;
|
||||
import android.view.SubMenu;
|
||||
import android.view.View;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
|
||||
/** Used to carry an instance of our version of MenuItem through a native channel. */
|
||||
public class MenuItemMule implements MenuItem {
|
||||
private static final String ERROR = "Cannot interact with object designed for temporary "
|
||||
+ "instance passing. Make sure you using both SherlockFragmentActivity and "
|
||||
+ "SherlockFragment.";
|
||||
|
||||
|
||||
private final com.actionbarsherlock.view.MenuItem mItem;
|
||||
|
||||
public MenuItemMule(com.actionbarsherlock.view.MenuItem item) {
|
||||
mItem = item;
|
||||
}
|
||||
|
||||
public com.actionbarsherlock.view.MenuItem unwrap() {
|
||||
return mItem;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean collapseActionView() {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean expandActionView() {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionProvider getActionProvider() {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getActionView() {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getAlphabeticShortcut() {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGroupId() {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getIcon() {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Intent getIntent() {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemId() {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextMenuInfo getMenuInfo() {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getNumericShortcut() {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu getSubMenu() {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTitle() {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTitleCondensed() {
|
||||
return mItem.getTitleCondensed();
|
||||
//throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSubMenu() {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActionViewExpanded() {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCheckable() {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible() {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setActionProvider(ActionProvider arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setActionView(View arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setActionView(int arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setAlphabeticShortcut(char arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setCheckable(boolean arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setChecked(boolean arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setEnabled(boolean arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setIcon(Drawable arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setIcon(int arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setIntent(Intent arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setNumericShortcut(char arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setOnActionExpandListener(OnActionExpandListener arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setShortcut(char arg0, char arg1) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShowAsAction(int arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setShowAsActionFlags(int arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setTitle(CharSequence arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setTitle(int arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setTitleCondensed(CharSequence arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setVisible(boolean arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import com.actionbarsherlock.internal.view.ActionProviderWrapper;
|
||||
import com.actionbarsherlock.view.ActionProvider;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import com.actionbarsherlock.view.SubMenu;
|
||||
|
||||
public class MenuItemWrapper implements MenuItem, android.view.MenuItem.OnMenuItemClickListener, android.view.MenuItem.OnActionExpandListener {
|
||||
private final android.view.MenuItem mNativeItem;
|
||||
private SubMenu mSubMenu = null;
|
||||
private OnMenuItemClickListener mMenuItemClickListener = null;
|
||||
private OnActionExpandListener mActionExpandListener = null;
|
||||
|
||||
|
||||
public MenuItemWrapper(android.view.MenuItem nativeItem) {
|
||||
if (nativeItem == null) {
|
||||
throw new IllegalStateException("Wrapped menu item cannot be null.");
|
||||
}
|
||||
mNativeItem = nativeItem;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getItemId() {
|
||||
return mNativeItem.getItemId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGroupId() {
|
||||
return mNativeItem.getGroupId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return mNativeItem.getOrder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setTitle(CharSequence title) {
|
||||
mNativeItem.setTitle(title);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setTitle(int title) {
|
||||
mNativeItem.setTitle(title);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTitle() {
|
||||
return mNativeItem.getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setTitleCondensed(CharSequence title) {
|
||||
mNativeItem.setTitleCondensed(title);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTitleCondensed() {
|
||||
return mNativeItem.getTitleCondensed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setIcon(Drawable icon) {
|
||||
mNativeItem.setIcon(icon);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setIcon(int iconRes) {
|
||||
mNativeItem.setIcon(iconRes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getIcon() {
|
||||
return mNativeItem.getIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setIntent(Intent intent) {
|
||||
mNativeItem.setIntent(intent);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Intent getIntent() {
|
||||
return mNativeItem.getIntent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setShortcut(char numericChar, char alphaChar) {
|
||||
mNativeItem.setShortcut(numericChar, alphaChar);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setNumericShortcut(char numericChar) {
|
||||
mNativeItem.setNumericShortcut(numericChar);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getNumericShortcut() {
|
||||
return mNativeItem.getNumericShortcut();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setAlphabeticShortcut(char alphaChar) {
|
||||
mNativeItem.setAlphabeticShortcut(alphaChar);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getAlphabeticShortcut() {
|
||||
return mNativeItem.getAlphabeticShortcut();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setCheckable(boolean checkable) {
|
||||
mNativeItem.setCheckable(checkable);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCheckable() {
|
||||
return mNativeItem.isCheckable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setChecked(boolean checked) {
|
||||
mNativeItem.setChecked(checked);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
return mNativeItem.isChecked();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setVisible(boolean visible) {
|
||||
mNativeItem.setVisible(visible);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible() {
|
||||
return mNativeItem.isVisible();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setEnabled(boolean enabled) {
|
||||
mNativeItem.setEnabled(enabled);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return mNativeItem.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSubMenu() {
|
||||
return mNativeItem.hasSubMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu getSubMenu() {
|
||||
if (hasSubMenu() && (mSubMenu == null)) {
|
||||
mSubMenu = new SubMenuWrapper(mNativeItem.getSubMenu());
|
||||
}
|
||||
return mSubMenu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) {
|
||||
mMenuItemClickListener = menuItemClickListener;
|
||||
//Register ourselves as the listener to proxy
|
||||
mNativeItem.setOnMenuItemClickListener(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemClick(android.view.MenuItem item) {
|
||||
if (mMenuItemClickListener != null) {
|
||||
return mMenuItemClickListener.onMenuItemClick(this);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextMenuInfo getMenuInfo() {
|
||||
return mNativeItem.getMenuInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShowAsAction(int actionEnum) {
|
||||
mNativeItem.setShowAsAction(actionEnum);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setShowAsActionFlags(int actionEnum) {
|
||||
mNativeItem.setShowAsActionFlags(actionEnum);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setActionView(View view) {
|
||||
mNativeItem.setActionView(view);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setActionView(int resId) {
|
||||
mNativeItem.setActionView(resId);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getActionView() {
|
||||
return mNativeItem.getActionView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setActionProvider(ActionProvider actionProvider) {
|
||||
mNativeItem.setActionProvider(new ActionProviderWrapper(actionProvider));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionProvider getActionProvider() {
|
||||
android.view.ActionProvider nativeProvider = mNativeItem.getActionProvider();
|
||||
if (nativeProvider != null && nativeProvider instanceof ActionProviderWrapper) {
|
||||
return ((ActionProviderWrapper)nativeProvider).unwrap();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean expandActionView() {
|
||||
return mNativeItem.expandActionView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collapseActionView() {
|
||||
return mNativeItem.collapseActionView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActionViewExpanded() {
|
||||
return mNativeItem.isActionViewExpanded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setOnActionExpandListener(OnActionExpandListener listener) {
|
||||
mActionExpandListener = listener;
|
||||
//Register ourselves as the listener to proxy
|
||||
mNativeItem.setOnActionExpandListener(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemActionCollapse(android.view.MenuItem item) {
|
||||
if (mActionExpandListener != null) {
|
||||
return mActionExpandListener.onMenuItemActionCollapse(this);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemActionExpand(android.view.MenuItem item) {
|
||||
if (mActionExpandListener != null) {
|
||||
return mActionExpandListener.onMenuItemActionExpand(this);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.SubMenu;
|
||||
|
||||
/** Used to carry an instance of our version of Menu through a native channel. */
|
||||
public class MenuMule implements Menu {
|
||||
private static final String ERROR = "Cannot interact with object designed for temporary "
|
||||
+ "instance passing. Make sure you using both SherlockFragmentActivity and "
|
||||
+ "SherlockFragment.";
|
||||
|
||||
|
||||
private final com.actionbarsherlock.view.Menu mMenu;
|
||||
|
||||
public MenuMule(com.actionbarsherlock.view.Menu menu) {
|
||||
mMenu = menu;
|
||||
}
|
||||
|
||||
public com.actionbarsherlock.view.Menu unwrap() {
|
||||
return mMenu;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public MenuItem add(CharSequence arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem add(int arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem add(int arg0, int arg1, int arg2, CharSequence arg3) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem add(int arg0, int arg1, int arg2, int arg3) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int addIntentOptions(int arg0, int arg1, int arg2,
|
||||
ComponentName arg3, Intent[] arg4, Intent arg5, int arg6,
|
||||
MenuItem[] arg7) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu addSubMenu(CharSequence arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu addSubMenu(int arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu addSubMenu(int arg0, int arg1, int arg2, CharSequence arg3) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu addSubMenu(int arg0, int arg1, int arg2, int arg3) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem findItem(int arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem getItem(int arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasVisibleItems() {
|
||||
return mMenu.hasVisibleItems();
|
||||
//throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShortcutKey(int arg0, KeyEvent arg1) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performIdentifierAction(int arg0, int arg1) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performShortcut(int arg0, KeyEvent arg1, int arg2) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeGroup(int arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeItem(int arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupCheckable(int arg0, boolean arg1, boolean arg2) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupEnabled(int arg0, boolean arg1) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupVisible(int arg0, boolean arg1) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQwertyMode(boolean arg0) {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
throw new IllegalStateException(ERROR);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* 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.menu;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.database.DataSetObserver;
|
||||
import android.os.Parcelable;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.MeasureSpec;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.PopupWindow;
|
||||
import com.actionbarsherlock.R;
|
||||
import com.actionbarsherlock.internal.view.View_HasStateListenerSupport;
|
||||
import com.actionbarsherlock.internal.view.View_OnAttachStateChangeListener;
|
||||
import com.actionbarsherlock.internal.widget.IcsListPopupWindow;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
/**
|
||||
* Presents a menu as a small, simple popup anchored to another view.
|
||||
* @hide
|
||||
*/
|
||||
public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.OnKeyListener,
|
||||
ViewTreeObserver.OnGlobalLayoutListener, PopupWindow.OnDismissListener,
|
||||
View_OnAttachStateChangeListener, MenuPresenter {
|
||||
//UNUSED private static final String TAG = "MenuPopupHelper";
|
||||
|
||||
static final int ITEM_LAYOUT = R.layout.abs__popup_menu_item_layout;
|
||||
|
||||
private Context mContext;
|
||||
private LayoutInflater mInflater;
|
||||
private IcsListPopupWindow mPopup;
|
||||
private MenuBuilder mMenu;
|
||||
private int mPopupMaxWidth;
|
||||
private View mAnchorView;
|
||||
private boolean mOverflowOnly;
|
||||
private ViewTreeObserver mTreeObserver;
|
||||
|
||||
private MenuAdapter mAdapter;
|
||||
|
||||
private Callback mPresenterCallback;
|
||||
|
||||
boolean mForceShowIcon;
|
||||
|
||||
private ViewGroup mMeasureParent;
|
||||
|
||||
public MenuPopupHelper(Context context, MenuBuilder menu) {
|
||||
this(context, menu, null, false);
|
||||
}
|
||||
|
||||
public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView) {
|
||||
this(context, menu, anchorView, false);
|
||||
}
|
||||
|
||||
public MenuPopupHelper(Context context, MenuBuilder menu,
|
||||
View anchorView, boolean overflowOnly) {
|
||||
mContext = context;
|
||||
mInflater = LayoutInflater.from(context);
|
||||
mMenu = menu;
|
||||
mOverflowOnly = overflowOnly;
|
||||
|
||||
final Resources res = context.getResources();
|
||||
mPopupMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2,
|
||||
res.getDimensionPixelSize(R.dimen.abs__config_prefDialogWidth));
|
||||
|
||||
mAnchorView = anchorView;
|
||||
|
||||
menu.addMenuPresenter(this);
|
||||
}
|
||||
|
||||
public void setAnchorView(View anchor) {
|
||||
mAnchorView = anchor;
|
||||
}
|
||||
|
||||
public void setForceShowIcon(boolean forceShow) {
|
||||
mForceShowIcon = forceShow;
|
||||
}
|
||||
|
||||
public void show() {
|
||||
if (!tryShow()) {
|
||||
throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean tryShow() {
|
||||
mPopup = new IcsListPopupWindow(mContext, null, R.attr.popupMenuStyle);
|
||||
mPopup.setOnDismissListener(this);
|
||||
mPopup.setOnItemClickListener(this);
|
||||
|
||||
mAdapter = new MenuAdapter(mMenu);
|
||||
mPopup.setAdapter(mAdapter);
|
||||
mPopup.setModal(true);
|
||||
|
||||
View anchor = mAnchorView;
|
||||
if (anchor != null) {
|
||||
final boolean addGlobalListener = mTreeObserver == null;
|
||||
mTreeObserver = anchor.getViewTreeObserver(); // Refresh to latest
|
||||
if (addGlobalListener) mTreeObserver.addOnGlobalLayoutListener(this);
|
||||
((View_HasStateListenerSupport)anchor).addOnAttachStateChangeListener(this);
|
||||
mPopup.setAnchorView(anchor);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
mPopup.setContentWidth(Math.min(measureContentWidth(mAdapter), mPopupMaxWidth));
|
||||
mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
|
||||
mPopup.show();
|
||||
mPopup.getListView().setOnKeyListener(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void dismiss() {
|
||||
if (isShowing()) {
|
||||
mPopup.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
public void onDismiss() {
|
||||
mPopup = null;
|
||||
mMenu.close();
|
||||
if (mTreeObserver != null) {
|
||||
if (!mTreeObserver.isAlive()) mTreeObserver = mAnchorView.getViewTreeObserver();
|
||||
mTreeObserver.removeGlobalOnLayoutListener(this);
|
||||
mTreeObserver = null;
|
||||
}
|
||||
((View_HasStateListenerSupport)mAnchorView).removeOnAttachStateChangeListener(this);
|
||||
}
|
||||
|
||||
public boolean isShowing() {
|
||||
return mPopup != null && mPopup.isShowing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
MenuAdapter adapter = mAdapter;
|
||||
adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0);
|
||||
}
|
||||
|
||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) {
|
||||
dismiss();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private int measureContentWidth(ListAdapter adapter) {
|
||||
// Menus don't tend to be long, so this is more sane than it looks.
|
||||
int width = 0;
|
||||
View itemView = null;
|
||||
int itemType = 0;
|
||||
final int widthMeasureSpec =
|
||||
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
final int heightMeasureSpec =
|
||||
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
final int count = adapter.getCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final int positionType = adapter.getItemViewType(i);
|
||||
if (positionType != itemType) {
|
||||
itemType = positionType;
|
||||
itemView = null;
|
||||
}
|
||||
if (mMeasureParent == null) {
|
||||
mMeasureParent = new FrameLayout(mContext);
|
||||
}
|
||||
itemView = adapter.getView(i, itemView, mMeasureParent);
|
||||
itemView.measure(widthMeasureSpec, heightMeasureSpec);
|
||||
width = Math.max(width, itemView.getMeasuredWidth());
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
if (isShowing()) {
|
||||
final View anchor = mAnchorView;
|
||||
if (anchor == null || !anchor.isShown()) {
|
||||
dismiss();
|
||||
} else if (isShowing()) {
|
||||
// Recompute window size and position
|
||||
mPopup.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewAttachedToWindow(View v) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View v) {
|
||||
if (mTreeObserver != null) {
|
||||
if (!mTreeObserver.isAlive()) mTreeObserver = v.getViewTreeObserver();
|
||||
mTreeObserver.removeGlobalOnLayoutListener(this);
|
||||
}
|
||||
((View_HasStateListenerSupport)v).removeOnAttachStateChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initForMenu(Context context, MenuBuilder menu) {
|
||||
// Don't need to do anything; we added as a presenter in the constructor.
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuView getMenuView(ViewGroup root) {
|
||||
throw new UnsupportedOperationException("MenuPopupHelpers manage their own views");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateMenuView(boolean cleared) {
|
||||
if (mAdapter != null) mAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCallback(Callback cb) {
|
||||
mPresenterCallback = cb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
|
||||
if (subMenu.hasVisibleItems()) {
|
||||
MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu, mAnchorView, false);
|
||||
subPopup.setCallback(mPresenterCallback);
|
||||
|
||||
boolean preserveIconSpacing = false;
|
||||
final int count = subMenu.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
MenuItem childItem = subMenu.getItem(i);
|
||||
if (childItem.isVisible() && childItem.getIcon() != null) {
|
||||
preserveIconSpacing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
subPopup.setForceShowIcon(preserveIconSpacing);
|
||||
|
||||
if (subPopup.tryShow()) {
|
||||
if (mPresenterCallback != null) {
|
||||
mPresenterCallback.onOpenSubMenu(subMenu);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
|
||||
// Only care about the (sub)menu we're presenting.
|
||||
if (menu != mMenu) return;
|
||||
|
||||
dismiss();
|
||||
if (mPresenterCallback != null) {
|
||||
mPresenterCallback.onCloseMenu(menu, allMenusAreClosing);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean flagActionItems() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parcelable onSaveInstanceState() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreInstanceState(Parcelable state) {
|
||||
}
|
||||
|
||||
private class MenuAdapter extends BaseAdapter {
|
||||
private MenuBuilder mAdapterMenu;
|
||||
private int mExpandedIndex = -1;
|
||||
|
||||
public MenuAdapter(MenuBuilder menu) {
|
||||
mAdapterMenu = menu;
|
||||
registerDataSetObserver(new ExpandedIndexObserver());
|
||||
findExpandedIndex();
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
ArrayList<MenuItemImpl> items = mOverflowOnly ?
|
||||
mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems();
|
||||
if (mExpandedIndex < 0) {
|
||||
return items.size();
|
||||
}
|
||||
return items.size() - 1;
|
||||
}
|
||||
|
||||
public MenuItemImpl getItem(int position) {
|
||||
ArrayList<MenuItemImpl> items = mOverflowOnly ?
|
||||
mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems();
|
||||
if (mExpandedIndex >= 0 && position >= mExpandedIndex) {
|
||||
position++;
|
||||
}
|
||||
return items.get(position);
|
||||
}
|
||||
|
||||
public long getItemId(int position) {
|
||||
// Since a menu item's ID is optional, we'll use the position as an
|
||||
// ID for the item in the AdapterView
|
||||
return position;
|
||||
}
|
||||
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = mInflater.inflate(ITEM_LAYOUT, parent, false);
|
||||
}
|
||||
|
||||
MenuView.ItemView itemView = (MenuView.ItemView) convertView;
|
||||
if (mForceShowIcon) {
|
||||
((ListMenuItemView) convertView).setForceShowIcon(true);
|
||||
}
|
||||
itemView.initialize(getItem(position), 0);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
void findExpandedIndex() {
|
||||
final MenuItemImpl expandedItem = mMenu.getExpandedItem();
|
||||
if (expandedItem != null) {
|
||||
final ArrayList<MenuItemImpl> items = mMenu.getNonActionItems();
|
||||
final int count = items.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final MenuItemImpl item = items.get(i);
|
||||
if (item == expandedItem) {
|
||||
mExpandedIndex = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
mExpandedIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private class ExpandedIndexObserver extends DataSetObserver {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
mAdapter.findExpandedIndex();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* 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.menu;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Parcelable;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* A MenuPresenter is responsible for building views for a Menu object.
|
||||
* It takes over some responsibility from the old style monolithic MenuBuilder class.
|
||||
*/
|
||||
public interface MenuPresenter {
|
||||
/**
|
||||
* Called by menu implementation to notify another component of open/close events.
|
||||
*/
|
||||
public interface Callback {
|
||||
/**
|
||||
* Called when a menu is closing.
|
||||
* @param menu
|
||||
* @param allMenusAreClosing
|
||||
*/
|
||||
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing);
|
||||
|
||||
/**
|
||||
* Called when a submenu opens. Useful for notifying the application
|
||||
* of menu state so that it does not attempt to hide the action bar
|
||||
* while a submenu is open or similar.
|
||||
*
|
||||
* @param subMenu Submenu currently being opened
|
||||
* @return true if the Callback will handle presenting the submenu, false if
|
||||
* the presenter should attempt to do so.
|
||||
*/
|
||||
public boolean onOpenSubMenu(MenuBuilder subMenu);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this presenter for the given context and menu.
|
||||
* This method is called by MenuBuilder when a presenter is
|
||||
* added. See {@link MenuBuilder#addMenuPresenter(MenuPresenter)}
|
||||
*
|
||||
* @param context Context for this presenter; used for view creation and resource management
|
||||
* @param menu Menu to host
|
||||
*/
|
||||
public void initForMenu(Context context, MenuBuilder menu);
|
||||
|
||||
/**
|
||||
* Retrieve a MenuView to display the menu specified in
|
||||
* {@link #initForMenu(Context, Menu)}.
|
||||
*
|
||||
* @param root Intended parent of the MenuView.
|
||||
* @return A freshly created MenuView.
|
||||
*/
|
||||
public MenuView getMenuView(ViewGroup root);
|
||||
|
||||
/**
|
||||
* Update the menu UI in response to a change. Called by
|
||||
* MenuBuilder during the normal course of operation.
|
||||
*
|
||||
* @param cleared true if the menu was entirely cleared
|
||||
*/
|
||||
public void updateMenuView(boolean cleared);
|
||||
|
||||
/**
|
||||
* Set a callback object that will be notified of menu events
|
||||
* related to this specific presentation.
|
||||
* @param cb Callback that will be notified of future events
|
||||
*/
|
||||
public void setCallback(Callback cb);
|
||||
|
||||
/**
|
||||
* Called by Menu implementations to indicate that a submenu item
|
||||
* has been selected. An active Callback should be notified, and
|
||||
* if applicable the presenter should present the submenu.
|
||||
*
|
||||
* @param subMenu SubMenu being opened
|
||||
* @return true if the the event was handled, false otherwise.
|
||||
*/
|
||||
public boolean onSubMenuSelected(SubMenuBuilder subMenu);
|
||||
|
||||
/**
|
||||
* Called by Menu implementations to indicate that a menu or submenu is
|
||||
* closing. Presenter implementations should close the representation
|
||||
* of the menu indicated as necessary and notify a registered callback.
|
||||
*
|
||||
* @param menu Menu or submenu that is closing.
|
||||
* @param allMenusAreClosing True if all associated menus are closing.
|
||||
*/
|
||||
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing);
|
||||
|
||||
/**
|
||||
* Called by Menu implementations to flag items that will be shown as actions.
|
||||
* @return true if this presenter changed the action status of any items.
|
||||
*/
|
||||
public boolean flagActionItems();
|
||||
|
||||
/**
|
||||
* Called when a menu item with a collapsable action view should expand its action view.
|
||||
*
|
||||
* @param menu Menu containing the item to be expanded
|
||||
* @param item Item to be expanded
|
||||
* @return true if this presenter expanded the action view, false otherwise.
|
||||
*/
|
||||
public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item);
|
||||
|
||||
/**
|
||||
* Called when a menu item with a collapsable action view should collapse its action view.
|
||||
*
|
||||
* @param menu Menu containing the item to be collapsed
|
||||
* @param item Item to be collapsed
|
||||
* @return true if this presenter collapsed the action view, false otherwise.
|
||||
*/
|
||||
public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item);
|
||||
|
||||
/**
|
||||
* Returns an ID for determining how to save/restore instance state.
|
||||
* @return a valid ID value.
|
||||
*/
|
||||
public int getId();
|
||||
|
||||
/**
|
||||
* Returns a Parcelable describing the current state of the presenter.
|
||||
* It will be passed to the {@link #onRestoreInstanceState(Parcelable)}
|
||||
* method of the presenter sharing the same ID later.
|
||||
* @return The saved instance state
|
||||
*/
|
||||
public Parcelable onSaveInstanceState();
|
||||
|
||||
/**
|
||||
* Supplies the previously saved instance state to be restored.
|
||||
* @param state The previously saved instance state
|
||||
*/
|
||||
public void onRestoreInstanceState(Parcelable state);
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* 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.menu;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
/**
|
||||
* Minimal interface for a menu view. {@link #initialize(MenuBuilder)} must be called for the
|
||||
* menu to be functional.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public interface MenuView {
|
||||
/**
|
||||
* Initializes the menu to the given menu. This should be called after the
|
||||
* view is inflated.
|
||||
*
|
||||
* @param menu The menu that this MenuView should display.
|
||||
*/
|
||||
public void initialize(MenuBuilder menu);
|
||||
|
||||
/**
|
||||
* Returns the default animations to be used for this menu when entering/exiting.
|
||||
* @return A resource ID for the default animations to be used for this menu.
|
||||
*/
|
||||
public int getWindowAnimations();
|
||||
|
||||
/**
|
||||
* Minimal interface for a menu item view. {@link #initialize(MenuItemImpl, int)} must be called
|
||||
* for the item to be functional.
|
||||
*/
|
||||
public interface ItemView {
|
||||
/**
|
||||
* Initializes with the provided MenuItemData. This should be called after the view is
|
||||
* inflated.
|
||||
* @param itemData The item that this ItemView should display.
|
||||
* @param menuType The type of this menu, one of
|
||||
* {@link MenuBuilder#TYPE_ICON}, {@link MenuBuilder#TYPE_EXPANDED},
|
||||
* {@link MenuBuilder#TYPE_DIALOG}).
|
||||
*/
|
||||
public void initialize(MenuItemImpl itemData, int menuType);
|
||||
|
||||
/**
|
||||
* Gets the item data that this view is displaying.
|
||||
* @return the item data, or null if there is not one
|
||||
*/
|
||||
public MenuItemImpl getItemData();
|
||||
|
||||
/**
|
||||
* Sets the title of the item view.
|
||||
* @param title The title to set.
|
||||
*/
|
||||
public void setTitle(CharSequence title);
|
||||
|
||||
/**
|
||||
* Sets the enabled state of the item view.
|
||||
* @param enabled Whether the item view should be enabled.
|
||||
*/
|
||||
public void setEnabled(boolean enabled);
|
||||
|
||||
/**
|
||||
* Displays the checkbox for the item view. This does not ensure the item view will be
|
||||
* checked, for that use {@link #setChecked}.
|
||||
* @param checkable Whether to display the checkbox or to hide it
|
||||
*/
|
||||
public void setCheckable(boolean checkable);
|
||||
|
||||
/**
|
||||
* Checks the checkbox for the item view. If the checkbox is hidden, it will NOT be
|
||||
* made visible, call {@link #setCheckable(boolean)} for that.
|
||||
* @param checked Whether the checkbox should be checked
|
||||
*/
|
||||
public void setChecked(boolean checked);
|
||||
|
||||
/**
|
||||
* Sets the shortcut for the item.
|
||||
* @param showShortcut Whether a shortcut should be shown(if false, the value of
|
||||
* shortcutKey should be ignored).
|
||||
* @param shortcutKey The shortcut key that should be shown on the ItemView.
|
||||
*/
|
||||
public void setShortcut(boolean showShortcut, char shortcutKey);
|
||||
|
||||
/**
|
||||
* Set the icon of this item view.
|
||||
* @param icon The icon of this item. null to hide the icon.
|
||||
*/
|
||||
public void setIcon(Drawable icon);
|
||||
|
||||
/**
|
||||
* Whether this item view prefers displaying the condensed title rather
|
||||
* than the normal title. If a condensed title is not available, the
|
||||
* normal title will be used.
|
||||
*
|
||||
* @return Whether this item view prefers displaying the condensed
|
||||
* title.
|
||||
*/
|
||||
public boolean prefersCondensedTitle();
|
||||
|
||||
/**
|
||||
* Whether this item view shows an icon.
|
||||
*
|
||||
* @return Whether this item view shows an icon.
|
||||
*/
|
||||
public boolean showsIcon();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import java.util.WeakHashMap;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.view.KeyEvent;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import com.actionbarsherlock.view.SubMenu;
|
||||
|
||||
public class MenuWrapper implements Menu {
|
||||
private final android.view.Menu mNativeMenu;
|
||||
|
||||
private final WeakHashMap<android.view.MenuItem, MenuItem> mNativeMap =
|
||||
new WeakHashMap<android.view.MenuItem, MenuItem>();
|
||||
|
||||
|
||||
public MenuWrapper(android.view.Menu nativeMenu) {
|
||||
mNativeMenu = nativeMenu;
|
||||
}
|
||||
|
||||
public android.view.Menu unwrap() {
|
||||
return mNativeMenu;
|
||||
}
|
||||
|
||||
private MenuItem addInternal(android.view.MenuItem nativeItem) {
|
||||
MenuItem item = new MenuItemWrapper(nativeItem);
|
||||
mNativeMap.put(nativeItem, item);
|
||||
return item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem add(CharSequence title) {
|
||||
return addInternal(mNativeMenu.add(title));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem add(int titleRes) {
|
||||
return addInternal(mNativeMenu.add(titleRes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem add(int groupId, int itemId, int order, CharSequence title) {
|
||||
return addInternal(mNativeMenu.add(groupId, itemId, order, title));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem add(int groupId, int itemId, int order, int titleRes) {
|
||||
return addInternal(mNativeMenu.add(groupId, itemId, order, titleRes));
|
||||
}
|
||||
|
||||
private SubMenu addInternal(android.view.SubMenu nativeSubMenu) {
|
||||
SubMenu subMenu = new SubMenuWrapper(nativeSubMenu);
|
||||
android.view.MenuItem nativeItem = nativeSubMenu.getItem();
|
||||
MenuItem item = subMenu.getItem();
|
||||
mNativeMap.put(nativeItem, item);
|
||||
return subMenu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu addSubMenu(CharSequence title) {
|
||||
return addInternal(mNativeMenu.addSubMenu(title));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu addSubMenu(int titleRes) {
|
||||
return addInternal(mNativeMenu.addSubMenu(titleRes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu addSubMenu(int groupId, int itemId, int order, CharSequence title) {
|
||||
return addInternal(mNativeMenu.addSubMenu(groupId, itemId, order, title));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) {
|
||||
return addInternal(mNativeMenu.addSubMenu(groupId, itemId, order, titleRes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int addIntentOptions(int groupId, int itemId, int order, ComponentName caller, Intent[] specifics, Intent intent, int flags, MenuItem[] outSpecificItems) {
|
||||
android.view.MenuItem[] nativeOutItems = new android.view.MenuItem[outSpecificItems.length];
|
||||
int result = mNativeMenu.addIntentOptions(groupId, itemId, order, caller, specifics, intent, flags, nativeOutItems);
|
||||
for (int i = 0, length = outSpecificItems.length; i < length; i++) {
|
||||
outSpecificItems[i] = new MenuItemWrapper(nativeOutItems[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeItem(int id) {
|
||||
mNativeMenu.removeItem(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeGroup(int groupId) {
|
||||
mNativeMenu.removeGroup(groupId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
mNativeMap.clear();
|
||||
mNativeMenu.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupCheckable(int group, boolean checkable, boolean exclusive) {
|
||||
mNativeMenu.setGroupCheckable(group, checkable, exclusive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupVisible(int group, boolean visible) {
|
||||
mNativeMenu.setGroupVisible(group, visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupEnabled(int group, boolean enabled) {
|
||||
mNativeMenu.setGroupEnabled(group, enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasVisibleItems() {
|
||||
return mNativeMenu.hasVisibleItems();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem findItem(int id) {
|
||||
android.view.MenuItem nativeItem = mNativeMenu.findItem(id);
|
||||
return findItem(nativeItem);
|
||||
}
|
||||
|
||||
public MenuItem findItem(android.view.MenuItem nativeItem) {
|
||||
if (nativeItem == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
MenuItem wrapped = mNativeMap.get(nativeItem);
|
||||
if (wrapped != null) {
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
return addInternal(nativeItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return mNativeMenu.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem getItem(int index) {
|
||||
android.view.MenuItem nativeItem = mNativeMenu.getItem(index);
|
||||
return findItem(nativeItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
mNativeMenu.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performShortcut(int keyCode, KeyEvent event, int flags) {
|
||||
return mNativeMenu.performShortcut(keyCode, event, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShortcutKey(int keyCode, KeyEvent event) {
|
||||
return mNativeMenu.isShortcutKey(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performIdentifierAction(int id, int flags) {
|
||||
return mNativeMenu.performIdentifierAction(id, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQwertyMode(boolean isQwerty) {
|
||||
mNativeMenu.setQwertyMode(isQwerty);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* 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.menu;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import com.actionbarsherlock.view.SubMenu;
|
||||
|
||||
/**
|
||||
* The model for a sub menu, which is an extension of the menu. Most methods are proxied to
|
||||
* the parent menu.
|
||||
*/
|
||||
public class SubMenuBuilder extends MenuBuilder implements SubMenu {
|
||||
private MenuBuilder mParentMenu;
|
||||
private MenuItemImpl mItem;
|
||||
|
||||
public SubMenuBuilder(Context context, MenuBuilder parentMenu, MenuItemImpl item) {
|
||||
super(context);
|
||||
|
||||
mParentMenu = parentMenu;
|
||||
mItem = item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQwertyMode(boolean isQwerty) {
|
||||
mParentMenu.setQwertyMode(isQwerty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isQwertyMode() {
|
||||
return mParentMenu.isQwertyMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShortcutsVisible(boolean shortcutsVisible) {
|
||||
mParentMenu.setShortcutsVisible(shortcutsVisible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShortcutsVisible() {
|
||||
return mParentMenu.isShortcutsVisible();
|
||||
}
|
||||
|
||||
public Menu getParentMenu() {
|
||||
return mParentMenu;
|
||||
}
|
||||
|
||||
public MenuItem getItem() {
|
||||
return mItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCallback(Callback callback) {
|
||||
mParentMenu.setCallback(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuBuilder getRootMenu() {
|
||||
return mParentMenu;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean dispatchMenuItemSelected(MenuBuilder menu, MenuItem item) {
|
||||
return super.dispatchMenuItemSelected(menu, item) ||
|
||||
mParentMenu.dispatchMenuItemSelected(menu, item);
|
||||
}
|
||||
|
||||
public SubMenu setIcon(Drawable icon) {
|
||||
mItem.setIcon(icon);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SubMenu setIcon(int iconRes) {
|
||||
mItem.setIcon(iconRes);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SubMenu setHeaderIcon(Drawable icon) {
|
||||
return (SubMenu) super.setHeaderIconInt(icon);
|
||||
}
|
||||
|
||||
public SubMenu setHeaderIcon(int iconRes) {
|
||||
return (SubMenu) super.setHeaderIconInt(iconRes);
|
||||
}
|
||||
|
||||
public SubMenu setHeaderTitle(CharSequence title) {
|
||||
return (SubMenu) super.setHeaderTitleInt(title);
|
||||
}
|
||||
|
||||
public SubMenu setHeaderTitle(int titleRes) {
|
||||
return (SubMenu) super.setHeaderTitleInt(titleRes);
|
||||
}
|
||||
|
||||
public SubMenu setHeaderView(View view) {
|
||||
return (SubMenu) super.setHeaderViewInt(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean expandItemActionView(MenuItemImpl item) {
|
||||
return mParentMenu.expandItemActionView(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collapseItemActionView(MenuItemImpl item) {
|
||||
return mParentMenu.collapseItemActionView(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActionViewStatesKey() {
|
||||
final int itemId = mItem != null ? mItem.getItemId() : 0;
|
||||
if (itemId == 0) {
|
||||
return null;
|
||||
}
|
||||
return super.getActionViewStatesKey() + ":" + itemId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import com.actionbarsherlock.view.SubMenu;
|
||||
|
||||
public class SubMenuWrapper extends MenuWrapper implements SubMenu {
|
||||
private final android.view.SubMenu mNativeSubMenu;
|
||||
private MenuItem mItem = null;
|
||||
|
||||
public SubMenuWrapper(android.view.SubMenu nativeSubMenu) {
|
||||
super(nativeSubMenu);
|
||||
mNativeSubMenu = nativeSubMenu;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SubMenu setHeaderTitle(int titleRes) {
|
||||
mNativeSubMenu.setHeaderTitle(titleRes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setHeaderTitle(CharSequence title) {
|
||||
mNativeSubMenu.setHeaderTitle(title);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setHeaderIcon(int iconRes) {
|
||||
mNativeSubMenu.setHeaderIcon(iconRes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setHeaderIcon(Drawable icon) {
|
||||
mNativeSubMenu.setHeaderIcon(icon);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setHeaderView(View view) {
|
||||
mNativeSubMenu.setHeaderView(view);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearHeader() {
|
||||
mNativeSubMenu.clearHeader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setIcon(int iconRes) {
|
||||
mNativeSubMenu.setIcon(iconRes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setIcon(Drawable icon) {
|
||||
mNativeSubMenu.setIcon(icon);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem getItem() {
|
||||
if (mItem == null) {
|
||||
mItem = new MenuItemWrapper(mNativeSubMenu.getItem());
|
||||
}
|
||||
return mItem;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user