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 17 package com.android.gallery3d.ui; 18 19 import com.android.gallery3d.app.AbstractGalleryActivity; 20 import com.android.gallery3d.data.DataManager; 21 import com.android.gallery3d.data.MediaItem; 22 import com.android.gallery3d.data.MediaSet; 23 import com.android.gallery3d.data.Path; 24 25 import java.util.ArrayList; 26 import java.util.HashSet; 27 import java.util.Set; 28 29 public 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 mTotal = -1; 73 enterSelectionMode(); 74 if (mListener != null) mListener.onSelectionModeChange(SELECT_ALL_MODE); 75 } 76 77 public void deSelectAll() { 78 leaveSelectionMode(); 79 mInverseSelection = false; 80 mClickedSet.clear(); 81 } 82 83 public boolean inSelectAllMode() { 84 return mInverseSelection; 85 } 86 87 public boolean inSelectionMode() { 88 return mInSelectionMode; 89 } 90 91 public void enterSelectionMode() { 92 if (mInSelectionMode) return; 93 94 mInSelectionMode = true; 95 if (mListener != null) mListener.onSelectionModeChange(ENTER_SELECTION_MODE); 96 } 97 98 public void leaveSelectionMode() { 99 if (!mInSelectionMode) return; 100 101 mInSelectionMode = false; 102 mInverseSelection = false; 103 mClickedSet.clear(); 104 if (mListener != null) mListener.onSelectionModeChange(LEAVE_SELECTION_MODE); 105 } 106 107 public boolean isItemSelected(Path itemId) { 108 return mInverseSelection ^ mClickedSet.contains(itemId); 109 } 110 111 private int getTotalCount() { 112 if (mSourceMediaSet == null) return -1; 113 114 if (mTotal < 0) { 115 mTotal = mIsAlbumSet 116 ? mSourceMediaSet.getSubMediaSetCount() 117 : mSourceMediaSet.getMediaItemCount(); 118 } 119 return mTotal; 120 } 121 122 public int getSelectedCount() { 123 int count = mClickedSet.size(); 124 if (mInverseSelection) { 125 count = getTotalCount() - count; 126 } 127 return count; 128 } 129 130 public void toggle(Path path) { 131 if (mClickedSet.contains(path)) { 132 mClickedSet.remove(path); 133 } else { 134 enterSelectionMode(); 135 mClickedSet.add(path); 136 } 137 138 // Convert to inverse selection mode if everything is selected. 139 int count = getSelectedCount(); 140 if (count == getTotalCount()) { 141 selectAll(); 142 } 143 144 if (mListener != null) mListener.onSelectionChange(path, isItemSelected(path)); 145 if (count == 0 && mAutoLeave) { 146 leaveSelectionMode(); 147 } 148 } 149 150 private static boolean expandMediaSet(ArrayList<Path> items, MediaSet set, int maxSelection) { 151 int subCount = set.getSubMediaSetCount(); 152 for (int i = 0; i < subCount; i++) { 153 if (!expandMediaSet(items, set.getSubMediaSet(i), maxSelection)) { 154 return false; 155 } 156 } 157 int total = set.getMediaItemCount(); 158 int batch = 50; 159 int index = 0; 160 161 while (index < total) { 162 int count = index + batch < total 163 ? batch 164 : total - index; 165 ArrayList<MediaItem> list = set.getMediaItem(index, count); 166 if (list != null 167 && list.size() > (maxSelection - items.size())) { 168 return false; 169 } 170 for (MediaItem item : list) { 171 items.add(item.getPath()); 172 } 173 index += batch; 174 } 175 return true; 176 } 177 178 public ArrayList<Path> getSelected(boolean expandSet) { 179 return getSelected(expandSet, Integer.MAX_VALUE); 180 } 181 182 public ArrayList<Path> getSelected(boolean expandSet, int maxSelection) { 183 ArrayList<Path> selected = new ArrayList<Path>(); 184 if (mIsAlbumSet) { 185 if (mInverseSelection) { 186 int total = getTotalCount(); 187 for (int i = 0; i < total; i++) { 188 MediaSet set = mSourceMediaSet.getSubMediaSet(i); 189 Path id = set.getPath(); 190 if (!mClickedSet.contains(id)) { 191 if (expandSet) { 192 if (!expandMediaSet(selected, set, maxSelection)) { 193 return null; 194 } 195 } else { 196 selected.add(id); 197 if (selected.size() > maxSelection) { 198 return null; 199 } 200 } 201 } 202 } 203 } else { 204 for (Path id : mClickedSet) { 205 if (expandSet) { 206 if (!expandMediaSet(selected, mDataManager.getMediaSet(id), 207 maxSelection)) { 208 return null; 209 } 210 } else { 211 selected.add(id); 212 if (selected.size() > maxSelection) { 213 return null; 214 } 215 } 216 } 217 } 218 } else { 219 if (mInverseSelection) { 220 int total = getTotalCount(); 221 int index = 0; 222 while (index < total) { 223 int count = Math.min(total - index, MediaSet.MEDIAITEM_BATCH_FETCH_COUNT); 224 ArrayList<MediaItem> list = mSourceMediaSet.getMediaItem(index, count); 225 for (MediaItem item : list) { 226 Path id = item.getPath(); 227 if (!mClickedSet.contains(id)) { 228 selected.add(id); 229 if (selected.size() > maxSelection) { 230 return null; 231 } 232 } 233 } 234 index += count; 235 } 236 } else { 237 for (Path id : mClickedSet) { 238 selected.add(id); 239 if (selected.size() > maxSelection) { 240 return null; 241 } 242 } 243 } 244 } 245 return selected; 246 } 247 248 public void setSourceMediaSet(MediaSet set) { 249 mSourceMediaSet = set; 250 mTotal = -1; 251 } 252 } 253