/*
This file is part of ZAX.
ZAX is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ZAX is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ZAX. If not, see <http://www.gnu.org/licenses/>.
*/
package com.inovex.zabbixmobile.adapters;
import android.os.Parcelable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.PagerAdapter;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import java.util.Collection;
import java.util.TreeSet;
/**
* Base class for a pager adapter maintained by a service. The base
* functionality is similar to {@link FragmentPagerAdapter}.
*
* @param <T>
* class of the items in this adapter's data set
*/
public abstract class BaseServicePagerAdapter<T> extends PagerAdapter {
protected TreeSet<T> mObjects;
private static final String TAG = BaseServicePagerAdapter.class
.getSimpleName();
private static final boolean DEBUG = true;
protected int mCurrentPosition;
protected FragmentManager mFragmentManager;
protected FragmentTransaction mCurTransaction = null;
private Fragment mCurrentPrimaryItem = null;
private boolean mRefresh;
public BaseServicePagerAdapter() {
mObjects = new TreeSet<T>();
}
public void setFragmentManager(FragmentManager fm) {
this.mFragmentManager = fm;
}
@Override
public void startUpdate(ViewGroup container) {
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
if (mFragmentManager == null)
return null;
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
final Long itemId = getItemId(position);
if (itemId == null)
return null;
// Do we already have this fragment?
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null && !mRefresh) {
if (DEBUG)
Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
mCurTransaction.attach(fragment);
} else {
fragment = getItem(position);
if (DEBUG)
Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
mCurTransaction.add(container.getId(), fragment,
makeFragmentName(container.getId(), itemId));
}
if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
}
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
// if the fragment was detached, the fragment manager should be null
if (mFragmentManager == null)
return;
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
mCurTransaction.detach((Fragment) object);
}
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
Fragment fragment = (Fragment) object;
if (fragment != mCurrentPrimaryItem) {
if (mCurrentPrimaryItem != null) {
mCurrentPrimaryItem.setMenuVisibility(false);
mCurrentPrimaryItem.setUserVisibleHint(false);
}
if (fragment != null) {
fragment.setMenuVisibility(true);
fragment.setUserVisibleHint(true);
}
mCurrentPrimaryItem = fragment;
}
}
@Override
public void finishUpdate(ViewGroup container) {
if (mFragmentManager == null)
return;
if (mCurTransaction != null) {
try {
mCurTransaction.commitAllowingStateLoss();
mCurTransaction = null;
// Commenting out the following two lines fixes a
// "Recursive entry to executePendingTransactions" exception
// I don't know why and hope this doesn't break anything
// if (mFragmentManager != null)
// mFragmentManager.executePendingTransactions();
} catch (IllegalStateException e) {
// this exception is thrown if the activity has been destroyed
// which unfortunately happens from time to time
e.printStackTrace();
mCurTransaction = null;
}
}
}
@Override
public boolean isViewFromObject(View view, Object object) {
if (object == null || view == null)
return false;
return ((Fragment) object).getView() == view;
}
@Override
public Parcelable saveState() {
return null;
}
@Override
public void restoreState(Parcelable state, ClassLoader loader) {
}
/**
* Return a unique identifier for the item at the given position.
*
* <p>
* The default implementation returns the given position. Subclasses should
* override this method if the positions of items can change.
* </p>
*
* @param position
* Position within this adapter
* @return Unique identifier for the item at position
*/
public abstract Long getItemId(int position);
protected static String makeFragmentName(int viewId, long id) {
return "android:switcher:" + viewId + ":" + id;
}
/**
* Creates a page (fragment) for a certain position.
*
* @param position
* the position within the adapter
* @return the created fragment
*/
protected abstract Fragment getItem(int position);
@Override
public int getCount() {
return mObjects.size();
}
/**
* Wrapper for {@link TreeSet#addAll(Collection)}.
*
* @param objects
*/
public void addAll(Collection<? extends T> objects) {
this.mObjects.addAll(objects);
}
/**
* Returns an item from the underlying data set.
*
* @param position
* position of the item
* @return
*/
@SuppressWarnings("unchecked")
public T getObject(int position) {
if (position >= mObjects.size())
return null;
return (T) mObjects.toArray()[position];
}
/**
* Returns the current item.
*
* @return
*/
@SuppressWarnings("unchecked")
public T getCurrentObject() {
if (mObjects.size() <= mCurrentPosition) {
if (mObjects.size() > 0)
return (T) mObjects.toArray()[0];
return null;
}
return (T) mObjects.toArray()[mCurrentPosition];
}
/**
* Wrapper for {@link TreeSet#clear()}.
*/
public void clear() {
mObjects.clear();
mRefresh = true;
}
public int getCurrentPosition() {
return mCurrentPosition;
}
public void setCurrentPosition(int position) {
this.mCurrentPosition = position;
}
}