package net.osmand.plus.myplaces; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.view.MenuItemCompat; import android.support.v7.app.AlertDialog; import android.support.v7.view.ActionMode; import android.support.v7.widget.PopupMenu; import android.support.v7.widget.SearchView; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.CheckBox; import android.widget.EditText; import android.widget.ExpandableListView; import android.widget.Filter; import android.widget.Filterable; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; import net.osmand.AndroidUtils; import net.osmand.data.FavouritePoint; import net.osmand.data.LatLon; import net.osmand.data.PointDescription; import net.osmand.plus.FavouritesDbHelper; import net.osmand.plus.GPXDatabase.GpxDataItem; import net.osmand.plus.GPXUtilities; import net.osmand.plus.GPXUtilities.GPXFile; import net.osmand.plus.GpxSelectionHelper.GpxDisplayGroup; import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem; import net.osmand.plus.GpxSelectionHelper.GpxDisplayItemType; import net.osmand.plus.IconsCache; import net.osmand.plus.MapMarkersHelper; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandSettings; import net.osmand.plus.R; import net.osmand.plus.TargetPointsHelper; import net.osmand.plus.activities.IntermediatePointsDialog; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.activities.OsmandActionBarActivity; import net.osmand.plus.activities.OsmandBaseExpandableListAdapter; import net.osmand.plus.activities.SavingTrackHelper; import net.osmand.plus.activities.TrackActivity; import net.osmand.plus.base.FavoriteImageDrawable; import net.osmand.plus.base.OsmandExpandableListFragment; import net.osmand.plus.dialogs.DirectionsDialogs; import net.osmand.util.Algorithms; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; public class TrackPointFragment extends OsmandExpandableListFragment { public static final String ARG_TO_FILTER_SHORT_TRACKS = "ARG_TO_FILTER_SHORT_TRACKS"; public static final int SEARCH_ID = -1; public static final int DELETE_ID = 2; public static final int DELETE_ACTION_ID = 3; public static final int SHARE_ID = 4; public static final int SELECT_MAP_MARKERS_ID = 5; public static final int SELECT_MAP_MARKERS_ACTION_MODE_ID = 6; public static final int SELECT_FAVORITES_ID = 7; public static final int SELECT_FAVORITES_ACTION_MODE_ID = 8; private OsmandApplication app; final private PointGPXAdapter adapter = new PointGPXAdapter(); private GpxDisplayItemType[] filterTypes = { GpxDisplayItemType.TRACK_POINTS, GpxDisplayItemType.TRACK_ROUTE_POINTS }; private boolean selectionMode = false; private Set<GpxDisplayItem> selectedItems = new LinkedHashSet<>(); private Set<Integer> selectedGroups = new LinkedHashSet<>(); private ActionMode actionMode; private SearchView searchView; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.app = getMyApplication(); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); listView.setBackgroundColor(getResources().getColor( getMyApplication().getSettings().isLightContent() ? R.color.ctx_menu_info_view_bg_light : R.color.ctx_menu_info_view_bg_dark)); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.favorites_tree, container, false); ExpandableListView listView = (ExpandableListView) view.findViewById(android.R.id.list); setHasOptionsMenu(true); TextView tv = new TextView(getActivity()); tv.setText(R.string.none_selected_gpx); tv.setTextSize(24); listView.setEmptyView(tv); setContent(listView); setListView(listView); expandAllGroups(); return view; } public TrackActivity getMyActivity() { return (TrackActivity) getActivity(); } private GPXFile getGpx() { return getMyActivity().getGpx(); } private GpxDataItem getGpxDataItem() { return getMyActivity().getGpxDataItem(); } private void expandAllGroups() { for (int i = 0; i < adapter.getGroupCount(); i++) { getExpandableListView().expandGroup(i); } } private void setupListView(ListView listView) { if (!adapter.isEmpty() && listView.getHeaderViewsCount() == 0) { listView.addHeaderView(getActivity().getLayoutInflater().inflate(R.layout.list_shadow_header, null, false)); listView.addFooterView(getActivity().getLayoutInflater().inflate(R.layout.list_shadow_footer, null, false)); } } private boolean isArgumentTrue(@NonNull String arg) { return getArguments() != null && getArguments().getBoolean(arg); } private boolean hasFilterType(GpxDisplayItemType filterType) { for (GpxDisplayItemType type : filterTypes) { if (type == filterType) { return true; } } return false; } private List<GpxDisplayGroup> filterGroups() { List<GpxDisplayGroup> result = getMyActivity().getGpxFile(false); List<GpxDisplayGroup> groups = new ArrayList<>(); for (GpxDisplayGroup group : result) { boolean add = hasFilterType(group.getType()); if (isArgumentTrue(ARG_TO_FILTER_SHORT_TRACKS)) { Iterator<GpxDisplayItem> item = group.getModifiableList().iterator(); while (item.hasNext()) { GpxDisplayItem it2 = item.next(); if (it2.analysis != null && it2.analysis.totalDistance < 100) { item.remove(); } } if (group.getModifiableList().isEmpty()) { add = false; } } if (add) { groups.add(group); } } return groups; } public void setContent() { setContent(listView); expandAllGroups(); } public void setContent(ExpandableListView listView) { adapter.synchronizeGroups(filterGroups()); setupListView(listView); if (listView.getAdapter() == null) { listView.setAdapter(adapter); } } protected List<GpxDisplayItem> flatten(List<GpxDisplayGroup> groups) { ArrayList<GpxDisplayItem> list = new ArrayList<>(); for(GpxDisplayGroup g : groups) { list.addAll(g.getModifiableList()); } return list; } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == SELECT_MAP_MARKERS_ID) { selectMapMarkers(); return true; } else if (item.getItemId() == SELECT_FAVORITES_ID) { selectFavorites(); return true; } else if (item.getItemId() == SHARE_ID) { shareItems(); return true; } else if (item.getItemId() == DELETE_ID) { enterDeleteMode(); return true; } else { return super.onOptionsItemSelected(item); } } private void selectMapMarkers() { enterMapMarkersMode(); } private void selectFavorites() { enterFavoritesMode(); } private void shareItems() { final Uri fileUri = Uri.fromFile(new File(getGpx().path)); final Intent sendIntent = new Intent(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_STREAM, fileUri); sendIntent.setType("application/gpx+xml"); startActivity(sendIntent); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { menu.clear(); MenuItem mi = createMenuItem(menu, SEARCH_ID, R.string.search_poi_filter, R.drawable.ic_action_search_dark, R.drawable.ic_action_search_dark, MenuItemCompat.SHOW_AS_ACTION_ALWAYS | MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW); searchView = new SearchView(getActivity()); FavoritesActivity.updateSearchView(getActivity(), searchView); MenuItemCompat.setActionView(mi, searchView); searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { adapter.getFilter().filter(query); return true; } @Override public boolean onQueryTextChange(String newText) { adapter.getFilter().filter(newText); return true; } }); MenuItemCompat.setOnActionExpandListener(mi, new MenuItemCompat.OnActionExpandListener() { @Override public boolean onMenuItemActionExpand(MenuItem item) { return true; } @Override public boolean onMenuItemActionCollapse(MenuItem item) { adapter.setFilterResults(null); adapter.synchronizeGroups(filterGroups()); adapter.notifyDataSetChanged(); // Needed to hide intermediate progress bar after closing action mode new Handler().postDelayed(new Runnable() { public void run() { hideProgressBar(); } }, 100); return true; } }); if (!MenuItemCompat.isActionViewExpanded(mi)) { createMenuItem(menu, SHARE_ID, R.string.shared_string_share, R.drawable.ic_action_gshare_dark, R.drawable.ic_action_gshare_dark, MenuItemCompat.SHOW_AS_ACTION_NEVER); if (getSettings().USE_MAP_MARKERS.get()) { createMenuItem(menu, SELECT_MAP_MARKERS_ID, R.string.shared_string_add_to_map_markers, R.drawable.ic_action_flag_dark, R.drawable.ic_action_flag_dark, MenuItemCompat.SHOW_AS_ACTION_NEVER); } else { createMenuItem(menu, SELECT_MAP_MARKERS_ID, R.string.select_destination_and_intermediate_points, R.drawable.ic_action_intermediate, R.drawable.ic_action_intermediate, MenuItemCompat.SHOW_AS_ACTION_NEVER); } createMenuItem(menu, SELECT_FAVORITES_ID, R.string.shared_string_add_to_favorites, R.drawable.ic_action_fav_dark, R.drawable.ic_action_fav_dark, MenuItemCompat.SHOW_AS_ACTION_NEVER); createMenuItem(menu, DELETE_ID, R.string.shared_string_delete, R.drawable.ic_action_delete_dark, R.drawable.ic_action_delete_dark, MenuItemCompat.SHOW_AS_ACTION_NEVER); } } public void showProgressBar() { OsmandActionBarActivity activity = getActionBarActivity(); if (activity != null) { activity.setSupportProgressBarIndeterminateVisibility(true); } } public void hideProgressBar() { OsmandActionBarActivity activity = getActionBarActivity(); if (activity != null) { activity.setSupportProgressBarIndeterminateVisibility(false); } } private void enableSelectionMode(boolean selectionMode) { this.selectionMode = selectionMode; } private void enterDeleteMode() { actionMode = getActionBarActivity().startSupportActionMode(new ActionMode.Callback() { @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { enableSelectionMode(true); createMenuItem(menu, DELETE_ACTION_ID, R.string.shared_string_delete, R.drawable.ic_action_delete_dark, R.drawable.ic_action_delete_dark, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM); selectedItems.clear(); selectedGroups.clear(); adapter.notifyDataSetInvalidated(); updateSelectionMode(mode); return true; } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; } @Override public void onDestroyActionMode(ActionMode mode) { enableSelectionMode(false); adapter.notifyDataSetInvalidated(); } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { if (item.getItemId() == DELETE_ACTION_ID) { deleteItemsAction(); } return true; } }); } private void deleteItemsAction() { if (selectedItems.size() > 0) { AlertDialog.Builder b = new AlertDialog.Builder(getActivity()); b.setMessage(getString(R.string.points_delete_multiple, selectedItems.size())); b.setPositiveButton(R.string.shared_string_delete, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (actionMode != null) { actionMode.finish(); } deleteItems(); } }); b.setNegativeButton(R.string.shared_string_cancel, null); b.show(); } } private void deleteItems() { new AsyncTask<Void, Object, String>() { @Override protected void onPreExecute() { showProgressBar(); } @Override protected void onPostExecute(String result) { hideProgressBar(); adapter.synchronizeGroups(filterGroups()); } @Override protected String doInBackground(Void... params) { GPXFile gpx = getGpx(); SavingTrackHelper savingTrackHelper = app.getSavingTrackHelper(); if (gpx != null) { for (GpxDisplayItem item : selectedItems) { if (gpx.showCurrentTrack) { savingTrackHelper.deletePointData(item.locationStart); } else { if (item.group.getType() == GpxDisplayItemType.TRACK_POINTS) { gpx.deleteWptPt(item.locationStart); } else if (item.group.getType() == GpxDisplayItemType.TRACK_ROUTE_POINTS) { gpx.deleteRtePt(item.locationStart); } } } if (!gpx.showCurrentTrack) { GPXUtilities.writeGpxFile(new File(gpx.path), gpx, app); boolean selected = app.getSelectedGpxHelper().getSelectedFileByPath(gpx.path) != null; if (selected) { app.getSelectedGpxHelper().setGpxFileToDisplay(gpx); } } } selectedItems.clear(); selectedGroups.clear(); return getString(R.string.points_delete_multiple_succesful); } }.execute(); } private void enterMapMarkersMode() { actionMode = getActionBarActivity().startSupportActionMode(new ActionMode.Callback() { @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { enableSelectionMode(true); if (getSettings().USE_MAP_MARKERS.get()) { createMenuItem(menu, SELECT_MAP_MARKERS_ACTION_MODE_ID, R.string.shared_string_add_to_map_markers, R.drawable.ic_action_flag_dark, R.drawable.ic_action_flag_dark, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM); } else { createMenuItem(menu, SELECT_MAP_MARKERS_ACTION_MODE_ID, R.string.select_destination_and_intermediate_points, R.drawable.ic_action_intermediate, R.drawable.ic_action_intermediate, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM); } selectedItems.clear(); selectedGroups.clear(); adapter.notifyDataSetInvalidated(); updateSelectionMode(mode); return true; } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; } @Override public void onDestroyActionMode(ActionMode mode) { enableSelectionMode(false); adapter.notifyDataSetInvalidated(); } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { if (item.getItemId() == SELECT_MAP_MARKERS_ACTION_MODE_ID) { mode.finish(); selectMapMarkersImpl(); } return true; } }); } private void selectMapMarkersImpl() { if (!selectedItems.isEmpty()) { if (getSettings().USE_MAP_MARKERS.get()) { MapMarkersHelper markersHelper = app.getMapMarkersHelper(); List<LatLon> points = new ArrayList<>(); List<PointDescription> names = new ArrayList<>(); for(GpxDisplayItem i : selectedItems) { if (i.locationStart != null) { points.add(new LatLon(i.locationStart.lat, i.locationStart.lon)); names.add(new PointDescription(PointDescription.POINT_TYPE_MAP_MARKER, i.name)); } } markersHelper.addMapMarkers(points, names); MapActivity.launchMapActivityMoveToTop(getActivity()); } else { final TargetPointsHelper targetPointsHelper = getMyApplication().getTargetPointsHelper(); for (GpxDisplayItem i : selectedItems) { if (i.locationStart != null) { targetPointsHelper.navigateToPoint(new LatLon(i.locationStart.lat, i.locationStart.lon), false, targetPointsHelper.getIntermediatePoints().size() + 1, new PointDescription(PointDescription.POINT_TYPE_FAVORITE, i.name)); } } if (getMyApplication().getRoutingHelper().isRouteCalculated()) { targetPointsHelper.updateRouteAndRefresh(true); } IntermediatePointsDialog.openIntermediatePointsDialog(getActivity(), getMyApplication(), true); } } } private void enterFavoritesMode() { actionMode = getActionBarActivity().startSupportActionMode(new ActionMode.Callback() { @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { enableSelectionMode(true); createMenuItem(menu, SELECT_FAVORITES_ACTION_MODE_ID, R.string.shared_string_add_to_favorites, R.drawable.ic_action_fav_dark, R.drawable.ic_action_fav_dark, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM); selectedItems.clear(); selectedGroups.clear(); adapter.notifyDataSetInvalidated(); updateSelectionMode(mode); return true; } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; } @Override public void onDestroyActionMode(ActionMode mode) { enableSelectionMode(false); adapter.notifyDataSetInvalidated(); } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { if (item.getItemId() == SELECT_FAVORITES_ACTION_MODE_ID) { selectFavoritesImpl(); } return true; } }); } private void selectFavoritesImpl() { if (!selectedItems.isEmpty()) { AlertDialog.Builder b = new AlertDialog.Builder(getMyActivity()); final EditText editText = new EditText(getMyActivity()); String name = selectedItems.iterator().next().group.getName(); if(name.indexOf('\n') > 0) { name = name.substring(0, name.indexOf('\n')); } editText.setText(name); int leftMargin = AndroidUtils.dpToPx(getContext(), 16f); int topMargin = AndroidUtils.dpToPx(getContext(), 8f); editText.setPadding(leftMargin, topMargin, leftMargin, topMargin); b.setTitle(R.string.save_as_favorites_points); b.setView(editText); b.setPositiveButton(R.string.shared_string_save, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (actionMode != null) { actionMode.finish(); } FavouritesDbHelper fdb = app.getFavorites(); for(GpxDisplayItem i : selectedItems) { if (i.locationStart != null) { FavouritePoint fp = new FavouritePoint(i.locationStart.lat, i.locationStart.lon, i.name, editText.getText().toString()); if (!Algorithms.isEmpty(i.description)) { fp.setDescription(i.description); } fdb.addFavourite(fp, false); } } fdb.saveCurrentPointsIntoFile(); MapActivity.launchMapActivityMoveToTop(getActivity()); } }); b.setNegativeButton(R.string.shared_string_cancel, null); b.show(); } } private void updateSelectionMode(ActionMode m) { if (selectedItems.size() > 0) { m.setTitle(selectedItems.size() + " " + getMyApplication().getString(R.string.shared_string_selected_lowercase)); } else { m.setTitle(""); } } @Override public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { if (selectionMode) { CheckBox ch = (CheckBox) v.findViewById(R.id.toggle_item); GpxDisplayItem item = adapter.getChild(groupPosition, childPosition); ch.setChecked(!ch.isChecked()); if (ch.isChecked()) { selectedItems.add(item); } else { selectedItems.remove(item); } updateSelectionMode(actionMode); } else { final GpxDisplayItem item = adapter.getChild(groupPosition, childPosition); if (item != null) { if (item.group.getGpx() != null) { app.getSelectedGpxHelper().setGpxFileToDisplay(item.group.getGpx()); } final OsmandSettings settings = app.getSettings(); LatLon location = new LatLon(item.locationStart.lat, item.locationStart.lon); settings.setMapLocationToShow(location.getLatitude(), location.getLongitude(), settings.getLastKnownMapZoom(), new PointDescription(PointDescription.POINT_TYPE_WPT, item.name), false, item.locationStart); MapActivity.launchMapActivityMoveToTop(getActivity()); } } return true; } class PointGPXAdapter extends OsmandBaseExpandableListAdapter implements Filterable { Map<GpxDisplayGroup, List<GpxDisplayItem>> itemGroups = new LinkedHashMap<>(); List<GpxDisplayGroup> groups = new ArrayList<>(); Filter myFilter; private Set<?> filter; public void synchronizeGroups(List<GpxDisplayGroup> gs) { itemGroups.clear(); groups.clear(); Set<?> flt = filter; Collections.sort(gs, new Comparator<GpxDisplayGroup>() { @Override public int compare(GpxDisplayGroup g1, GpxDisplayGroup g2) { int i1 = g1.getType().ordinal(); int i2 = g2.getType().ordinal(); return i1 < i2 ? -1 : (i1 == i2 ? 0 : 1); } }); for (GpxDisplayGroup g : gs) { if (g.getModifiableList().isEmpty()) { continue; } boolean empty = true; if (flt == null) { empty = false; itemGroups.put(g, new ArrayList<>(g.getModifiableList())); } else { ArrayList<GpxDisplayItem> list = new ArrayList<>(); for (GpxDisplayItem i : g.getModifiableList()) { if (flt.contains(i)) { list.add(i); empty = false; } } itemGroups.put(g, list); } if (!empty) { groups.add(g); } } notifyDataSetChanged(); } @Override public GpxDisplayItem getChild(int groupPosition, int childPosition) { return itemGroups.get(groups.get(groupPosition)).get(childPosition); } @Override public long getChildId(int groupPosition, int childPosition) { return groupPosition * 10000 + childPosition; } @Override public int getChildrenCount(int groupPosition) { return itemGroups.get(groups.get(groupPosition)).size(); } @Override public GpxDisplayGroup getGroup(int groupPosition) { return groups.get(groupPosition); } @Override public int getGroupCount() { return groups.size(); } @Override public long getGroupId(int groupPosition) { return groupPosition; } @Override public boolean hasStableIds() { return false; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } @Override public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { View row = convertView; boolean checkBox = row != null && row.findViewById(R.id.toggle_item) instanceof CheckBox; boolean same = (selectionMode && checkBox) || (!selectionMode && !checkBox); if (row == null || !same) { LayoutInflater inflater = getActivity().getLayoutInflater(); row = inflater.inflate(R.layout.wpt_list_item_category, parent, false); } row.setOnClickListener(null); final GpxDisplayGroup group = getGroup(groupPosition); row.findViewById(R.id.group_divider).setVisibility(groupPosition == 0 ? View.GONE : View.VISIBLE); TextView label = (TextView) row.findViewById(R.id.category_name); TextView description = (TextView) row.findViewById(R.id.category_desc); if (group.getType() == GpxDisplayItemType.TRACK_POINTS) { label.setText(getString(R.string.waypoints)); description.setText(getString(R.string.track_points_category_name)); } else { label.setText(getString(R.string.route_points)); description.setText(getString(R.string.route_points_category_name)); } if (selectionMode) { final CheckBox ch = (CheckBox) row.findViewById(R.id.toggle_item); ch.setVisibility(View.VISIBLE); ch.setChecked(selectedGroups.contains(groupPosition)); ch.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { List<GpxDisplayItem> items = itemGroups.get(group); if (ch.isChecked()) { selectedGroups.add(groupPosition); if (items != null) { selectedItems.addAll(items); } } else { selectedGroups.remove(groupPosition); if (items != null) { selectedItems.removeAll(items); } } adapter.notifyDataSetInvalidated(); updateSelectionMode(actionMode); } }); } else { final CheckBox ch = (CheckBox) row.findViewById(R.id.toggle_item); ch.setVisibility(View.GONE); } row.findViewById(R.id.category_icon).setVisibility(View.GONE); row.findViewById(R.id.options).setVisibility(View.GONE); return row; } @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { View row = convertView; if (row == null) { LayoutInflater inflater = getActivity().getLayoutInflater(); row = inflater.inflate(R.layout.wpt_list_item, parent, false); } if (childPosition == 0) { row.findViewById(R.id.divider).setVisibility(View.VISIBLE); row.findViewById(R.id.list_divider).setVisibility(View.GONE); } else { row.findViewById(R.id.divider).setVisibility(View.GONE); row.findViewById(R.id.list_divider).setVisibility(View.VISIBLE); } ImageView icon = (ImageView) row.findViewById(R.id.icon); TextView title = (TextView) row.findViewById(R.id.label); TextView description = (TextView) row.findViewById(R.id.description); final GpxDisplayItem gpxItem = getChild(groupPosition, childPosition); boolean isWpt = gpxItem.group.getType() == GpxDisplayItemType.TRACK_POINTS; ImageView options = (ImageView) row.findViewById(R.id.options); if (isWpt) { options.setFocusable(false); options.setImageDrawable(getMyApplication().getIconsCache().getThemedIcon( R.drawable.ic_overflow_menu_white)); options.setVisibility(View.VISIBLE); options.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { IconsCache iconsCache = getMyApplication().getIconsCache(); final PopupMenu optionsMenu = new PopupMenu(getActivity(), v); DirectionsDialogs.setupPopUpMenuIcon(optionsMenu); MenuItem menuItem = optionsMenu.getMenu().add(R.string.shared_string_edit).setIcon(iconsCache.getThemedIcon(R.drawable.ic_action_edit_dark)); menuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem mItem) { final OsmandSettings settings = app.getSettings(); LatLon location = new LatLon(gpxItem.locationStart.lat, gpxItem.locationStart.lon); if (gpxItem.group.getGpx() != null) { app.getSelectedGpxHelper().setGpxFileToDisplay(gpxItem.group.getGpx()); } settings.setMapLocationToShow(location.getLatitude(), location.getLongitude(), settings.getLastKnownMapZoom(), new PointDescription(PointDescription.POINT_TYPE_WPT, gpxItem.name), false, gpxItem.locationStart); settings.setEditObjectToShow(); MapActivity.launchMapActivityMoveToTop(getActivity()); return true; } }); optionsMenu.show(); } }); int groupColor = gpxItem.group.getColor(); if (gpxItem.locationStart != null) { groupColor = gpxItem.locationStart.getColor(groupColor); } if (groupColor == 0) { groupColor = getMyActivity().getResources().getColor(R.color.gpx_color_point); } icon.setImageDrawable(FavoriteImageDrawable.getOrCreate(getActivity(), groupColor, false)); } else { icon.setImageDrawable(app.getIconsCache().getThemedIcon(R.drawable.ic_action_marker_dark)); options.setVisibility(View.GONE); } title.setText(gpxItem.name); if (!Algorithms.isEmpty(gpxItem.description)) { description.setText(gpxItem.description); description.setVisibility(View.VISIBLE); } else { description.setVisibility(View.GONE); } final CheckBox ch = (CheckBox) row.findViewById(R.id.toggle_item); if (selectionMode) { ch.setVisibility(View.VISIBLE); ch.setChecked(selectedItems.contains(gpxItem)); row.findViewById(R.id.icon).setVisibility(View.GONE); options.setVisibility(View.GONE); ch.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (ch.isChecked()) { selectedItems.add(gpxItem); } else { selectedItems.remove(gpxItem); } updateSelectionMode(actionMode); } }); } else { row.findViewById(R.id.icon).setVisibility(View.VISIBLE); ch.setVisibility(View.GONE); } return row; } @Override public Filter getFilter() { if (myFilter == null) { myFilter = new PointsFilter(); } return myFilter; } public void setFilterResults(Set<?> values) { this.filter = values; } } public class PointsFilter extends Filter { public PointsFilter() { } @Override protected FilterResults performFiltering(CharSequence constraint) { FilterResults results = new FilterResults(); if (constraint == null || constraint.length() == 0) { results.values = null; results.count = 1; } else { Set<Object> filter = new HashSet<>(); String cs = constraint.toString().toLowerCase(); for (GpxDisplayGroup g : filterGroups()) { for (GpxDisplayItem i : g.getModifiableList()) { if (i.name.toLowerCase().contains(cs)) { filter.add(i); } } } results.values = filter; results.count = filter.size(); } return results; } @Override protected void publishResults(CharSequence constraint, FilterResults results) { synchronized (adapter) { adapter.setFilterResults((Set<?>) results.values); adapter.synchronizeGroups(filterGroups()); } adapter.notifyDataSetChanged(); expandAllGroups(); } } }