/* * 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.android.browser.view; import com.android.browser.BreadCrumbView; import com.android.browser.BrowserBookmarksAdapter; import com.android.browser.R; import com.android.internal.view.menu.MenuBuilder; import android.content.Context; import android.database.DataSetObserver; import android.provider.BrowserContract; import android.util.AttributeSet; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseExpandableListAdapter; import android.widget.ExpandableListAdapter; import android.widget.ExpandableListView; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.TextView; import java.util.ArrayList; import java.util.HashMap; public class BookmarkExpandableGridView extends ExpandableListView implements BreadCrumbView.Controller { private BookmarkAccountAdapter mAdapter; private int mColumnWidth; private Context mContext; private OnChildClickListener mOnChildClickListener; private ContextMenuInfo mContextMenuInfo = null; private OnCreateContextMenuListener mOnCreateContextMenuListener; private boolean mLongClickable; private BreadCrumbView.Controller mBreadcrumbController; public BookmarkExpandableGridView(Context context) { super(context); init(context); } public BookmarkExpandableGridView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public BookmarkExpandableGridView( Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } void init(Context context) { mContext = context; setItemsCanFocus(true); setLongClickable(false); mAdapter = new BookmarkAccountAdapter(mContext); super.setAdapter(mAdapter); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mAdapter.measureChildren(); } @Override public void setAdapter(ExpandableListAdapter adapter) { throw new RuntimeException("Not supported"); } public void setColumnWidthFromLayout(int layout) { LayoutInflater infalter = LayoutInflater.from(mContext); View v = infalter.inflate(layout, this, false); v.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); mColumnWidth = v.getMeasuredWidth(); } public void setHorizontalSpacing(int horizontalSpacing) { // TODO Auto-generated method stub } public void clearAccounts() { mAdapter.clear(); } public void addAccount(String accountName, BrowserBookmarksAdapter adapter) { // First, check if it already exists int indexOf = mAdapter.mGroups.indexOf(accountName); if (indexOf >= 0) { BrowserBookmarksAdapter existing = mAdapter.mChildren.get(indexOf); if (existing != adapter) { existing.unregisterDataSetObserver(mAdapter.mObserver); // Replace the existing one mAdapter.mChildren.remove(indexOf); mAdapter.mChildren.add(indexOf, adapter); adapter.registerDataSetObserver(mAdapter.mObserver); } } else { mAdapter.mGroups.add(accountName); mAdapter.mChildren.add(adapter); adapter.registerDataSetObserver(mAdapter.mObserver); } mAdapter.notifyDataSetChanged(); expandGroup(mAdapter.getGroupCount() - 1); } @Override public void setOnChildClickListener(OnChildClickListener onChildClickListener) { mOnChildClickListener = onChildClickListener; } @Override public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { mOnCreateContextMenuListener = l; if (!mLongClickable) { mLongClickable = true; if (mAdapter != null) { mAdapter.notifyDataSetChanged(); } } } @Override public void createContextMenu(ContextMenu menu) { // The below is copied from View - we want to bypass the override // in AbsListView ContextMenuInfo menuInfo = getContextMenuInfo(); // Sets the current menu info so all items added to menu will have // my extra info set. ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); onCreateContextMenu(menu); if (mOnCreateContextMenuListener != null) { mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); } // Clear the extra information so subsequent items that aren't mine don't // have my extra info. ((MenuBuilder)menu).setCurrentMenuInfo(null); if (mParent != null) { mParent.createContextMenu(menu); } } @Override public boolean showContextMenuForChild(View originalView) { int groupPosition = (Integer) originalView.getTag(R.id.group_position); int childPosition = (Integer) originalView.getTag(R.id.child_position); mContextMenuInfo = new BookmarkContextMenuInfo(originalView, childPosition, groupPosition); if (getParent() != null) { getParent().showContextMenuForChild(this); } return true; } @Override public void onTop(BreadCrumbView view, int level, Object data) { if (mBreadcrumbController != null) { mBreadcrumbController.onTop(view, level, data); } } public void setBreadcrumbController(BreadCrumbView.Controller controller) { mBreadcrumbController = controller; } @Override protected ContextMenuInfo getContextMenuInfo() { return mContextMenuInfo; } public BrowserBookmarksAdapter getChildAdapter(int groupPosition) { return mAdapter.mChildren.get(groupPosition); } private OnClickListener mChildClickListener = new OnClickListener() { @Override public void onClick(View v) { int groupPosition = (Integer) v.getTag(R.id.group_position); int childPosition = (Integer) v.getTag(R.id.child_position); long id = (Long) v.getTag(R.id.child_id); if (mOnChildClickListener != null) { mOnChildClickListener.onChildClick(BookmarkExpandableGridView.this, v, groupPosition, childPosition, id); } } }; private OnClickListener mGroupOnClickListener = new OnClickListener() { @Override public void onClick(View v) { int groupPosition = (Integer) v.getTag(R.id.group_position); if (isGroupExpanded(groupPosition)) { collapseGroup(groupPosition); } else { expandGroup(groupPosition); } } }; public BreadCrumbView getBreadCrumbs(int groupPosition) { return mAdapter.getBreadCrumbView(groupPosition); } class BookmarkAccountAdapter extends BaseExpandableListAdapter { ArrayList mChildren; ArrayList mGroups; HashMap mBreadcrumbs = new HashMap(); LayoutInflater mInflater; int mRowCount = 1; // assume at least 1 child fits in a row int mLastViewWidth = -1; int mRowPadding = -1; DataSetObserver mObserver = new DataSetObserver() { @Override public void onChanged() { notifyDataSetChanged(); } @Override public void onInvalidated() { notifyDataSetChanged(); } }; public BookmarkAccountAdapter(Context context) { mContext = context; mInflater = LayoutInflater.from(mContext); mChildren = new ArrayList(); mGroups = new ArrayList(); } public void clear() { mGroups.clear(); mChildren.clear(); notifyDataSetChanged(); } @Override public Object getChild(int groupPosition, int childPosition) { return mChildren.get(groupPosition).getItem(childPosition); } @Override public long getChildId(int groupPosition, int childPosition) { return childPosition; } @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { if (convertView == null) { convertView = mInflater.inflate(R.layout.bookmark_grid_row, parent, false); } LinearLayout row = (LinearLayout) convertView; row.setPadding( mRowPadding, row.getPaddingTop(), mRowPadding, row.getPaddingBottom()); if (row.getChildCount() > mRowCount) { row.removeViews(mRowCount, row.getChildCount() - mRowCount); } for (int i = 0; i < mRowCount; i++) { View cv = null; if (row.getChildCount() > i) { cv = row.getChildAt(i); } int realChildPosition = (childPosition * mRowCount) + i; BrowserBookmarksAdapter childAdapter = mChildren.get(groupPosition); if (realChildPosition < childAdapter.getCount()) { View v = childAdapter.getView(realChildPosition, cv, row); v.setTag(R.id.group_position, groupPosition); v.setTag(R.id.child_position, realChildPosition); v.setTag(R.id.child_id, childAdapter.getItemId(realChildPosition)); v.setOnClickListener(mChildClickListener); v.setLongClickable(mLongClickable); if (cv == null) { row.addView(v); } else if (cv != v) { row.removeViewAt(i); row.addView(v, i); } else { cv.setVisibility(View.VISIBLE); } } else if (cv != null) { cv.setVisibility(View.GONE); } } return row; } @Override public int getChildrenCount(int groupPosition) { return (int) Math.ceil( mChildren.get(groupPosition).getCount() / (float)mRowCount); } @Override public Object getGroup(int groupPosition) { return mChildren.get(groupPosition); } @Override public int getGroupCount() { return mGroups.size(); } public void measureChildren() { int viewWidth = getMeasuredWidth(); if (mLastViewWidth == viewWidth) return; ViewGroup parent = (ViewGroup) mInflater.inflate(R.layout.bookmark_grid_row, null); viewWidth -= parent.getPaddingLeft() + parent.getPaddingRight(); int rowCount = viewWidth / mColumnWidth; int rowPadding = (viewWidth - (rowCount * mColumnWidth)) / 2; boolean notify = rowCount != mRowCount || rowPadding != mRowPadding; mRowCount = rowCount; mRowPadding = rowPadding; mLastViewWidth = viewWidth; if (notify) { notifyDataSetChanged(); } } @Override public long getGroupId(int groupPosition) { return groupPosition; } @Override public View getGroupView(int groupPosition, boolean isExpanded, View view, ViewGroup parent) { if (view == null) { view = mInflater.inflate(R.layout.bookmark_group_view, parent, false); view.setOnClickListener(mGroupOnClickListener); } view.setTag(R.id.group_position, groupPosition); FrameLayout crumbHolder = (FrameLayout) view.findViewById(R.id.crumb_holder); crumbHolder.removeAllViews(); BreadCrumbView crumbs = getBreadCrumbView(groupPosition); if (crumbs.getParent() != null) { ((ViewGroup)crumbs.getParent()).removeView(crumbs); } crumbHolder.addView(crumbs); TextView name = (TextView) view.findViewById(R.id.group_name); String groupName = mGroups.get(groupPosition); if (groupName == null) { groupName = mContext.getString(R.string.local_bookmarks); } name.setText(groupName); return view; } public BreadCrumbView getBreadCrumbView(int groupPosition) { BreadCrumbView crumbs = mBreadcrumbs.get(groupPosition); if (crumbs == null) { crumbs = (BreadCrumbView) mInflater.inflate(R.layout.bookmarks_header, null); crumbs.setController(BookmarkExpandableGridView.this); crumbs.setUseBackButton(true); crumbs.setMaxVisible(2); String bookmarks = mContext.getString(R.string.bookmarks); crumbs.pushView(bookmarks, false, BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER); crumbs.setTag(R.id.group_position, groupPosition); mBreadcrumbs.put(groupPosition, crumbs); } return crumbs; } @Override public boolean hasStableIds() { return false; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } } public static class BookmarkContextMenuInfo implements ContextMenuInfo { private BookmarkContextMenuInfo(View targetView, int childPosition, int groupPosition) { this.targetView = targetView; this.childPosition = childPosition; this.groupPosition = groupPosition; } public View targetView; public int childPosition; public int groupPosition; } }