/* * GeoSolutions map - Digital field mapping on Android based devices * Copyright (C) 2013 GeoSolutions (www.geo-solutions.it) * * This program 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. * * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ package it.geosolutions.android.map.geostore.fragment; import it.geosolutions.android.map.MapsActivity; import it.geosolutions.android.map.R; import it.geosolutions.android.map.geostore.activities.GeoStoreResourceDetailActivity; import it.geosolutions.android.map.geostore.activities.GeoStoreResourcesActivity; import it.geosolutions.android.map.geostore.activities.GeoStoreResourceDetailActivity.PARAMS; import it.geosolutions.android.map.geostore.adapters.GeoStoreResourceAdapter; import it.geosolutions.android.map.geostore.loaders.GeoStoreResourceLoader; import it.geosolutions.android.map.geostore.model.Resource; import it.geosolutions.android.map.mapstore.activities.MapStoreLayerListActivity; import it.geosolutions.android.map.mapstore.model.MapStoreConfiguration; import it.geosolutions.android.map.mapstore.utils.MapStoreConfigTask; import it.geosolutions.android.map.model.stores.LayerStore; import java.util.ArrayList; import java.util.Formatter; import java.util.List; import android.app.Activity; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Resources; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.LoaderManager; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.Loader; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.TextView; import android.widget.Toast; import com.actionbarsherlock.app.SherlockListFragment; import com.actionbarsherlock.view.ActionMode; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import com.actionbarsherlock.widget.SearchView; /** * Show a list of the resources from a GeoStore instance. * Load 5 at time the resources to fill the screen and provides * search capabilities * * @author Lorenzo Natali (www.geo-solutions.it) * */ public class GeoStoreResourceListFragment extends SherlockListFragment implements LoaderCallbacks<List<Resource>>, SearchView.OnQueryTextListener, SearchView.OnCloseListener, OnScrollListener,ActionMode.Callback { /** * The adapter to show resources */ private GeoStoreResourceAdapter adapter; /** * The loader index (uses only one loader) */ private static final int LOADER_INDEX =0; private int page =0; private int size = 5; private String geoStoreUrl; // The callbacks through which we will interact with the LoaderManager. private LoaderManager.LoaderCallbacks<List<Resource>> mCallbacks; //actionMode private ActionMode actionMode = null; private Resource selected; //the string to search private String filter; //a reference to the searchView on top private SearchView searchView; //a reference to the current loader to get totalCount private GeoStoreResourceLoader loader; //a flag to skip scroll event if already loading private boolean isLoading; /** * Constructor */ public GeoStoreResourceListFragment(){ // call seatHasOptionsMenu to allow inflate of // menu in the actionBar this.setHasOptionsMenu(true); } /** * Called once on creation */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // view operations setRetainInstance(true); // get parameters to create the task query // TODO use arguments instead Bundle extras = getActivity().getIntent().getExtras(); geoStoreUrl = extras.getString(GeoStoreResourcesActivity.PARAMS.GEOSTORE_URL); // create task query //queryQueue = createTaskQueryQueue(layers, query); // Initialize loader and callbacks for the parent activity // setup the listView adapter = new GeoStoreResourceAdapter(getSherlockActivity(), R.layout.geostore_resource_row); setListAdapter(adapter); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { //start loading first data startDataLoading(geoStoreUrl, LOADER_INDEX); return inflater.inflate(R.layout.geostore_resource_list, container, false); } /** * Set the loading bar and loading text */ private void startLoadingGUI() { if(getSherlockActivity()!=null){ // start progress bars getSherlockActivity().setSupportProgressBarVisibility(true); getSherlockActivity().setSupportProgressBarIndeterminateVisibility(true); getSherlockActivity().getSupportActionBar(); } // set suggestion text ((TextView) getView().findViewById(R.id.empty_text)) .setText(R.string.geostore_extracting_information);//TODO change the String } /** * hide loading bar and set loading task */ private void stopLoadingGUI() { if (getSherlockActivity() != null) { getSherlockActivity() .setSupportProgressBarIndeterminateVisibility(false); getSherlockActivity() .setSupportProgressBarVisibility(false); Log.v("GEOSTORE_LOADER", "task terminated"); } adapter.notifyDataSetChanged(); isLoading=false; } /** * Sets the view to show that no data are available */ private void setNoData() { ((TextView) getView().findViewById(R.id.empty_text)) .setText(R.string.geostore_extracting_no_result); getView().findViewById(R.id.progress_bar).setVisibility(TextView.GONE); } /** * Create the data loader and bind the loader to the * parent callbacks * @param URL (not used for now) * @param loaderIndex a unique id for query loader */ private void startDataLoading(String url, int loaderIndex) { // initialize Load Manager mCallbacks = this; //reset page LoaderManager lm = getSherlockActivity().getSupportLoaderManager(); adapter.clear(); page=0; lm.initLoader(loaderIndex, null, this); } /* * (non-Javadoc) * @see android.support.v4.app.ListFragment#onViewCreated(android.view.View, * android.os.Bundle) */ @Override public void onViewCreated(View view, Bundle savedInstanceState) { // TODO Auto-generated method stub super.onViewCreated(view, savedInstanceState); //init progress bar and loading text startLoadingGUI(); final GeoStoreResourceListFragment callback =this; //long click starts the action mode getListView().setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { Resource current = (Resource) parent.getAdapter().getItem(position); if(current == selected){ closeActionMode(); getListView().setItemChecked(position, false); }else{ selected = (Resource) parent.getAdapter().getItem(position); getListView().setItemChecked(position, true); actionMode = getSherlockActivity().startActionMode(callback); //override the done button to clear selection all when the button is pressed int doneButtonId = Resources.getSystem().getIdentifier("action_mode_close_button", "id", "android"); View doneButton = getActivity().findViewById(doneButtonId); if(doneButton != null){ doneButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { closeActionMode(); } }); } } return true; } }); //single click open layer list getListView().setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { closeActionMode(); Resource r = (Resource) parent.getAdapter().getItem(position); getListView().setItemChecked(position, true); startLayerSelection(r.id); } }); //associate scroll listener to implement infinite scroll getListView().setOnScrollListener(this); } protected void loadMore() { if(loader!=null){ if(loader.totalCount > adapter.getCount() && loader.totalCount>0){ page++; getLoaderManager().restartLoader(LOADER_INDEX, null, this); }else{ //TODO notify finish loading } } } /* (non-Javadoc) * @see android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader(int, android.os.Bundle) */ @Override public Loader<List<Resource>> onCreateLoader(int id, Bundle args) { //set the loading getSherlockActivity().setSupportProgressBarIndeterminateVisibility(true); getSherlockActivity().getSupportActionBar(); loader = new GeoStoreResourceLoader(getSherlockActivity(),geoStoreUrl,filter,page,size); return loader; } /* (non-Javadoc) * @see android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished(android.support.v4.content.Loader, java.lang.Object) */ @Override public void onLoadFinished(Loader<List<Resource>> loader, List<Resource> results) { if(results == null){ Toast.makeText(getSherlockActivity(), R.string.error_retrieving_resources_from_mapstore, Toast.LENGTH_SHORT).show(); setNoData(); }else{ //add loaded resources to the listView for(Resource a : results ){ adapter.add(a); } if (adapter.isEmpty()) { setNoData(); }else{ updateView(); } } stopLoadingGUI(); } /** * Update the info about pagination and visibility of more button */ private void updateView() { int count =adapter.getCount(); if(loader!=null){ TextView infoView = (TextView)getView().findViewById(R.id.info); Formatter f = new Formatter(); String info = f.format(getString(R.string.geostore_info_format),count,loader.totalCount).toString(); f.close(); infoView.setText(info); // if(count < loader.totalCount){ // moreButton.setVisibility(Button.VISIBLE); // } } } /* (non-Javadoc) * @see android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset(android.support.v4.content.Loader) */ @Override public void onLoaderReset(Loader<List<Resource>> arg0) { adapter.clear(); } /* * (non-Javadoc) * @see android.support.v4.app.Fragment#onDestroy() */ @Override public void onDestroy() { // TODO try to kill the load process super.onDestroy(); } @Override public void onCreateOptionsMenu(Menu menu,MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); inflater.inflate(R.menu.geostore_list, menu); searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView(); if(searchView !=null){ setupSearch(searchView); }else{ Toast.makeText(getSherlockActivity(), "Unable to setup search button", Toast.LENGTH_SHORT).show(); } } /** * setup the searchView <QueryTextlistener> and <CloseListener>. * This class implements also the interfaces to manage * query text changes and close events. * @param searchView */ private void setupSearch(SearchView searchView) { searchView.setOnQueryTextListener(this); searchView.setOnCloseListener(this); searchView.setIconifiedByDefault(true); //item.setActionView(searchView); } /* (non-Javadoc) * @see com.actionbarsherlock.widget.SearchView.OnQueryTextListener#onQueryTextSubmit(java.lang.String) */ @Override public boolean onQueryTextSubmit(String query) { //change the filter text and reload filter = !TextUtils.isEmpty(query) ? query : null; adapter.clear(); page=0; getLoaderManager().restartLoader(LOADER_INDEX, null, this); return false; } @Override public boolean onQueryTextChange(String newText) { //change the filter text and reload filter = !TextUtils.isEmpty(newText) ? newText : null; adapter.clear(); page=0; getLoaderManager().restartLoader(LOADER_INDEX, null, this); return false; } @Override public boolean onClose() { //reset the query when searchView is closed if (!TextUtils.isEmpty(searchView.getQuery())) { searchView.setQuery(null, true); } return true; } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { //check if applicable if (adapter == null){ return ; } if (adapter.getCount() == 0){ return ; } if(loader==null){ return; } if(loader.totalCount==0){ return; } //if the last item is visible and can load more resources //load more resources int l = visibleItemCount + firstVisibleItem; if (l >= totalItemCount && !isLoading && adapter.getCount()<loader.totalCount) { // It is time to add new data. We call the listener //this.addFooterView(footer); isLoading = true; loadMore(); } } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { //Nothing to do for now } // // ACTION MODE CALLBACKS // /* (non-Javadoc) * @see com.actionbarsherlock.view.ActionMode.Callback#onCreateActionMode(com.actionbarsherlock.view.ActionMode, com.actionbarsherlock.view.Menu) */ @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { mode.getMenuInflater().inflate(R.menu.details_loadmap_selectlayers, menu); this.actionMode =mode; return true; } /* (non-Javadoc) * @see com.actionbarsherlock.view.ActionMode.Callback#onPrepareActionMode(com.actionbarsherlock.view.ActionMode, com.actionbarsherlock.view.Menu) */ @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { // TODO Auto-generated method stub return false; } /* (non-Javadoc) * @see com.actionbarsherlock.view.ActionMode.Callback#onActionItemClicked(com.actionbarsherlock.view.ActionMode, com.actionbarsherlock.view.MenuItem) */ @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { int itemId = item.getItemId(); if(selected == null) return true; if(itemId == R.id.details){ showDetailsActivity(selected); return true; }else if( itemId == R.id.load_map){ /** * show a confirm dialog for load map */ confirmLoadMap(); //TODO }else if ( itemId == R.id.select_layers){ startLayerSelection(selected.id); } return true; } /** * return the resource and the GeoStore URL to make the * map load the map itself */ private void loadAllMap() { Intent data = new Intent(); data.putExtra(PARAMS.RESOURCE, selected); data.putExtra(GeoStoreResourcesActivity.PARAMS.GEOSTORE_URL, geoStoreUrl); getActivity().setResult(Activity.RESULT_OK, data); getActivity().finish(); } /** * Show A confirm dialog before load map */ public void confirmLoadMap(){ new AlertDialog.Builder(getActivity()) .setIcon(android.R.drawable.ic_dialog_alert) .setTitle(R.string.load_map) .setMessage(R.string.are_you_sure_to_load_this_map) .setNegativeButton(R.string.no, null) .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { loadAllMap(); } }) .show(); } /** * Start the activity that shows layer selection */ private void startLayerSelection(Long id) { final Activity ac = getActivity(); final ProgressDialog dialog = ProgressDialog.show(getSherlockActivity(), getString(R.string.please_wait), getString(R.string.loading_layer_list), true); AsyncTask<String, String, MapStoreConfiguration> task = new MapStoreConfigTask( id, geoStoreUrl) { @Override protected void onPostExecute(MapStoreConfiguration result) { //Log.d("MapStore", result.toString()); // call the loadMapStore config on the Activity if(result != null){ Intent i = new Intent(ac, MapStoreLayerListActivity.class); //TODO put MapStore config i.putExtra(MapsActivity.MAPSTORE_CONFIG ,result); startActivityForResult(i, MapsActivity.MAPSTORE_REQUEST_CODE); }else{ Toast.makeText(ac, R.string.error_retrieving_resources_from_mapstore, Toast.LENGTH_LONG).show(); } getSherlockActivity().overridePendingTransition(R.anim.in_from_right, R.anim.out_to_left); dialog.dismiss(); } }; task.execute(""); } /* (non-Javadoc) * @see com.actionbarsherlock.view.ActionMode.Callback#onDestroyActionMode(com.actionbarsherlock.view.ActionMode) */ @Override public void onDestroyActionMode(ActionMode mode) { //nothing to do } /** * Open the Activity that shows details about the map * @param ctx * @param item */ private void showDetailsActivity(Resource item) { Intent i = new Intent(this.getSherlockActivity(), GeoStoreResourceDetailActivity.class); i.putExtras(getActivity().getIntent().getExtras()); i.putExtra(GeoStoreResourceDetailActivity.PARAMS.RESOURCE,item); String action = getActivity().getIntent().getAction(); i.setAction(action); getActivity().startActivityForResult(i, GeoStoreResourcesActivity.GET_MAP_CONFIG); } /** * Close the action mode and clear selection */ private void closeActionMode() { getListView().clearChoices(); getListView().clearFocus(); selected = null; if(actionMode!=null){ actionMode.finish(); } } }