Android Open Source - android_widget_adapters Selection Module






From Project

Back to project page android_widget_adapters.

License

The source code is released under:

[Apache License](http://www.apache.org/licenses/): Version 2.0, January 2004 =============== ## TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION ## ### 1. Definitions. ### "License" sha...

If you think the Android project android_widget_adapters listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * =================================================================================================
 *                 Copyright (C) 2013 - 2014 Martin Albedinsky [Wolf-ITechnologies]
 * =================================================================================================
 *         Licensed under the Apache License, Version 2.0 or later (further "License" only).
 * -------------------------------------------------------------------------------------------------
 * You may use this file only in compliance with the License. More details and copy of this License
 * you may obtain at/*from  w w  w .j av  a  2s .c o  m*/
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * You can redistribute, modify or publish any part of the code written within this file but as it
 * is described in the License, the software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES or CONDITIONS OF ANY KIND.
 *
 * See the License for the specific language governing permissions and limitations under the License.
 * =================================================================================================
 */
package com.wit.android.ui.widget.adapter.module;

import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.SparseIntArray;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * <h3>Class Overview</h3>
 * todo: description
 *
 * @author Martin Albedinsky
 */
public class SelectionModule extends AdapterModule {

  /**
   * Interface ===================================================================================
   */

  /**
   * <h3>Annotation Overview</h3>
   * Defines an annotation for determining set of allowed modes for {@link #setMode(int)} method.
   */
  @Retention(RetentionPolicy.SOURCE)
  @IntDef({MODE_SINGLE, MODE_MULTIPLE})
  public @interface Mode {}

  /**
   * Constants ===================================================================================
   */

  /**
   * Log TAG.
   */
  // private static final String TAG = "SelectionModule";

  /**
   * Flag indicating whether the debug output trough log-cat is enabled or not.
   */
  // private static final boolean DEBUG_ENABLED = true;

  /**
   * Flag indicating whether the output trough log-cat is enabled or not.
   */
  // private static final boolean LOG_ENABLED = true;

  /**
   * Mode to allow only single selected position.
   *
   * @see #getSelectedPosition()
   */
  public static final int MODE_SINGLE = 0x00;

  /**
   * Mode to allow multiple selected positions.
   *
   * @see #getSelectedPositions()
   */
  public static final int MODE_MULTIPLE = 0x01;

  /**
   * Static members ==============================================================================
   */

  /**
   * Members =====================================================================================
   */

  /**
   * Set of the currently selected positions.
   */
  private final SparseIntArray SELECTION = new SparseIntArray();

  /**
   * Current selection mode of this module.
   */
  private int mMode = MODE_SINGLE;

  /**
   * Constructors ================================================================================
   */

  /**
   * Methods =====================================================================================
   */

  /**
   * Public --------------------------------------------------------------------------------------
   */

  /**
   * Checks whether the specified position is currently selected or not.
   *
   * @param position The position of an item of which selection state to check.
   * @return {@code True} if the specified position is selected, {@code false} otherwise.
   * @see #setSelected(int, boolean)
   * @see #toggleSelectionState(int)
   */
  public boolean isSelected(int position) {
    return contains(position);
  }

  /**
   * Changes selection state of the specified position to the opposite one
   * ({@code selected -> unselected; unselected -> selected}) and <b>notifies adapter</b>.
   *
   * @param position The position of an item of which selection state to toggle.
   * @return Count of the currently selected positions.
   * @see #setSelected(int, boolean)
   * @see #isAdapterNotificationEnabled()
   */
  public int toggleSelectionState(int position) {
    setSelected(position, !contains(position));
    return getSelectionCount();
  }

  /**
   * Changes selection state of the specified position to the desired one and <b>notifies adapter</b>.
   *
   * @param position The position of an item of which selection state to change.
   * @param selected New selection state.
   * @see #selectRange(int, int)
   * @see #selectAll()
   * @see #toggleSelectionState(int)
   * @see #isAdapterNotificationEnabled()
   */
  public void setSelected(int position, boolean selected) {
    switch (getMode()) {
      case MODE_MULTIPLE:
        break;
      case MODE_SINGLE:
        clearSelection(false);
        break;
    }

    if (selected) {
      select(position);
    } else {
      deselect(position);
    }
    notifyAdapter();
  }

  /**
   * Same as {@link #selectRange(int, int)} with parameters {@code (0, ModuleAdapter.getCount())}.
   *
   * @see #setSelected(int, boolean)
   */
  public void selectAll() {
    this.checkActualModeFor(MODE_MULTIPLE, "select all items");
    selectRange(0, mAdapter.getCount());
  }

  /**
   * Selects positions in the range {@code [startPosition, startPosition + count]} and
   * <b>notifies adapter</b>.
   * <p>
   * All previously selected positions will remain selected.
   *
   * @param startPosition The position from which to start selection.
   * @param count         Count of items to select from the start position.
   * @throws IllegalStateException     If the current mode is not set to {@link #MODE_MULTIPLE}.
   * @throws IndexOutOfBoundsException If {@code startPosition + count > n}.
   * @see #selectAll()
   * @see #setSelected(int, boolean)
   * @see #isAdapterNotificationEnabled()
   */
  public void selectRange(int startPosition, int count) {
    this.checkActualModeFor(MODE_MULTIPLE, "select all items");
    // Check correct index.
    final int n = mAdapter.getCount();
    if (startPosition + count > n) {
      throw new IndexOutOfBoundsException("Incorrect count(" + count + ") for start position(" + startPosition + "). Adapter has only " + n + " items.");
    }

    // Select all items in the requested range.
    for (int i = startPosition; i < startPosition + count; i++) {
      select(i);
    }
    notifyAdapter();
  }

  /**
   * Deselects all currently selected positions and <b>notifies adapter</b>.
   *
   * @see #clearSelectionInRange(int, int)
   * @see #isAdapterNotificationEnabled()
   */
  public void clearSelection() {
    clearSelection(true);
  }

  /**
   * Deselects all currently selected positions in the range {@code [startPosition, startPosition + count]}
   * and <b>notifies adapter</b>.
   *
   * @param startPosition The position from which to start deselection.
   * @param count         Count of items to deselect from the start position.
   * @throws IllegalStateException     If the current mode is not set to {@link #MODE_MULTIPLE}.
   * @throws IndexOutOfBoundsException If {@code startPosition + count > n}.
   * @see #clearSelection()
   * @see #isAdapterNotificationEnabled()
   */
  public void clearSelectionInRange(int startPosition, int count) {
    this.checkActualModeFor(MODE_MULTIPLE, "clear all selected items");
    // Check correct index.
    final int n = mAdapter.getCount();
    if (startPosition + count > n) {
      throw new IndexOutOfBoundsException("Incorrect count(" + count + ") for start position(" + startPosition + "). Adapter has only " + n + " items.");
    }

    // Deselect all items in the requested range.
    for (int i = startPosition; i < startPosition + count; i++) {
      deselect(i);
    }
    notifyAdapter();
  }

  /**
   * @return {@code True} whether there are some selected positions to save, {@code false}
   * otherwise.
   */
  @Override
  public boolean requiresStateSaving() {
    return SELECTION.size() > 0;
  }

  /**
   * Getters + Setters ---------------------------------------------------------------------------
   */

  /**
   * Returns the sparse array with the currently selected positions.
   *
   * @return {@link android.util.SparseIntArray} with positions which are at this time selected.
   * <b>Note</b> that this array is sorted for optimization (from lowest to highest position).
   */
  @NonNull
  public SparseIntArray getSelection() {
    return SELECTION;
  }

  /**
   * Returns the current selection size.
   *
   * @return Count of the currently selected positions.
   */
  public int getSelectionCount() {
    return SELECTION.size();
  }

  /**
   * Returns the position which is at this time selected.
   *
   * @return Currently selected position or {@code -1} if there is no position selected at
   * this time.
   * @throws IllegalStateException If the current mode is not set to {@link #MODE_SINGLE}.
   * @see #getSelectedPositions()
   */
  public int getSelectedPosition() {
    this.checkActualModeFor(MODE_SINGLE, "obtain selected item position");
    return SELECTION.size() > 0 ? SELECTION.get(SELECTION.keyAt(0)) : -1;
  }

  /**
   * Same as {@link #getSelectedPositions(boolean)} with {@code true} for <var>ascending</var>
   * parameter, so items in the array will be sorted ascending.
   */
  @NonNull
  public int[] getSelectedPositions() {
    return getSelectedPositions(true);
  }

  /**
   * Returns an array with all positions which are currently selected.
   * <p>
   * <b>Note</b>, that array is obtained/processed from the {@link android.util.SparseIntArray},
   * so its items will be by default sorted ascending.
   *
   * @param ascending {@code False} to sort array items descending, {@code true} to ascending.
   * @return Array with all currently selected positions.
   * @throws IllegalStateException If the current mode is not set to {@link #MODE_MULTIPLE}.
   * @see #getSelectedPositions()
   */
  @NonNull
  public int[] getSelectedPositions(boolean ascending) {
    this.checkActualModeFor(MODE_MULTIPLE, "obtain selected items position");
    final int[] positions = new int[SELECTION.size()];
    for (int i = 0; i < positions.length; i++) {
      positions[i] = SELECTION.keyAt(i);
    }
    return ascending ? positions : reversePositions(positions);
  }

  /**
   * Sets the current selection mode of this module to the specified one.
   *
   * @param mode The desired selection mode. One of {@link #MODE_SINGLE} or {@link #MODE_MULTIPLE}.
   * @see #getMode()
   */
  public void setMode(@Mode int mode) {
    switch (mode) {
      case MODE_SINGLE:
      case MODE_MULTIPLE:
        this.mMode = mode;
    }
  }

  /**
   * Returns the current selection mode of this module.
   *
   * @return Current selection mode (one of {@link #MODE_SINGLE}, {@link #MODE_MULTIPLE}) or {@link #MODE_SINGLE}
   * by default.
   * @see #setMode(int)
   */
  @Mode
  public int getMode() {
    return mMode;
  }

  /**
   * Protected -----------------------------------------------------------------------------------
   */

  /**
   * Checks whether a set of the currently selected positions contains the specified position or not.
   *
   * @param position The position to check.
   * @return {@code True} if the specified position is presented within a set of the currently
   * selected positions, {@code false} otherwise.
   */
  protected final boolean contains(int position) {
    return SELECTION.indexOfKey(position) >= 0;
  }

  /**
   * Adds the specified position into a set of the currently selected positions.
   *
   * @param position The position to add into the selected ones.
   */
  protected final void select(int position) {
    SELECTION.append(position, position);
  }

  /**
   * Removes the specified position form a set of the currently selected positions.
   *
   * @param position The position to remove from the selected ones.
   */
  protected final void deselect(int position) {
    final int index = SELECTION.indexOfKey(position);
    if (index >= 0) {
      SELECTION.removeAt(index);
    }
  }

  /**
   * Removes all positions form a set of the currently selected positions.
   *
   * @param notify {@code True} to notify the currently attached adapter by {@link #notifyAdapter()},
   *               {@code false} otherwise.
   */
  protected final void clearSelection(boolean notify) {
    SELECTION.clear();
    if (notify) {
      notifyAdapter();
    }
  }

  /**
   */
  @NonNull
  @Override
  protected Parcelable onSaveInstanceState() {
    final SavedState state = new SavedState(super.onSaveInstanceState());
    state.mode = mMode;
    // Change mode to obtain selected positions.
    this.mMode = MODE_MULTIPLE;
    // Save selected item positions.
    state.selectedItems = getSelectedPositions();
    return state;
  }

  /**
   */
  @Override
  protected void onRestoreInstanceState(@NonNull Parcelable savedState) {
    if (!(savedState instanceof SavedState)) {
      super.onRestoreInstanceState(savedState);
      return;
    }

    final SavedState state = (SavedState) savedState;
    super.onRestoreInstanceState(state.getSuperState());

    // Restore selected item positions.
    int[] selected = state.selectedItems;
    if (selected != null && selected.length > 0) {
      for (int i : selected) {
        select(i);
      }
    }
    // Restore mode.
    this.mMode = state.mode;
    notifyAdapter();
  }

  /**
   * Private -------------------------------------------------------------------------------------
   */

  /**
   * Check whether the current mode complies with the requested mode for the given action. If not
   * the IllegalStateException is thrown.
   *
   * @param requiredMode Flag of the required mode.
   * @param action       Action for which is this check performed.
   */
  private void checkActualModeFor(int requiredMode, String action) {
    if (mMode != requiredMode) {
      throw new IllegalStateException("Can't " + action + ". Not in required(" + getModeName(requiredMode) + ") mode.");
    }
  }

  /**
   * Returns name for the given mode.
   *
   * @param mode Mode identifier.
   * @return Name of the requested mode.
   */
  private String getModeName(int mode) {
    switch (mode) {
      case MODE_MULTIPLE:
        return "MODE_MULTIPLE";
      case MODE_SINGLE:
        return "MODE_SINGLE";
    }
    return "";
  }

  /**
   * Reverses the given array of positions.
   *
   * @param positions Array to reverse.
   * @return Reversed array.
   */
  private int[] reversePositions(int[] positions) {
    final int[] reverse = new int[positions.length];
    for (int i = 0; i < reverse.length; i++) {
      reverse[i] = positions[positions.length - (i + 1)];
    }
    return reverse;
  }

  /**
   * Inner classes ===============================================================================
   */

  /**
   * <h3>Class Overview</h3>
   * todo: description
   *
   * @author Martin Albedinsky
   */
  public static class SavedState extends BaseSavedState {

    /**
     * Members =================================================================================
     */

    /**
     * Creator used to create an instance or array of instances of SavedState from {@link android.os.Parcel}.
     */
    public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
      /**
       */
      @Override
      public SavedState createFromParcel(Parcel source) {
        return new SavedState(source);
      }

      /**
       */
      @Override
      public SavedState[] newArray(int size) {
        return new SavedState[size];
      }
    };

    /**
     * Selection module mode to save and restore.
     */
    private int mode = MODE_SINGLE;

    /**
     * Selection module selected items set to save and restore.
     */
    private int[] selectedItems = {};

    /**
     * Constructors ============================================================================
     */

    /**
     * Creates a new instance SavedState with the given <var>superState</var> to allow
     * chaining of saved states in {@link #onSaveInstanceState()} and also in
     * {@link #onRestoreInstanceState(android.os.Parcelable)}.
     *
     * @param superState A super state obtained from {@code super.onSaveInstanceState()}
     *                   within {@code onSaveInstanceState()} of a specific {@link SelectionModule}
     *                   implementation.
     */
    protected SavedState(@Nullable Parcelable superState) {
      super(superState);
    }

    /**
     * Called form {@link #CREATOR} to create an instance of SavedState form the given parcel
     * <var>source</var>.
     *
     * @param source Parcel with data for a new instance.
     */
    protected SavedState(@NonNull Parcel source) {
      super(source);
      this.mode = source.readInt();
      this.selectedItems = source.createIntArray();
    }

    /**
     * Methods =================================================================================
     */

    /**
     */
    @Override
    public void writeToParcel(@NonNull Parcel dest, int flags) {
      super.writeToParcel(dest, flags);
      dest.writeInt(mode);
      dest.writeIntArray(selectedItems);
    }
  }
}




