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 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 boolean expandMediaSet(ArrayList<Path> items, MediaSet set, int maxSelection) { 150 int subCount = set.getSubMediaSetCount(); 151 for (int i = 0; i < subCount; i++) { 152 if (!expandMediaSet(items, set.getSubMediaSet(i), maxSelection)) { 153 return false; 154 } 155 } 156 int total = set.getMediaItemCount(); 157 int batch = 50; 158 int index = 0; 159 160 while (index < total) { 161 int count = index + batch < total 162 ? batch 163 : total - index; 164 ArrayList<MediaItem> list = set.getMediaItem(index, count); 165 if (list != null 166 && list.size() > (maxSelection - items.size())) { 167 return false; 168 } 169 for (MediaItem item : list) { 170 items.add(item.getPath()); 171 } 172 index += batch; 173 } 174 return true; 175 } 176 177 public ArrayList<Path> getSelected(boolean expandSet) { 178 return getSelected(expandSet, Integer.MAX_VALUE); 179 } 180 181 public ArrayList<Path> getSelected(boolean expandSet, int maxSelection) { 182 ArrayList<Path> selected = new ArrayList<Path>(); 183 if (mIsAlbumSet) { 184 if (mInverseSelection) { 185 int total = getTotalCount(); 186 for (int i = 0; i < total; i++) { 187 MediaSet set = mSourceMediaSet.getSubMediaSet(i); 188 Path id = set.getPath(); 189 if (!mClickedSet.contains(id)) { 190 if (expandSet) { 191 if (!expandMediaSet(selected, set, maxSelection)) { 192 return null; 193 } 194 } else { 195 selected.add(id); 196 if (selected.size() > maxSelection) { 197 return null; 198 } 199 } 200 } 201 } 202 } else { 203 for (Path id : mClickedSet) { 204 if (expandSet) { 205 if (!expandMediaSet(selected, mDataManager.getMediaSet(id), 206 maxSelection)) { 207 return null; 208 } 209 } else { 210 selected.add(id); 211 if (selected.size() > maxSelection) { 212 return null; 213 } 214 } 215 } 216 } 217 } else { 218 if (mInverseSelection) { 219 int total = getTotalCount(); 220 int index = 0; 221 while (index < total) { 222 int count = Math.min(total - index, MediaSet.MEDIAITEM_BATCH_FETCH_COUNT); 223 ArrayList<MediaItem> list = mSourceMediaSet.getMediaItem(index, count); 224 for (MediaItem item : list) { 225 Path id = item.getPath(); 226 if (!mClickedSet.contains(id)) { 227 selected.add(id); 228 if (selected.size() > maxSelection) { 229 return null; 230 } 231 } 232 } 233 index += count; 234 } 235 } else { 236 for (Path id : mClickedSet) { 237 selected.add(id); 238 if (selected.size() > maxSelection) { 239 return null; 240 } 241 } 242 } 243 } 244 return selected; 245 } 246 247 public void setSourceMediaSet(MediaSet set) { 248 mSourceMediaSet = set; 249 mTotal = -1; 250 } 251 } 252