// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package org.chromium.chrome.browser.widget.selection; import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; import android.widget.Checkable; import android.widget.FrameLayout; import org.chromium.chrome.R; import org.chromium.chrome.browser.widget.selection.SelectionDelegate.SelectionObserver; import java.util.List; /** * An item that can be selected. When selected, the item will be highlighted. A selection is * initially established via long-press. If a selection is already established, clicking on the item * will toggle its selection. * * @param <E> The type of the item associated with this SelectableItemView. */ public abstract class SelectableItemView<E> extends FrameLayout implements Checkable, OnClickListener, OnLongClickListener, SelectionObserver<E> { private SelectionDelegate<E> mSelectionDelegate; private SelectableItemHighlightView mHighlightView; private E mItem; /** * Constructor for inflating from XML. */ public SelectableItemView(Context context, AttributeSet attrs) { super(context, attrs); } /** * Destroys and cleans up itself. */ public void destroy() { if (mSelectionDelegate != null) { mSelectionDelegate.removeObserver(this); } } /** * Sets the SelectionDelegate and registers this object as an observer. The SelectionDelegate * must be set before the item can respond to click events. * @param delegate The SelectionDelegate that will inform this item of selection changes. */ public void setSelectionDelegate(SelectionDelegate<E> delegate) { if (mSelectionDelegate != delegate) { if (mSelectionDelegate != null) mSelectionDelegate.removeObserver(this); mSelectionDelegate = delegate; mSelectionDelegate.addObserver(this); } } /** * @param item The item associated with this SelectableItemView. */ public void setItem(E item) { mItem = item; setChecked(mSelectionDelegate.isItemSelected(item)); } // FrameLayout implementations. @Override protected void onFinishInflate() { super.onFinishInflate(); inflate(getContext(), R.layout.selectable_item_highlight_view, this); mHighlightView = (SelectableItemHighlightView) findViewById(R.id.highlight); setOnClickListener(this); setOnLongClickListener(this); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); if (mSelectionDelegate != null) { setChecked(mSelectionDelegate.isItemSelected(mItem)); } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); setChecked(false); } // OnClickListener implementation. @Override public final void onClick(View view) { assert view == this; if (mSelectionDelegate.isSelectionEnabled()) { onLongClick(view); } else { onClick(); } } // OnLongClickListener implementation. @Override public boolean onLongClick(View view) { assert view == this; boolean checked = mSelectionDelegate.toggleSelectionForItem(mItem); setChecked(checked); return true; } // Checkable implementations. @Override public boolean isChecked() { return mHighlightView.isChecked(); } @Override public void toggle() { setChecked(!isChecked()); } @Override public void setChecked(boolean checked) { mHighlightView.setChecked(checked); } // SelectionObserver implementation. @Override public void onSelectionStateChange(List<E> selectedItems) { setChecked(mSelectionDelegate.isItemSelected(mItem)); } /** * Same as {@link OnClickListener#onClick(View)} on this. * Subclasses should override this instead of setting their own OnClickListener because this * class handles onClick events in selection mode, and won't forward events to subclasses in * that case. */ protected abstract void onClick(); }