• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.documentsui.selection;
17 
18 import static android.support.v4.util.Preconditions.checkArgument;
19 import static android.support.v7.widget.RecyclerView.NO_POSITION;
20 import static com.android.documentsui.selection.Shared.DEBUG;
21 import static com.android.documentsui.selection.Shared.TAG;
22 
23 import android.util.Log;
24 
25 import com.android.documentsui.selection.DefaultSelectionHelper.RangeType;
26 
27 /**
28  * Class providing support for managing range selections.
29  */
30 final class Range {
31 
32     private final Callbacks mCallbacks;
33     private final int mBegin;
34     private int mEnd = NO_POSITION;
35 
Range(Callbacks callbacks, int begin)36     public Range(Callbacks callbacks, int begin) {
37         if (DEBUG) Log.d(TAG, "New Ranger created beginning @ " + begin);
38         mCallbacks = callbacks;
39         mBegin = begin;
40     }
41 
extendSelection(int position, @RangeType int type)42     void extendSelection(int position, @RangeType int type) {
43         checkArgument(position != NO_POSITION, "Position cannot be NO_POSITION.");
44 
45         if (mEnd == NO_POSITION || mEnd == mBegin) {
46             // Reset mEnd so it can be established in establishRange.
47             mEnd = NO_POSITION;
48             establishRange(position, type);
49         } else {
50             reviseRange(position, type);
51         }
52     }
53 
establishRange(int position, @RangeType int type)54     private void establishRange(int position, @RangeType int type) {
55         checkArgument(mEnd == NO_POSITION, "End has already been set.");
56 
57         if (position == mBegin) {
58             mEnd = position;
59         }
60 
61         if (position > mBegin) {
62             updateRange(mBegin + 1, position, true, type);
63         } else if (position < mBegin) {
64             updateRange(position, mBegin - 1, true, type);
65         }
66 
67         mEnd = position;
68     }
69 
reviseRange(int position, @RangeType int type)70     private void reviseRange(int position, @RangeType int type) {
71         checkArgument(mEnd != NO_POSITION, "End must already be set.");
72         checkArgument(mBegin != mEnd, "Beging and end point to same position.");
73 
74         if (position == mEnd) {
75             if (DEBUG) Log.v(TAG, "Ignoring no-op revision for range: " + this);
76         }
77 
78         if (mEnd > mBegin) {
79             reviseAscendingRange(position, type);
80         } else if (mEnd < mBegin) {
81             reviseDescendingRange(position, type);
82         }
83         // the "else" case is covered by checkState at beginning of method.
84 
85         mEnd = position;
86     }
87 
88     /**
89      * Updates an existing ascending selection.
90      * @param position
91      */
reviseAscendingRange(int position, @RangeType int type)92     private void reviseAscendingRange(int position, @RangeType int type) {
93         // Reducing or reversing the range....
94         if (position < mEnd) {
95             if (position < mBegin) {
96                 updateRange(mBegin + 1, mEnd, false, type);
97                 updateRange(position, mBegin -1, true, type);
98             } else {
99                 updateRange(position + 1, mEnd, false, type);
100             }
101         }
102 
103         // Extending the range...
104         else if (position > mEnd) {
105             updateRange(mEnd + 1, position, true, type);
106         }
107     }
108 
reviseDescendingRange(int position, @RangeType int type)109     private void reviseDescendingRange(int position, @RangeType int type) {
110         // Reducing or reversing the range....
111         if (position > mEnd) {
112             if (position > mBegin) {
113                 updateRange(mEnd, mBegin - 1, false, type);
114                 updateRange(mBegin + 1, position, true, type);
115             } else {
116                 updateRange(mEnd, position - 1, false, type);
117             }
118         }
119 
120         // Extending the range...
121         else if (position < mEnd) {
122             updateRange(position, mEnd - 1, true, type);
123         }
124     }
125 
126     /**
127      * Try to set selection state for all elements in range. Not that callbacks can cancel
128      * selection of specific items, so some or even all items may not reflect the desired state
129      * after the update is complete.
130      *
131      * @param begin Adapter position for range start (inclusive).
132      * @param end Adapter position for range end (inclusive).
133      * @param selected New selection state.
134      */
updateRange(int begin, int end, boolean selected, @RangeType int type)135     private void updateRange(int begin, int end, boolean selected, @RangeType int type) {
136         mCallbacks.updateForRange(begin, end, selected, type);
137     }
138 
139     @Override
toString()140     public String toString() {
141         return "Range{begin=" + mBegin + ", end=" + mEnd + "}";
142     }
143 
144     /*
145      * @see {@link DefaultSelectionHelper#updateForRange(int, int , boolean, int)}.
146      */
147     static abstract class Callbacks {
updateForRange( int begin, int end, boolean selected, @RangeType int type)148         abstract void updateForRange(
149                 int begin, int end, boolean selected, @RangeType int type);
150     }
151 }
152