Add author's line in license
[pub/Android/ownCloud.git] / src / com / owncloud / android / ui / preview / PreviewImagePagerAdapter.java
1 /* ownCloud Android client application
2 *
3 * @author David A. Velasco
4 * Copyright (C) 2012-2013 ownCloud Inc.
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2,
8 * as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19 package com.owncloud.android.ui.preview;
20
21 import java.util.Collections;
22 import java.util.Comparator;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.Iterator;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.Vector;
29
30 import android.accounts.Account;
31 import android.support.v4.app.Fragment;
32 import android.support.v4.app.FragmentManager;
33 import android.support.v4.app.FragmentStatePagerAdapter;
34 import android.view.ViewGroup;
35
36 import com.owncloud.android.datamodel.FileDataStorageManager;
37 import com.owncloud.android.datamodel.OCFile;
38 import com.owncloud.android.ui.adapter.FileListListAdapter;
39 import com.owncloud.android.ui.fragment.FileFragment;
40 import com.owncloud.android.utils.FileStorageUtils;
41
42 /**
43 * Adapter class that provides Fragment instances
44 */
45 //public class PreviewImagePagerAdapter extends PagerAdapter {
46 public class PreviewImagePagerAdapter extends FragmentStatePagerAdapter {
47
48 private Vector<OCFile> mImageFiles;
49 private Account mAccount;
50 private Set<Object> mObsoleteFragments;
51 private Set<Integer> mObsoletePositions;
52 private Set<Integer> mDownloadErrors;
53 private FileDataStorageManager mStorageManager;
54
55 private Map<Integer, FileFragment> mCachedFragments;
56
57 /**
58 * Constructor.
59 *
60 * @param fragmentManager {@link FragmentManager} instance that will handle the {@link Fragment}s provided by the adapter.
61 * @param parentFolder Folder where images will be searched for.
62 * @param storageManager Bridge to database.
63 */
64 public PreviewImagePagerAdapter(FragmentManager fragmentManager, OCFile parentFolder, Account account, FileDataStorageManager storageManager) {
65 super(fragmentManager);
66
67 if (fragmentManager == null) {
68 throw new IllegalArgumentException("NULL FragmentManager instance");
69 }
70 if (parentFolder == null) {
71 throw new IllegalArgumentException("NULL parent folder");
72 }
73 if (storageManager == null) {
74 throw new IllegalArgumentException("NULL storage manager");
75 }
76
77 mAccount = account;
78 mStorageManager = storageManager;
79 mImageFiles = mStorageManager.getFolderImages(parentFolder);
80
81 mImageFiles = FileStorageUtils.sortFolder(mImageFiles);
82
83 mObsoleteFragments = new HashSet<Object>();
84 mObsoletePositions = new HashSet<Integer>();
85 mDownloadErrors = new HashSet<Integer>();
86 //mFragmentManager = fragmentManager;
87 mCachedFragments = new HashMap<Integer, FileFragment>();
88 }
89
90 /**
91 * Returns the image files handled by the adapter.
92 *
93 * @return A vector with the image files handled by the adapter.
94 */
95 protected OCFile getFileAt(int position) {
96 return mImageFiles.get(position);
97 }
98
99
100 public Fragment getItem(int i) {
101 OCFile file = mImageFiles.get(i);
102 Fragment fragment = null;
103 if (file.isDown()) {
104 fragment = new PreviewImageFragment(file, mAccount, mObsoletePositions.contains(Integer.valueOf(i)));
105
106 } else if (mDownloadErrors.contains(Integer.valueOf(i))) {
107 fragment = new FileDownloadFragment(file, mAccount, true);
108 ((FileDownloadFragment)fragment).setError(true);
109 mDownloadErrors.remove(Integer.valueOf(i));
110
111 } else {
112 fragment = new FileDownloadFragment(file, mAccount, mObsoletePositions.contains(Integer.valueOf(i)));
113 }
114 mObsoletePositions.remove(Integer.valueOf(i));
115 return fragment;
116 }
117
118 public int getFilePosition(OCFile file) {
119 return mImageFiles.indexOf(file);
120 }
121
122 @Override
123 public int getCount() {
124 return mImageFiles.size();
125 }
126
127 @Override
128 public CharSequence getPageTitle(int position) {
129 return mImageFiles.get(position).getFileName();
130 }
131
132
133 public void updateFile(int position, OCFile file) {
134 FileFragment fragmentToUpdate = mCachedFragments.get(Integer.valueOf(position));
135 if (fragmentToUpdate != null) {
136 mObsoleteFragments.add(fragmentToUpdate);
137 }
138 mObsoletePositions.add(Integer.valueOf(position));
139 mImageFiles.set(position, file);
140 }
141
142
143 public void updateWithDownloadError(int position) {
144 FileFragment fragmentToUpdate = mCachedFragments.get(Integer.valueOf(position));
145 if (fragmentToUpdate != null) {
146 mObsoleteFragments.add(fragmentToUpdate);
147 }
148 mDownloadErrors.add(Integer.valueOf(position));
149 }
150
151 public void clearErrorAt(int position) {
152 FileFragment fragmentToUpdate = mCachedFragments.get(Integer.valueOf(position));
153 if (fragmentToUpdate != null) {
154 mObsoleteFragments.add(fragmentToUpdate);
155 }
156 mDownloadErrors.remove(Integer.valueOf(position));
157 }
158
159
160 @Override
161 public int getItemPosition(Object object) {
162 if (mObsoleteFragments.contains(object)) {
163 mObsoleteFragments.remove(object);
164 return POSITION_NONE;
165 }
166 return super.getItemPosition(object);
167 }
168
169
170 @Override
171 public Object instantiateItem(ViewGroup container, int position) {
172 Object fragment = super.instantiateItem(container, position);
173 mCachedFragments.put(Integer.valueOf(position), (FileFragment)fragment);
174 return fragment;
175 }
176
177 @Override
178 public void destroyItem(ViewGroup container, int position, Object object) {
179 mCachedFragments.remove(Integer.valueOf(position));
180 super.destroyItem(container, position, object);
181 }
182
183
184 public boolean pendingErrorAt(int position) {
185 return mDownloadErrors.contains(Integer.valueOf(position));
186 }
187
188 /**
189 * Reset the image zoom to default value for each CachedFragments
190 */
191 public void resetZoom() {
192 Iterator<FileFragment> entries = mCachedFragments.values().iterator();
193 while (entries.hasNext()) {
194 FileFragment fileFragment = (FileFragment) entries.next();
195 if (fileFragment instanceof PreviewImageFragment) {
196 ((PreviewImageFragment) fileFragment).getImageView().resetZoom();
197 }
198 }
199 }
200
201 /* -*
202 * Called when a change in the shown pages is going to start being made.
203 *
204 * @param container The containing View which is displaying this adapter's page views.
205 *- /
206 @Override
207 public void startUpdate(ViewGroup container) {
208 Log_OC.e(TAG, "** startUpdate");
209 }
210
211 @Override
212 public Object instantiateItem(ViewGroup container, int position) {
213 Log_OC.e(TAG, "** instantiateItem " + position);
214
215 if (mFragments.size() > position) {
216 Fragment fragment = mFragments.get(position);
217 if (fragment != null) {
218 Log_OC.e(TAG, "** \t returning cached item");
219 return fragment;
220 }
221 }
222
223 if (mCurTransaction == null) {
224 mCurTransaction = mFragmentManager.beginTransaction();
225 }
226
227 Fragment fragment = getItem(position);
228 if (mSavedState.size() > position) {
229 Fragment.SavedState savedState = mSavedState.get(position);
230 if (savedState != null) {
231 // TODO WATCH OUT:
232 // * The Fragment must currently be attached to the FragmentManager.
233 // * A new Fragment created using this saved state must be the same class type as the Fragment it was created from.
234 // * The saved state can not contain dependencies on other fragments -- that is it can't use putFragment(Bundle, String, Fragment)
235 // to store a fragment reference
236 fragment.setInitialSavedState(savedState);
237 }
238 }
239 while (mFragments.size() <= position) {
240 mFragments.add(null);
241 }
242 fragment.setMenuVisibility(false);
243 mFragments.set(position, fragment);
244 //Log_OC.e(TAG, "** \t adding fragment at position " + position + ", containerId " + container.getId());
245 mCurTransaction.add(container.getId(), fragment);
246
247 return fragment;
248 }
249
250 @Override
251 public void destroyItem(ViewGroup container, int position, Object object) {
252 Log_OC.e(TAG, "** destroyItem " + position);
253 Fragment fragment = (Fragment)object;
254
255 if (mCurTransaction == null) {
256 mCurTransaction = mFragmentManager.beginTransaction();
257 }
258 Log_OC.e(TAG, "** \t removing fragment at position " + position);
259 while (mSavedState.size() <= position) {
260 mSavedState.add(null);
261 }
262 mSavedState.set(position, mFragmentManager.saveFragmentInstanceState(fragment));
263 mFragments.set(position, null);
264
265 mCurTransaction.remove(fragment);
266 }
267
268 @Override
269 public void setPrimaryItem(ViewGroup container, int position, Object object) {
270 Fragment fragment = (Fragment)object;
271 if (fragment != mCurrentPrimaryItem) {
272 if (mCurrentPrimaryItem != null) {
273 mCurrentPrimaryItem.setMenuVisibility(false);
274 }
275 if (fragment != null) {
276 fragment.setMenuVisibility(true);
277 }
278 mCurrentPrimaryItem = fragment;
279 }
280 }
281
282 @Override
283 public void finishUpdate(ViewGroup container) {
284 Log_OC.e(TAG, "** finishUpdate (start)");
285 if (mCurTransaction != null) {
286 mCurTransaction.commitAllowingStateLoss();
287 mCurTransaction = null;
288 mFragmentManager.executePendingTransactions();
289 }
290 Log_OC.e(TAG, "** finishUpdate (end)");
291 }
292
293 @Override
294 public boolean isViewFromObject(View view, Object object) {
295 return ((Fragment)object).getView() == view;
296 }
297
298 @Override
299 public Parcelable saveState() {
300 Bundle state = null;
301 if (mSavedState.size() > 0) {
302 state = new Bundle();
303 Fragment.SavedState[] savedStates = new Fragment.SavedState[mSavedState.size()];
304 mSavedState.toArray(savedStates);
305 state.putParcelableArray("states", savedStates);
306 }
307 for (int i=0; i<mFragments.size(); i++) {
308 Fragment fragment = mFragments.get(i);
309 if (fragment != null) {
310 if (state == null) {
311 state = new Bundle();
312 }
313 String key = "f" + i;
314 mFragmentManager.putFragment(state, key, fragment);
315 }
316 }
317 return state;
318 }
319
320 @Override
321 public void restoreState(Parcelable state, ClassLoader loader) {
322 if (state != null) {
323 Bundle bundle = (Bundle)state;
324 bundle.setClassLoader(loader);
325 Parcelable[] states = bundle.getParcelableArray("states");
326 mSavedState.clear();
327 mFragments.clear();
328 if (states != null) {
329 for (int i=0; i<states.length; i++) {
330 mSavedState.add((Fragment.SavedState)states[i]);
331 }
332 }
333 Iterable<String> keys = bundle.keySet();
334 for (String key: keys) {
335 if (key.startsWith("f")) {
336 int index = Integer.parseInt(key.substring(1));
337 Fragment f = mFragmentManager.getFragment(bundle, key);
338 if (f != null) {
339 while (mFragments.size() <= index) {
340 mFragments.add(null);
341 }
342 f.setMenuVisibility(false);
343 mFragments.set(index, f);
344 } else {
345 Log_OC.w(TAG, "Bad fragment at key " + key);
346 }
347 }
348 }
349 }
350 }
351 */
352 }