Java Source Code List

com.wit.android.ui.widget.adapter.AdapterAnnotations.java
com.wit.android.ui.widget.adapter.AdapterWrapper.java
com.wit.android.ui.widget.adapter.AdaptersConfig.java
com.wit.android.ui.widget.adapter.BaseAdapter.java
com.wit.android.ui.widget.adapter.BaseMultiAdapter.java
com.wit.android.ui.widget.adapter.BaseSpinnerAdapter.java
com.wit.android.ui.widget.adapter.FactoryHolderAdapter.java
com.wit.android.ui.widget.adapter.LoadableAdapter.java
com.wit.android.ui.widget.adapter.MissingUiAnnotationException.java
com.wit.android.ui.widget.adapter.ModuleManager.java
com.wit.android.ui.widget.adapter.OnDataSetActionListener.java
com.wit.android.ui.widget.adapter.OnDataSetListener.java
com.wit.android.ui.widget.adapter.SimpleAdapter.java
com.wit.android.ui.widget.adapter.SimpleSpinnerAdapter.java
com.wit.android.ui.widget.adapter.StateAdapter.java
com.wit.android.ui.widget.adapter.ViewHolderFactory.java
com.wit.android.ui.widget.adapter.ViewHolder.java
com.wit.android.ui.widget.adapter.annotation.DropDownViewHolderFactory.java
com.wit.android.ui.widget.adapter.annotation.DropDownViewHolder.java
com.wit.android.ui.widget.adapter.annotation.DropDownView.java
com.wit.android.ui.widget.adapter.annotation.ItemViewHolderFactory.java
com.wit.android.ui.widget.adapter.annotation.ItemViewHolder.java
com.wit.android.ui.widget.adapter.annotation.ItemView.java
com.wit.android.ui.widget.adapter.module.AdapterModule.java
com.wit.android.ui.widget.adapter.module.AlphabeticHeaders.java
com.wit.android.ui.widget.adapter.module.HeadersModule.java
com.wit.android.ui.widget.adapter.module.SelectionModule.java