refactor: extract MarkerRenderer from ItemizedLayer
- move ItemizedLayer stuff to MarkerLayer - rename ItemizedIconLayer to ItemizedLayer
This commit is contained in:
parent
7f64fff46d
commit
5ef8026ac4
@ -1 +1 @@
|
|||||||
Subproject commit 7f3da3fb6e7e8d40280e944ad1fa3bf0504cb4b2
|
Subproject commit b0e4f6b7579b22d5b01fe14ebb1b79b9c6f35b8f
|
@ -22,8 +22,8 @@ import java.util.List;
|
|||||||
import org.oscim.android.canvas.AndroidGraphics;
|
import org.oscim.android.canvas.AndroidGraphics;
|
||||||
import org.oscim.core.GeoPoint;
|
import org.oscim.core.GeoPoint;
|
||||||
import org.oscim.layers.TileGridLayer;
|
import org.oscim.layers.TileGridLayer;
|
||||||
import org.oscim.layers.marker.ItemizedIconLayer;
|
import org.oscim.layers.marker.ItemizedLayer;
|
||||||
import org.oscim.layers.marker.ItemizedIconLayer.OnItemGestureListener;
|
import org.oscim.layers.marker.ItemizedLayer.OnItemGestureListener;
|
||||||
import org.oscim.layers.marker.MarkerItem;
|
import org.oscim.layers.marker.MarkerItem;
|
||||||
import org.oscim.layers.marker.MarkerItem.HotspotPlace;
|
import org.oscim.layers.marker.MarkerItem.HotspotPlace;
|
||||||
import org.oscim.layers.marker.MarkerSymbol;
|
import org.oscim.layers.marker.MarkerSymbol;
|
||||||
@ -47,8 +47,8 @@ implements OnItemGestureListener<MarkerItem> {
|
|||||||
Drawable d = getResources().getDrawable(R.drawable.marker_poi);
|
Drawable d = getResources().getDrawable(R.drawable.marker_poi);
|
||||||
MarkerSymbol symbol = AndroidGraphics.makeMarker(d, HotspotPlace.CENTER);
|
MarkerSymbol symbol = AndroidGraphics.makeMarker(d, HotspotPlace.CENTER);
|
||||||
|
|
||||||
ItemizedIconLayer<MarkerItem> markerLayer =
|
ItemizedLayer<MarkerItem> markerLayer =
|
||||||
new ItemizedIconLayer<MarkerItem>(mMap, new ArrayList<MarkerItem>(),
|
new ItemizedLayer<MarkerItem>(mMap, new ArrayList<MarkerItem>(),
|
||||||
symbol, this);
|
symbol, this);
|
||||||
|
|
||||||
mMap.getLayers().add(markerLayer);
|
mMap.getLayers().add(markerLayer);
|
||||||
|
@ -53,4 +53,8 @@ public abstract class Layer {
|
|||||||
*/
|
*/
|
||||||
public void onDetach() {
|
public void onDetach() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map map() {
|
||||||
|
return mMap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,245 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 osmdroid authors
|
|
||||||
* Copyright 2013 Hannes Janetzek
|
|
||||||
*
|
|
||||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify it under the
|
|
||||||
* terms of the GNU Lesser 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 Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License along with
|
|
||||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package org.oscim.layers.marker;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.oscim.core.BoundingBox;
|
|
||||||
import org.oscim.core.Point;
|
|
||||||
import org.oscim.event.Gesture;
|
|
||||||
import org.oscim.event.GestureListener;
|
|
||||||
import org.oscim.event.MotionEvent;
|
|
||||||
import org.oscim.map.Map;
|
|
||||||
import org.oscim.map.Viewport;
|
|
||||||
|
|
||||||
public class ItemizedIconLayer<Item extends MarkerItem> extends ItemizedLayer<Item>
|
|
||||||
implements GestureListener {
|
|
||||||
//static final Logger log = LoggerFactory.getLogger(ItemizedIconOverlay.class);
|
|
||||||
|
|
||||||
protected final List<Item> mItemList;
|
|
||||||
protected OnItemGestureListener<Item> mOnItemGestureListener;
|
|
||||||
private int mDrawnItemsLimit = Integer.MAX_VALUE;
|
|
||||||
|
|
||||||
private final Point mTmpPoint = new Point();
|
|
||||||
|
|
||||||
public ItemizedIconLayer(Map map, List<Item> list,
|
|
||||||
MarkerSymbol defaultMarker,
|
|
||||||
OnItemGestureListener<Item> onItemGestureListener) {
|
|
||||||
|
|
||||||
super(map, defaultMarker);
|
|
||||||
|
|
||||||
mItemList = list;
|
|
||||||
mOnItemGestureListener = onItemGestureListener;
|
|
||||||
populate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onSnapToItem(int x, int y, Point snapPoint) {
|
|
||||||
// TODO Implement this!
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Item createItem(int index) {
|
|
||||||
return mItemList.get(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int size() {
|
|
||||||
return Math.min(mItemList.size(), mDrawnItemsLimit);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean addItem(Item item) {
|
|
||||||
final boolean result = mItemList.add(item);
|
|
||||||
populate();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addItem(int location, Item item) {
|
|
||||||
mItemList.add(location, item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean addItems(List<Item> items) {
|
|
||||||
final boolean result = mItemList.addAll(items);
|
|
||||||
populate();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeAllItems() {
|
|
||||||
removeAllItems(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeAllItems(boolean withPopulate) {
|
|
||||||
mItemList.clear();
|
|
||||||
if (withPopulate) {
|
|
||||||
populate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean removeItem(Item item) {
|
|
||||||
final boolean result = mItemList.remove(item);
|
|
||||||
populate();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Item removeItem(int position) {
|
|
||||||
final Item result = mItemList.remove(position);
|
|
||||||
populate();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Each of these methods performs a item sensitive check. If the item is
|
|
||||||
* located its corresponding method is called. The result of the call is
|
|
||||||
* returned. Helper methods are provided so that child classes may more
|
|
||||||
* easily override behavior without resorting to overriding the
|
|
||||||
* ItemGestureListener methods.
|
|
||||||
*/
|
|
||||||
// @Override
|
|
||||||
// public boolean onTap(MotionEvent event, MapPosition pos) {
|
|
||||||
// return activateSelectedItems(event, mActiveItemSingleTap);
|
|
||||||
// }
|
|
||||||
|
|
||||||
protected boolean onSingleTapUpHelper(int index, Item item) {
|
|
||||||
return mOnItemGestureListener.onItemSingleTapUp(index, item);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final ActiveItem mActiveItemSingleTap = new ActiveItem() {
|
|
||||||
@Override
|
|
||||||
public boolean run(int index) {
|
|
||||||
final ItemizedIconLayer<Item> that = ItemizedIconLayer.this;
|
|
||||||
if (that.mOnItemGestureListener == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return onSingleTapUpHelper(index, that.mItemList.get(index));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// @Override
|
|
||||||
// public boolean onLongPress(MotionEvent event, MapPosition pos) {
|
|
||||||
// return activateSelectedItems(event, mActiveItemLongPress);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// protected boolean onLongPressHelper(int index, Item item) {
|
|
||||||
// return this.mOnItemGestureListener.onItemLongPress(index, item);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private final ActiveItem mActiveItemLongPress = new ActiveItem() {
|
|
||||||
// @Override
|
|
||||||
// public boolean run(final int index) {
|
|
||||||
// final ItemizedIconLayer<Item> that = ItemizedIconLayer.this;
|
|
||||||
// if (that.mOnItemGestureListener == null) {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// return onLongPressHelper(index, getItem(index));
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// @Override
|
|
||||||
// public boolean onPress(MotionEvent e, MapPosition pos) {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When a content sensitive action is performed the content item needs to be
|
|
||||||
* identified. This method does that and then performs the assigned task on
|
|
||||||
* that item.
|
|
||||||
*
|
|
||||||
* @param event
|
|
||||||
* ...
|
|
||||||
* @param task
|
|
||||||
* ..
|
|
||||||
* @return true if event is handled false otherwise
|
|
||||||
*/
|
|
||||||
protected boolean activateSelectedItems(MotionEvent event, ActiveItem task) {
|
|
||||||
int size = mItemList.size();
|
|
||||||
if (size == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
int eventX = (int) event.getX() - mMap.getWidth() / 2;
|
|
||||||
int eventY = (int) event.getY() - mMap.getHeight() / 2;
|
|
||||||
Viewport mapPosition = mMap.getViewport();
|
|
||||||
|
|
||||||
BoundingBox bbox = mapPosition.getViewBox();
|
|
||||||
|
|
||||||
int nearest = -1;
|
|
||||||
double dist = Double.MAX_VALUE;
|
|
||||||
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
Item item = getItem(i);
|
|
||||||
|
|
||||||
if (!bbox.contains(item.mGeoPoint))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// TODO use intermediate projection
|
|
||||||
mapPosition.toScreenPoint(item.getPoint(), mTmpPoint);
|
|
||||||
|
|
||||||
float dx = (float) (mTmpPoint.x - eventX);
|
|
||||||
float dy = (float) (mTmpPoint.y - eventY);
|
|
||||||
|
|
||||||
// squared dist: 50*50 pixel
|
|
||||||
double d = dx * dx + dy * dy;
|
|
||||||
if (d < 2500) {
|
|
||||||
if (d < dist) {
|
|
||||||
dist = d;
|
|
||||||
nearest = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nearest >= 0 && task.run(nearest)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getDrawnItemsLimit() {
|
|
||||||
return this.mDrawnItemsLimit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDrawnItemsLimit(final int aLimit) {
|
|
||||||
this.mDrawnItemsLimit = aLimit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When the item is touched one of these methods may be invoked depending on
|
|
||||||
* the type of touch. Each of them returns true if the event was completely
|
|
||||||
* handled.
|
|
||||||
*
|
|
||||||
* @param <T>
|
|
||||||
* ....
|
|
||||||
*/
|
|
||||||
public static interface OnItemGestureListener<T> {
|
|
||||||
public boolean onItemSingleTapUp(int index, T item);
|
|
||||||
|
|
||||||
public boolean onItemLongPress(int index, T item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static interface ActiveItem {
|
|
||||||
public boolean run(int aIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onGesture(Gesture g, MotionEvent e) {
|
|
||||||
if (g instanceof Gesture.Tap)
|
|
||||||
return activateSelectedItems(e, mActiveItemSingleTap);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012 osmdroid authors
|
* Copyright 2012 osmdroid authors:
|
||||||
|
* Copyright 2012 Nicolas Gramlich
|
||||||
|
* Copyright 2012 Theodore Hong
|
||||||
|
* Copyright 2012 Fred Eisele
|
||||||
|
*
|
||||||
* Copyright 2013 Hannes Janetzek
|
* Copyright 2013 Hannes Janetzek
|
||||||
*
|
*
|
||||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||||
@ -15,287 +19,208 @@
|
|||||||
* You should have received a copy of the GNU Lesser General Public License along with
|
* You should have received a copy of the GNU Lesser General Public License along with
|
||||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.oscim.layers.marker;
|
package org.oscim.layers.marker;
|
||||||
|
|
||||||
// TODO
|
import java.util.List;
|
||||||
// - need to sort items back to front for rendering
|
|
||||||
// - and to make this work for multiple overlays
|
|
||||||
// a global scenegraph is probably required.
|
|
||||||
|
|
||||||
import org.oscim.core.MapPosition;
|
import org.oscim.core.BoundingBox;
|
||||||
import org.oscim.core.MercatorProjection;
|
|
||||||
import org.oscim.core.Point;
|
import org.oscim.core.Point;
|
||||||
import org.oscim.core.Tile;
|
import org.oscim.event.Gesture;
|
||||||
|
import org.oscim.event.GestureListener;
|
||||||
|
import org.oscim.event.MotionEvent;
|
||||||
import org.oscim.map.Map;
|
import org.oscim.map.Map;
|
||||||
import org.oscim.renderer.ElementRenderer;
|
import org.oscim.map.Viewport;
|
||||||
import org.oscim.renderer.MapRenderer.Matrices;
|
|
||||||
import org.oscim.renderer.elements.SymbolItem;
|
|
||||||
import org.oscim.renderer.elements.SymbolLayer;
|
|
||||||
import org.oscim.utils.GeometryUtils;
|
|
||||||
|
|
||||||
/* @author Marc Kurtz
|
public class ItemizedLayer<Item extends MarkerItem> extends MarkerLayer<Item>
|
||||||
* @author Nicolas Gramlich
|
implements GestureListener {
|
||||||
* @author Theodore Hong
|
|
||||||
* @author Fred Eisele
|
|
||||||
* @author Hannes Janetzek
|
|
||||||
* */
|
|
||||||
/**
|
|
||||||
* Draws a list of {@link MarkerItem} as markers to a map. The item with the
|
|
||||||
* lowest index is drawn as last and therefore the 'topmost' marker. It also
|
|
||||||
* gets checked for onTap first. This class is generic, because you then you get
|
|
||||||
* your custom item-class passed back in onTap().
|
|
||||||
*
|
|
||||||
* @param <Item>
|
|
||||||
* ...
|
|
||||||
*/
|
|
||||||
public abstract class ItemizedLayer<Item extends MarkerItem> extends MarkerLayer implements
|
|
||||||
MarkerLayer.Snappable {
|
|
||||||
|
|
||||||
//static final Logger log = LoggerFactory.getLogger(ItemizedOverlay.class);
|
//static final Logger log = LoggerFactory.getLogger(ItemizedIconOverlay.class);
|
||||||
|
|
||||||
protected final MarkerSymbol mDefaultMarker;
|
protected final List<Item> mItemList;
|
||||||
|
protected final Point mTmpPoint = new Point();
|
||||||
|
protected OnItemGestureListener<Item> mOnItemGestureListener;
|
||||||
|
protected int mDrawnItemsLimit = Integer.MAX_VALUE;
|
||||||
|
|
||||||
/** increase view to show items that are partially visible */
|
public ItemizedLayer(Map map, List<Item> list,
|
||||||
protected int mExtents = 100;
|
MarkerSymbol defaultMarker,
|
||||||
|
OnItemGestureListener<Item> onItemGestureListener) {
|
||||||
|
|
||||||
class InternalItem {
|
super(map, defaultMarker);
|
||||||
InternalItem next;
|
|
||||||
|
|
||||||
Item item;
|
mItemList = list;
|
||||||
boolean visible;
|
mOnItemGestureListener = onItemGestureListener;
|
||||||
boolean changes;
|
populate();
|
||||||
float x, y;
|
|
||||||
double px, py;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* package */InternalItem mItems;
|
|
||||||
/* package */Object lock = new Object();
|
|
||||||
/* package */Item mFocusedItem;
|
|
||||||
/* package */boolean mUpdate;
|
|
||||||
|
|
||||||
private int mSize;
|
|
||||||
|
|
||||||
class ItemOverlay extends ElementRenderer {
|
|
||||||
|
|
||||||
private final SymbolLayer mSymbolLayer;
|
|
||||||
private final float[] mBox = new float[8];
|
|
||||||
|
|
||||||
public ItemOverlay() {
|
|
||||||
mSymbolLayer = new SymbolLayer();
|
|
||||||
}
|
|
||||||
|
|
||||||
// note: this is called from GL-Thread. so check your syncs!
|
|
||||||
@Override
|
|
||||||
public synchronized void update(MapPosition pos, boolean changed, Matrices m) {
|
|
||||||
|
|
||||||
if (!changed && !mUpdate)
|
|
||||||
return;
|
|
||||||
|
|
||||||
mUpdate = false;
|
|
||||||
|
|
||||||
double mx = pos.x;
|
|
||||||
double my = pos.y;
|
|
||||||
double scale = Tile.SIZE * pos.scale;
|
|
||||||
|
|
||||||
int changesInvisible = 0;
|
|
||||||
int changedVisible = 0;
|
|
||||||
int numVisible = 0;
|
|
||||||
|
|
||||||
mMap.getViewport().getMapExtents(mBox, mExtents);
|
|
||||||
|
|
||||||
long flip = (long) (Tile.SIZE * pos.scale) >> 1;
|
|
||||||
|
|
||||||
synchronized (lock) {
|
|
||||||
if (mItems == null) {
|
|
||||||
if (layers.getTextureLayers() != null) {
|
|
||||||
layers.clear();
|
|
||||||
compile();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check visibility
|
|
||||||
for (InternalItem it = mItems; it != null; it = it.next) {
|
|
||||||
it.changes = false;
|
|
||||||
it.x = (float) ((it.px - mx) * scale);
|
|
||||||
it.y = (float) ((it.py - my) * scale);
|
|
||||||
|
|
||||||
if (it.x > flip)
|
|
||||||
it.x -= (flip << 1);
|
|
||||||
else if (it.x < -flip)
|
|
||||||
it.x += (flip << 1);
|
|
||||||
|
|
||||||
if (!GeometryUtils.pointInPoly(it.x, it.y, mBox, 8, 0)) {
|
|
||||||
if (it.visible) {
|
|
||||||
it.changes = true;
|
|
||||||
changesInvisible++;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!it.visible) {
|
|
||||||
it.visible = true;
|
|
||||||
changedVisible++;
|
|
||||||
}
|
|
||||||
numVisible++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//log.debug(numVisible + " " + changedVisible + " " + changesInvisible);
|
|
||||||
|
|
||||||
// only update when zoomlevel changed, new items are visible
|
|
||||||
// or more than 10 of the current items became invisible
|
|
||||||
if ((numVisible == 0) && (changedVisible == 0 && changesInvisible < 10))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// keep position for current state
|
|
||||||
// updateMapPosition();
|
|
||||||
mMapPosition.copy(pos);
|
|
||||||
|
|
||||||
layers.clear();
|
|
||||||
|
|
||||||
for (InternalItem it = mItems; it != null; it = it.next) {
|
|
||||||
if (!it.visible)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (it.changes) {
|
|
||||||
it.visible = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
MarkerSymbol marker = it.item.getMarker();
|
|
||||||
if (marker == null)
|
|
||||||
marker = mDefaultMarker;
|
|
||||||
|
|
||||||
SymbolItem s = SymbolItem.pool.get();
|
|
||||||
s.bitmap = marker.getBitmap();
|
|
||||||
|
|
||||||
s.x = it.x;
|
|
||||||
s.y = it.y;
|
|
||||||
s.offset = marker.getHotspot();
|
|
||||||
s.billboard = true;
|
|
||||||
|
|
||||||
mSymbolLayer.addSymbol(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mSymbolLayer.prepare();
|
|
||||||
layers.setTextureLayers(mSymbolLayer);
|
|
||||||
|
|
||||||
compile();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void compile() {
|
protected Item createItem(int index) {
|
||||||
super.compile();
|
return mItemList.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return Math.min(mItemList.size(), mDrawnItemsLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean addItem(Item item) {
|
||||||
|
final boolean result = mItemList.add(item);
|
||||||
|
populate();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addItem(int location, Item item) {
|
||||||
|
mItemList.add(location, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean addItems(List<Item> items) {
|
||||||
|
final boolean result = mItemList.addAll(items);
|
||||||
|
populate();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeAllItems() {
|
||||||
|
removeAllItems(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeAllItems(boolean withPopulate) {
|
||||||
|
mItemList.clear();
|
||||||
|
if (withPopulate) {
|
||||||
|
populate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean removeItem(Item item) {
|
||||||
|
final boolean result = mItemList.remove(item);
|
||||||
|
populate();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Item removeItem(int position) {
|
||||||
|
final Item result = mItemList.remove(position);
|
||||||
|
populate();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method by which subclasses create the actual Items. This will only be
|
* Each of these methods performs a item sensitive check. If the item is
|
||||||
* called from populate() we'll cache them for later use.
|
* located its corresponding method is called. The result of the call is
|
||||||
|
* returned. Helper methods are provided so that child classes may more
|
||||||
|
* easily override behavior without resorting to overriding the
|
||||||
|
* ItemGestureListener methods.
|
||||||
|
*/
|
||||||
|
// @Override
|
||||||
|
// public boolean onTap(MotionEvent event, MapPosition pos) {
|
||||||
|
// return activateSelectedItems(event, mActiveItemSingleTap);
|
||||||
|
// }
|
||||||
|
|
||||||
|
protected boolean onSingleTapUpHelper(int index, Item item) {
|
||||||
|
return mOnItemGestureListener.onItemSingleTapUp(index, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ActiveItem mActiveItemSingleTap = new ActiveItem() {
|
||||||
|
@Override
|
||||||
|
public boolean run(int index) {
|
||||||
|
final ItemizedLayer<Item> that = ItemizedLayer.this;
|
||||||
|
if (mOnItemGestureListener == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return onSingleTapUpHelper(index, that.mItemList.get(index));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public boolean onLongPress(MotionEvent event, MapPosition pos) {
|
||||||
|
// return activateSelectedItems(event, mActiveItemLongPress);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// protected boolean onLongPressHelper(int index, Item item) {
|
||||||
|
// return this.mOnItemGestureListener.onItemLongPress(index, item);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private final ActiveItem mActiveItemLongPress = new ActiveItem() {
|
||||||
|
// @Override
|
||||||
|
// public boolean run(final int index) {
|
||||||
|
// final ItemizedIconLayer<Item> that = ItemizedIconLayer.this;
|
||||||
|
// if (that.mOnItemGestureListener == null) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// return onLongPressHelper(index, getItem(index));
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public boolean onPress(MotionEvent e, MapPosition pos) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a content sensitive action is performed the content item needs to be
|
||||||
|
* identified. This method does that and then performs the assigned task on
|
||||||
|
* that item.
|
||||||
*
|
*
|
||||||
* @param i
|
* @return true if event is handled false otherwise
|
||||||
* ...
|
|
||||||
* @return ...
|
|
||||||
*/
|
*/
|
||||||
protected abstract Item createItem(int i);
|
protected boolean activateSelectedItems(MotionEvent event, ActiveItem task) {
|
||||||
|
int size = mItemList.size();
|
||||||
|
if (size == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
/**
|
int eventX = (int) event.getX() - mMap.getWidth() / 2;
|
||||||
* The number of items in this overlay.
|
int eventY = (int) event.getY() - mMap.getHeight() / 2;
|
||||||
*
|
Viewport mapPosition = mMap.getViewport();
|
||||||
* @return ...
|
|
||||||
*/
|
|
||||||
public abstract int size();
|
|
||||||
|
|
||||||
public ItemizedLayer(Map map, MarkerSymbol defaultSymbol) {
|
BoundingBox bbox = mapPosition.getViewBox();
|
||||||
super(map);
|
|
||||||
|
|
||||||
mDefaultMarker = defaultSymbol;
|
int nearest = -1;
|
||||||
mRenderer = new ItemOverlay();
|
|
||||||
|
/* squared dist: 50*50 pixel */
|
||||||
|
double dist = 2500;
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
Item item = mItemList.get(i);
|
||||||
|
|
||||||
|
if (!bbox.contains(item.mGeoPoint))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mapPosition.toScreenPoint(item.getPoint(), mTmpPoint);
|
||||||
|
|
||||||
|
float dx = (float) (mTmpPoint.x - eventX);
|
||||||
|
float dy = (float) (mTmpPoint.y - eventY);
|
||||||
|
|
||||||
|
double d = dx * dx + dy * dy;
|
||||||
|
if (d > dist)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
dist = d;
|
||||||
|
nearest = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Point mMapPoint = new Point();
|
if (nearest >= 0 && task.run(nearest))
|
||||||
|
return true;
|
||||||
|
|
||||||
/**
|
return false;
|
||||||
* Utility method to perform all processing on a new ItemizedOverlay.
|
|
||||||
* Subclasses provide Items through the createItem(int) method. The subclass
|
|
||||||
* should call this as soon as it has data, before anything else gets
|
|
||||||
* called.
|
|
||||||
*/
|
|
||||||
protected final void populate() {
|
|
||||||
synchronized (lock) {
|
|
||||||
final int size = size();
|
|
||||||
mSize = size;
|
|
||||||
|
|
||||||
// reuse previous items
|
|
||||||
InternalItem pool = mItems;
|
|
||||||
mItems = null;
|
|
||||||
|
|
||||||
// flip order to draw in backward cycle, so the items
|
|
||||||
// with the least index are on the front.
|
|
||||||
for (int a = 0; a < size; a++) {
|
|
||||||
InternalItem it;
|
|
||||||
if (pool != null) {
|
|
||||||
it = pool;
|
|
||||||
it.visible = false;
|
|
||||||
it.changes = false;
|
|
||||||
pool = pool.next;
|
|
||||||
} else {
|
|
||||||
it = new InternalItem();
|
|
||||||
}
|
|
||||||
it.next = mItems;
|
|
||||||
mItems = it;
|
|
||||||
|
|
||||||
it.item = createItem(a);
|
|
||||||
|
|
||||||
// pre-project points
|
|
||||||
MercatorProjection.project(it.item.getPoint(), mMapPoint);
|
|
||||||
it.px = mMapPoint.x;
|
|
||||||
it.py = mMapPoint.y;
|
|
||||||
}
|
|
||||||
mUpdate = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the Item at the given index.
|
* When the item is touched one of these methods may be invoked depending on
|
||||||
*
|
* the type of touch. Each of them returns true if the event was completely
|
||||||
* @param position
|
* handled.
|
||||||
* the position of the item to return
|
|
||||||
* @return the Item of the given index.
|
|
||||||
*/
|
*/
|
||||||
public final Item getItem(final int position) {
|
public static interface OnItemGestureListener<T> {
|
||||||
synchronized (lock) {
|
public boolean onItemSingleTapUp(int index, T item);
|
||||||
InternalItem item = mItems;
|
|
||||||
for (int i = mSize - position - 1; i > 0 && item != null; i--)
|
|
||||||
item = item.next;
|
|
||||||
|
|
||||||
if (item != null)
|
public boolean onItemLongPress(int index, T item);
|
||||||
return item.item;
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static interface ActiveItem {
|
||||||
* TODO
|
public boolean run(int aIndex);
|
||||||
* If the given Item is found in the overlay, force it to be the current
|
|
||||||
* focus-bearer. Any registered {link ItemizedLayer#OnFocusChangeListener}
|
|
||||||
* will be notified. This does not move the map, so if the Item isn't
|
|
||||||
* already centered, the user may get confused. If the Item is not found,
|
|
||||||
* this is a no-op. You can also pass null to remove focus.
|
|
||||||
*
|
|
||||||
* @param item
|
|
||||||
*/
|
|
||||||
public void setFocus(final Item item) {
|
|
||||||
mFocusedItem = item;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* @return the currently-focused item, or null if no item is currently
|
public boolean onGesture(Gesture g, MotionEvent e) {
|
||||||
* focused.
|
if (g instanceof Gesture.Tap)
|
||||||
*/
|
return activateSelectedItems(e, mActiveItemSingleTap);
|
||||||
public Item getFocus() {
|
|
||||||
return mFocusedItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012 osmdroid authors
|
* Copyright 2012 osmdroid authors:
|
||||||
* Copyright 2013 Hannes Janetzek
|
* Copyright 2012 Nicolas Gramlich
|
||||||
|
* Copyright 2012 Theodore Hong
|
||||||
|
* Copyright 2012 Fred Eisele
|
||||||
|
*
|
||||||
|
* Copyright 2014 Hannes Janetzek
|
||||||
*
|
*
|
||||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||||
*
|
*
|
||||||
@ -16,17 +20,12 @@
|
|||||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Created by plusminus on 00:02:58 - 03.10.2008
|
|
||||||
package org.oscim.layers.marker;
|
package org.oscim.layers.marker;
|
||||||
|
|
||||||
import org.oscim.core.GeoPoint;
|
import org.oscim.core.GeoPoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Immutable class describing a GeoPoint with a Title and a Description.
|
* Immutable class describing a GeoPoint with a Title and a Description.
|
||||||
*
|
|
||||||
* @author Nicolas Gramlich
|
|
||||||
* @author Theodore Hong
|
|
||||||
* @author Fred Eisele
|
|
||||||
*/
|
*/
|
||||||
public class MarkerItem {
|
public class MarkerItem {
|
||||||
|
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012 osmdroid authors
|
* Copyright 2012 osmdroid authors:
|
||||||
|
* Copyright 2012 Nicolas Gramlich
|
||||||
|
* Copyright 2012 Theodore Hong
|
||||||
|
* Copyright 2012 Fred Eisele
|
||||||
|
*
|
||||||
* Copyright 2013 Hannes Janetzek
|
* Copyright 2013 Hannes Janetzek
|
||||||
*
|
*
|
||||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||||
@ -22,19 +26,73 @@ import org.oscim.core.Point;
|
|||||||
import org.oscim.layers.Layer;
|
import org.oscim.layers.Layer;
|
||||||
import org.oscim.map.Map;
|
import org.oscim.map.Map;
|
||||||
|
|
||||||
public abstract class MarkerLayer extends Layer {
|
/**
|
||||||
|
* Draws a list of {@link MarkerItem} as markers to a map. The item with the
|
||||||
|
* lowest index is drawn as last and therefore the 'topmost' marker. It also
|
||||||
|
* gets checked for onTap first. This class is generic, because you then you get
|
||||||
|
* your custom item-class passed back in onTap(). << TODO
|
||||||
|
*/
|
||||||
|
public abstract class MarkerLayer<Item extends MarkerItem> extends Layer {
|
||||||
|
|
||||||
public MarkerLayer(Map map) {
|
protected final MarkerRenderer mMarkerRenderer;
|
||||||
|
protected Item mFocusedItem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method by which subclasses create the actual Items. This will only be
|
||||||
|
* called from populate() we'll cache them for later use.
|
||||||
|
*/
|
||||||
|
protected abstract Item createItem(int i);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of items in this overlay.
|
||||||
|
*/
|
||||||
|
public abstract int size();
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public MarkerLayer(Map map, MarkerSymbol defaultSymbol) {
|
||||||
super(map);
|
super(map);
|
||||||
|
|
||||||
|
mMarkerRenderer = new MarkerRenderer((MarkerLayer<MarkerItem>) this, defaultSymbol);
|
||||||
|
mRenderer = mMarkerRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TBD
|
* Utility method to perform all processing on a new ItemizedOverlay.
|
||||||
|
* Subclasses provide Items through the createItem(int) method. The subclass
|
||||||
|
* should call this as soon as it has data, before anything else gets
|
||||||
|
* called.
|
||||||
|
*/
|
||||||
|
protected final void populate() {
|
||||||
|
mMarkerRenderer.populate(size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
* If the given Item is found in the overlay, force it to be the current
|
||||||
|
* focus-bearer. Any registered {link ItemizedLayer#OnFocusChangeListener}
|
||||||
|
* will be notified. This does not move the map, so if the Item isn't
|
||||||
|
* already centered, the user may get confused. If the Item is not found,
|
||||||
|
* this is a no-op. You can also pass null to remove focus.
|
||||||
*
|
*
|
||||||
|
* @param item
|
||||||
|
*/
|
||||||
|
public void setFocus(Item item) {
|
||||||
|
mFocusedItem = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the currently-focused item, or null if no item is currently
|
||||||
|
* focused.
|
||||||
|
*/
|
||||||
|
public Item getFocus() {
|
||||||
|
return mFocusedItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
* Interface definition for overlays that contain items that can be snapped
|
* Interface definition for overlays that contain items that can be snapped
|
||||||
* to (for example, when the user invokes a zoom, this could be called
|
* to (for example, when the user invokes a zoom, this could be called
|
||||||
* allowing the user to snap the zoom to an interesting point.)
|
* allowing the user to snap the zoom to an interesting point.)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public interface Snappable {
|
public interface Snappable {
|
||||||
|
|
||||||
|
213
vtm/src/org/oscim/layers/marker/MarkerRenderer.java
Normal file
213
vtm/src/org/oscim/layers/marker/MarkerRenderer.java
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 Hannes Janetzek
|
||||||
|
*
|
||||||
|
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.oscim.layers.marker;
|
||||||
|
|
||||||
|
import org.oscim.core.MapPosition;
|
||||||
|
import org.oscim.core.MercatorProjection;
|
||||||
|
import org.oscim.core.Point;
|
||||||
|
import org.oscim.core.Tile;
|
||||||
|
import org.oscim.map.Map;
|
||||||
|
import org.oscim.renderer.ElementRenderer;
|
||||||
|
import org.oscim.renderer.MapRenderer.Matrices;
|
||||||
|
import org.oscim.renderer.elements.SymbolItem;
|
||||||
|
import org.oscim.renderer.elements.SymbolLayer;
|
||||||
|
import org.oscim.utils.GeometryUtils;
|
||||||
|
import org.oscim.utils.pool.Inlist;
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
//- need to sort items back to front for rendering
|
||||||
|
//- and to make this work for multiple overlays
|
||||||
|
//a global scenegraph is probably required.
|
||||||
|
|
||||||
|
public class MarkerRenderer extends ElementRenderer {
|
||||||
|
|
||||||
|
protected final MarkerSymbol mDefaultMarker;
|
||||||
|
|
||||||
|
private final SymbolLayer mSymbolLayer;
|
||||||
|
private final float[] mBox = new float[8];
|
||||||
|
private final MarkerLayer<MarkerItem> mMarkerLayer;
|
||||||
|
/** increase view to show items that are partially visible */
|
||||||
|
protected int mExtents = 100;
|
||||||
|
private boolean mUpdate;
|
||||||
|
private Map mMap;
|
||||||
|
private InternalItem mItems;
|
||||||
|
private final Point mMapPoint = new Point();
|
||||||
|
|
||||||
|
static class InternalItem extends Inlist<InternalItem> {
|
||||||
|
MarkerItem item;
|
||||||
|
boolean visible;
|
||||||
|
boolean changes;
|
||||||
|
float x, y;
|
||||||
|
double px, py;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MarkerRenderer(MarkerLayer<MarkerItem> markerLayer, MarkerSymbol defaultSymbol) {
|
||||||
|
mSymbolLayer = new SymbolLayer();
|
||||||
|
mMarkerLayer = markerLayer;
|
||||||
|
mDefaultMarker = defaultSymbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void update(MapPosition pos, boolean changed, Matrices m) {
|
||||||
|
|
||||||
|
if (!changed && !mUpdate)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mUpdate = false;
|
||||||
|
|
||||||
|
double mx = pos.x;
|
||||||
|
double my = pos.y;
|
||||||
|
double scale = Tile.SIZE * pos.scale;
|
||||||
|
|
||||||
|
int changesInvisible = 0;
|
||||||
|
int changedVisible = 0;
|
||||||
|
int numVisible = 0;
|
||||||
|
|
||||||
|
mMarkerLayer.map().getViewport().getMapExtents(mBox, mExtents);
|
||||||
|
|
||||||
|
long flip = (long) (Tile.SIZE * pos.scale) >> 1;
|
||||||
|
|
||||||
|
if (mItems == null) {
|
||||||
|
if (layers.getTextureLayers() != null) {
|
||||||
|
layers.clear();
|
||||||
|
compile();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check visibility */
|
||||||
|
for (InternalItem it = mItems; it != null; it = it.next) {
|
||||||
|
it.changes = false;
|
||||||
|
it.x = (float) ((it.px - mx) * scale);
|
||||||
|
it.y = (float) ((it.py - my) * scale);
|
||||||
|
|
||||||
|
if (it.x > flip)
|
||||||
|
it.x -= (flip << 1);
|
||||||
|
else if (it.x < -flip)
|
||||||
|
it.x += (flip << 1);
|
||||||
|
|
||||||
|
if (!GeometryUtils.pointInPoly(it.x, it.y, mBox, 8, 0)) {
|
||||||
|
if (it.visible) {
|
||||||
|
it.changes = true;
|
||||||
|
changesInvisible++;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!it.visible) {
|
||||||
|
it.visible = true;
|
||||||
|
changedVisible++;
|
||||||
|
}
|
||||||
|
numVisible++;
|
||||||
|
}
|
||||||
|
|
||||||
|
//log.debug(numVisible + " " + changedVisible + " " + changesInvisible);
|
||||||
|
|
||||||
|
/* only update when zoomlevel changed, new items are visible
|
||||||
|
* or more than 10 of the current items became invisible */
|
||||||
|
if ((numVisible == 0) && (changedVisible == 0 && changesInvisible < 10))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* keep position for current state */
|
||||||
|
mMapPosition.copy(pos);
|
||||||
|
|
||||||
|
layers.clear();
|
||||||
|
|
||||||
|
for (InternalItem it = mItems; it != null; it = it.next) {
|
||||||
|
if (!it.visible)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (it.changes) {
|
||||||
|
it.visible = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkerSymbol marker = it.item.getMarker();
|
||||||
|
if (marker == null)
|
||||||
|
marker = mDefaultMarker;
|
||||||
|
|
||||||
|
SymbolItem s = SymbolItem.pool.get();
|
||||||
|
s.bitmap = marker.getBitmap();
|
||||||
|
|
||||||
|
s.x = it.x;
|
||||||
|
s.y = it.y;
|
||||||
|
s.offset = marker.getHotspot();
|
||||||
|
s.billboard = true;
|
||||||
|
|
||||||
|
mSymbolLayer.addSymbol(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
mSymbolLayer.prepare();
|
||||||
|
layers.setTextureLayers(mSymbolLayer);
|
||||||
|
|
||||||
|
compile();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void compile() {
|
||||||
|
super.compile();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected synchronized void populate(int size) {
|
||||||
|
|
||||||
|
InternalItem pool = mItems;
|
||||||
|
mItems = null;
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
InternalItem it;
|
||||||
|
if (pool != null) {
|
||||||
|
it = pool;
|
||||||
|
it.visible = false;
|
||||||
|
it.changes = false;
|
||||||
|
pool = pool.next;
|
||||||
|
} else {
|
||||||
|
it = new InternalItem();
|
||||||
|
}
|
||||||
|
it.next = mItems;
|
||||||
|
mItems = it;
|
||||||
|
|
||||||
|
it.item = mMarkerLayer.createItem(i);
|
||||||
|
|
||||||
|
/* pre-project points */
|
||||||
|
MercatorProjection.project(it.item.getPoint(), mMapPoint);
|
||||||
|
it.px = mMapPoint.x;
|
||||||
|
it.py = mMapPoint.y;
|
||||||
|
}
|
||||||
|
mUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * Returns the Item at the given index.
|
||||||
|
// *
|
||||||
|
// * @param position
|
||||||
|
// * the position of the item to return
|
||||||
|
// * @return the Item of the given index.
|
||||||
|
// */
|
||||||
|
// public final Item getItem(int position) {
|
||||||
|
//
|
||||||
|
// synchronized (lock) {
|
||||||
|
// InternalItem item = mItems;
|
||||||
|
// for (int i = mSize - position - 1; i > 0 && item != null; i--)
|
||||||
|
// item = item.next;
|
||||||
|
//
|
||||||
|
// if (item != null)
|
||||||
|
// return item.item;
|
||||||
|
//
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user