SelectionManager.java revision b21b8e58a604f6c701245d84b141b5b87663192b
1/*
2 * Copyright (C) 2010 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
17package com.android.gallery3d.ui;
18
19import com.android.gallery3d.app.AbstractGalleryActivity;
20import com.android.gallery3d.data.DataManager;
21import com.android.gallery3d.data.MediaItem;
22import com.android.gallery3d.data.MediaSet;
23import com.android.gallery3d.data.Path;
24
25import java.util.ArrayList;
26import java.util.HashSet;
27import java.util.Set;
28
29public class SelectionManager {
30    @SuppressWarnings("unused")
31    private static final String TAG = "SelectionManager";
32
33    public static final int ENTER_SELECTION_MODE = 1;
34    public static final int LEAVE_SELECTION_MODE = 2;
35    public static final int SELECT_ALL_MODE = 3;
36
37    private Set<Path> mClickedSet;
38    private MediaSet mSourceMediaSet;
39    private SelectionListener mListener;
40    private DataManager mDataManager;
41    private boolean mInverseSelection;
42    private boolean mIsAlbumSet;
43    private boolean mInSelectionMode;
44    private boolean mAutoLeave = true;
45    private int mTotal;
46
47    public interface SelectionListener {
48        public void onSelectionModeChange(int mode);
49        public void onSelectionChange(Path path, boolean selected);
50    }
51
52    public SelectionManager(AbstractGalleryActivity activity, boolean isAlbumSet) {
53        mDataManager = activity.getDataManager();
54        mClickedSet = new HashSet<Path>();
55        mIsAlbumSet = isAlbumSet;
56        mTotal = -1;
57    }
58
59    // Whether we will leave selection mode automatically once the number of
60    // selected items is down to zero.
61    public void setAutoLeaveSelectionMode(boolean enable) {
62        mAutoLeave = enable;
63    }
64
65    public void setSelectionListener(SelectionListener listener) {
66        mListener = listener;
67    }
68
69    public void selectAll() {
70        mInverseSelection = true;
71        mClickedSet.clear();
72        enterSelectionMode();
73        if (mListener != null) mListener.onSelectionModeChange(SELECT_ALL_MODE);
74    }
75
76    public void deSelectAll() {
77        leaveSelectionMode();
78        mInverseSelection = false;
79        mClickedSet.clear();
80    }
81
82    public boolean inSelectAllMode() {
83        return mInverseSelection;
84    }
85
86    public boolean inSelectionMode() {
87        return mInSelectionMode;
88    }
89
90    public void enterSelectionMode() {
91        if (mInSelectionMode) return;
92
93        mInSelectionMode = true;
94        if (mListener != null) mListener.onSelectionModeChange(ENTER_SELECTION_MODE);
95    }
96
97    public void leaveSelectionMode() {
98        if (!mInSelectionMode) return;
99
100        mInSelectionMode = false;
101        mInverseSelection = false;
102        mClickedSet.clear();
103        if (mListener != null) mListener.onSelectionModeChange(LEAVE_SELECTION_MODE);
104    }
105
106    public boolean isItemSelected(Path itemId) {
107        return mInverseSelection ^ mClickedSet.contains(itemId);
108    }
109
110    private int getTotalCount() {
111        if (mSourceMediaSet == null) return -1;
112
113        if (mTotal < 0) {
114            mTotal = mIsAlbumSet
115                    ? mSourceMediaSet.getSubMediaSetCount()
116                    : mSourceMediaSet.getMediaItemCount();
117        }
118        return mTotal;
119    }
120
121    public int getSelectedCount() {
122        int count = mClickedSet.size();
123        if (mInverseSelection) {
124            count = getTotalCount() - count;
125        }
126        return count;
127    }
128
129    public void toggle(Path path) {
130        if (mClickedSet.contains(path)) {
131            mClickedSet.remove(path);
132        } else {
133            enterSelectionMode();
134            mClickedSet.add(path);
135        }
136
137        // Convert to inverse selection mode if everything is selected.
138        int count = getSelectedCount();
139        if (count == getTotalCount()) {
140            selectAll();
141        }
142
143        if (mListener != null) mListener.onSelectionChange(path, isItemSelected(path));
144        if (count == 0 && mAutoLeave) {
145            leaveSelectionMode();
146        }
147    }
148
149    private static void expandMediaSet(ArrayList<Path> items, MediaSet set) {
150        int subCount = set.getSubMediaSetCount();
151        for (int i = 0; i < subCount; i++) {
152            expandMediaSet(items, set.getSubMediaSet(i));
153        }
154        int total = set.getMediaItemCount();
155        int batch = 50;
156        int index = 0;
157
158        while (index < total) {
159            int count = index + batch < total
160                    ? batch
161                    : total - index;
162            ArrayList<MediaItem> list = set.getMediaItem(index, count);
163            for (MediaItem item : list) {
164                items.add(item.getPath());
165            }
166            index += batch;
167        }
168    }
169
170    public ArrayList<Path> getSelected(boolean expandSet) {
171        ArrayList<Path> selected = new ArrayList<Path>();
172        if (mIsAlbumSet) {
173            if (mInverseSelection) {
174                int total = getTotalCount();
175                for (int i = 0; i < total; i++) {
176                    MediaSet set = mSourceMediaSet.getSubMediaSet(i);
177                    Path id = set.getPath();
178                    if (!mClickedSet.contains(id)) {
179                        if (expandSet) {
180                            expandMediaSet(selected, set);
181                        } else {
182                            selected.add(id);
183                        }
184                    }
185                }
186            } else {
187                for (Path id : mClickedSet) {
188                    if (expandSet) {
189                        expandMediaSet(selected, mDataManager.getMediaSet(id));
190                    } else {
191                        selected.add(id);
192                    }
193                }
194            }
195        } else {
196            if (mInverseSelection) {
197                int total = getTotalCount();
198                int index = 0;
199                while (index < total) {
200                    int count = Math.min(total - index, MediaSet.MEDIAITEM_BATCH_FETCH_COUNT);
201                    ArrayList<MediaItem> list = mSourceMediaSet.getMediaItem(index, count);
202                    for (MediaItem item : list) {
203                        Path id = item.getPath();
204                        if (!mClickedSet.contains(id)) selected.add(id);
205                    }
206                    index += count;
207                }
208            } else {
209                for (Path id : mClickedSet) {
210                    selected.add(id);
211                }
212            }
213        }
214        return selected;
215    }
216
217    public void setSourceMediaSet(MediaSet set) {
218        mSourceMediaSet = set;
219        mTotal = -1;
220    }
221}
222