Change preference screen

This commit is contained in:
Victor Shcherb 2011-05-29 23:12:24 +02:00
parent 3b202f03c8
commit f85fa4118d
10 changed files with 138 additions and 111 deletions

View file

@ -11,23 +11,18 @@ public class ToDoConstants {
// == Osmand application (TODO 127) ==
// Map Refactoring
// || 124 || Animated transition using only raster images (?) - skip animations (!) - don not render vectoring for animations (Issue 238) ||
// Fix issue with min/max zoom
// Empty screen replace (?)
// Remove notification from OsmAndMapTileView (?)
// Refactoring ResourceManager with cached images (tiles density)
// YandexLayer goes to MapTileLayer
// Add transparency filter to bitmap layers
// Download layers from internet / Yandex Traffic (not download on osmand?)
// Review all constructors of TileSourceTemplate
/// allow to add own tile sources from application (?)
// Manage tile sources and allow to compact them into sqlite db
// Allow to create over/under map layers
// Allow to config transparency filter
// Yandex Traffic make downloadable
// allow to add own tile sources from OsmAnd (?)
// allow to create sqlite sources from OsmAnd (?)
// === Refactoring issues ===
// !|| 125 || Introduce service layer rather than singletons and put all related into new package (services). Review architecture. Split some big classes. ||
// === Common issues ===
// || 104 || Add activity to show current loaded indexes and information about them (Issue 366) ||
// || 123 || Improve gpx file showing (very slow for big files) (Issue 412) ||
@ -49,9 +44,6 @@ public class ToDoConstants {
// === Unscheduled (complex) ===
// || 65 || Intermediate points - for better control routing, to avoid traffic jams ...(?) ||
// _19. colors for road trunk and motorway
/////////////////////////// DONE //////////////////////////////
// DONE ANDROID :
// || 112 || Investigate exiting/minimizing app (Issue 214) ||
@ -59,9 +51,8 @@ public class ToDoConstants {
// || 120 || Show icons over poi circle (issue 414) ||
// || 119 || Dialog on main screen tips and tricks (Issue 415) ||
// || 118 || Config switching between maps on different zoom levels <14 (using raster), > 14 vector (Issue 419) ||
// || 124 || Animated transition using only raster images (?) - skip animations (!) - don not render vectoring for animations (Issue 238) ||
// DONE SWING
}

View file

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="map_vector_data">Векторные карты</string>
<string name="map_vector_data_descr">Использовать загруженные векторные карты</string>
<string name="tile_source_already_installed">Карта уже установлена, настройки будут обновлены</string>
<string name="select_tile_source_to_install">Выберите карты для установки или обновления</string>
<string name="internet_not_available">Интернет соединение не доступно</string>
@ -437,7 +439,7 @@
<string name="show_poi_over_map_description">Показывать слой POI</string>
<string name="show_poi_over_map">POI</string>
<string name="map_tile_source_descr">Загружать недостающие части карты из : </string>
<string name="map_tile_source">Источник данных</string>
<string name="map_tile_source">Растровые карты</string>
<string name="map_source">Источник карты</string>
<string name="use_internet">Интернет</string>
<string name="show_location">Показать место</string>

View file

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<resources>
<string name="map_vector_data">Vector maps</string>
<string name="map_vector_data_descr">Use downloaded vector maps</string>
<string name="tile_source_already_installed">Map is already installed, settings will be updated</string>
<string name="select_tile_source_to_install">Select maps to install or update</string>
<string name="internet_not_available">Internet connection required for operation is not available</string>

View file

@ -4,6 +4,8 @@
<ListPreference android:summary="@string/settings_preset_descr" android:title="@string/settings_preset" android:key="application_mode"></ListPreference>
<PreferenceScreen android:title="@string/rendering_settings" android:summary="@string/rendering_settings_descr">
<CheckBoxPreference android:summary="@string/map_vector_data_descr" android:title="@string/map_vector_data"
android:key="map_vector_data"></CheckBoxPreference>
<ListPreference android:title="@string/map_tile_source" android:summary="@string/map_tile_source_descr" android:key="map_tile_sources"></ListPreference>
<CheckBoxPreference android:summary="@string/use_english_names_descr" android:title="@string/use_english_names"
android:key="use_english_names"></CheckBoxPreference>

View file

@ -510,18 +510,13 @@ public class OsmandSettings {
}
// this value string is synchronized with settings_pref.xml preference name
public static final String MAP_VECTOR_DATA = "map_vector_data"; //$NON-NLS-1$
public final CommonPreference<Boolean> MAP_VECTOR_DATA = new BooleanPreference("map_vector_data",
false, true);
// this value string is synchronized with settings_pref.xml preference name
public static final String MAP_TILE_SOURCES = "map_tile_sources"; //$NON-NLS-1$
public boolean isUsingMapVectorData(){
return globalPreferences.getBoolean(MAP_VECTOR_DATA, false);
}
public boolean setUsingMapVectorData(boolean val){
return globalPreferences.edit().putBoolean(MAP_VECTOR_DATA, val).commit();
}
public boolean setMapTileSource(String tileSource){
return globalPreferences.edit().putString(MAP_TILE_SOURCES, tileSource).commit();
}

View file

@ -47,7 +47,7 @@ public class DownloadTilesDialog {
public void openDialog(){
BaseMapLayer mainLayer = mapView.getMainLayer();
if(!(mainLayer instanceof MapTileLayer) || ((MapTileLayer) mainLayer).isVisible()){
if(!(mainLayer instanceof MapTileLayer) || !((MapTileLayer) mainLayer).isVisible()){
Toast.makeText(ctx, R.string.maps_could_not_be_downloaded, Toast.LENGTH_SHORT).show();
}
final ITileSource mapSource = ((MapTileLayer) mainLayer).getMap();

View file

@ -158,7 +158,7 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
@Override
public void onDismiss(DialogInterface dialog) {
OsmandApplication app = ((OsmandApplication)getApplication());
if(settings.isUsingMapVectorData() && app.getResourceManager().getRenderer().isEmpty()){
if(settings.MAP_VECTOR_DATA.get() && app.getResourceManager().getRenderer().isEmpty()){
Toast.makeText(MapActivity.this, getString(R.string.no_vector_map_loaded), Toast.LENGTH_LONG).show();
}
}

View file

@ -181,13 +181,13 @@ public class MapActivityLayers {
public void updateMapSource(OsmandMapTileView mapView){
OsmandSettings settings = getApplication().getSettings();
boolean showTiles = !settings.isUsingMapVectorData();
boolean showTiles = !settings.MAP_VECTOR_DATA.get();
ITileSource source = showTiles ? settings.getMapTileSource() : null;
if (showTiles == mapTileLayer.isVisible() && Algoritms.objectEquals(mapTileLayer.getMap(), source)) {
return;
}
boolean vectorData = settings.isUsingMapVectorData();
boolean vectorData = settings.MAP_VECTOR_DATA.get();
OsmandApplication app = ((OsmandApplication)getApplication());
ResourceManager rm = app.getResourceManager();
if(vectorData && !app.isApplicationInitializing()){
@ -440,14 +440,19 @@ public class MapActivityLayers {
Toast.makeText(activity, getString(R.string.no_vector_map_loaded), Toast.LENGTH_LONG).show();
return;
} else {
settings.setUsingMapVectorData(true);
settings.MAP_VECTOR_DATA.set(true);
}
updateMapSource(mapView);
} else if (which == items.length - 1){
installMapLayers(mapView);
SettingsActivity.installMapLayers(activity, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
openLayerSelectionDialog(mapView);
}
});
} else {
settings.setMapTileSource(keys.get(which - 1));
settings.setUsingMapVectorData(false);
settings.MAP_VECTOR_DATA.set(false);
updateMapSource(mapView);
}
@ -457,54 +462,7 @@ public class MapActivityLayers {
builder.show();
}
private void installMapLayers(final OsmandMapTileView mapView){
final OsmandSettings settings = getApplication().getSettings();
final Map<String, String> entriesMap = settings.getTileSourceEntries();
if(!settings.isInternetConnectionAvailable(true)){
Toast.makeText(activity, R.string.internet_not_available, Toast.LENGTH_LONG).show();
return;
}
final List<TileSourceTemplate> downloaded = TileSourceManager.downloadTileSourceTemplates();
if(downloaded == null || downloaded.isEmpty()){
Toast.makeText(activity, R.string.error_io_error, Toast.LENGTH_SHORT).show();
return;
}
Builder builder = new AlertDialog.Builder(activity);
String[] names = new String[downloaded.size()];
for(int i=0; i<names.length; i++){
names[i] = downloaded.get(i).getName();
}
final boolean[] selected = new boolean[downloaded.size()];
builder.setMultiChoiceItems(names, selected, new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
selected[which] = isChecked;
if(entriesMap.containsKey(downloaded.get(which).getName()) && isChecked){
Toast.makeText(activity, R.string.tile_source_already_installed, Toast.LENGTH_SHORT).show();
}
}
});
builder.setNegativeButton(R.string.default_buttons_cancel, null);
builder.setTitle(R.string.select_tile_source_to_install);
builder.setPositiveButton(R.string.default_buttons_apply, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
List<TileSourceTemplate> toInstall = new ArrayList<TileSourceTemplate>();
for(int i=0; i<selected.length; i++){
if(selected[i]){
toInstall.add(downloaded.get(i));
}
}
for(TileSourceTemplate ts : toInstall){
settings.installTileSource(ts);
}
openLayerSelectionDialog(mapView);
}
});
builder.show();
}
private String getString(int resId) {
return activity.getString(resId);

View file

@ -1,6 +1,7 @@
package net.osmand.plus.activities;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
@ -9,6 +10,8 @@ import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import net.osmand.map.TileSourceManager;
import net.osmand.map.TileSourceManager.TileSourceTemplate;
import net.osmand.plus.NavigationService;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.ProgressDialogImplementation;
@ -18,6 +21,8 @@ import net.osmand.plus.OsmandSettings.DayNightMode;
import net.osmand.plus.OsmandSettings.MetricsConstants;
import net.osmand.plus.OsmandSettings.OsmandPreference;
import net.osmand.plus.activities.RouteProvider.RouteService;
import net.osmand.plus.render.MapRenderRepositories;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.app.AlertDialog.Builder;
@ -42,8 +47,7 @@ import android.preference.Preference.OnPreferenceClickListener;
import android.widget.Toast;
public class SettingsActivity extends PreferenceActivity implements OnPreferenceChangeListener, OnPreferenceClickListener {
private final static String VECTOR_MAP = "#VECTOR_MAP"; //$NON-NLS-1$
private static final String MORE_VALUE = "MORE_VALUE";
private Preference saveCurrentTrack;
private Preference reloadIndexes;
@ -144,6 +148,7 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
registerBooleanPreference(osmandSettings.FAST_ROUTE_MODE,screen);
registerBooleanPreference(osmandSettings.USE_OSMAND_ROUTING_SERVICE_ALWAYS,screen);
registerBooleanPreference(osmandSettings.USE_INTERNET_TO_DOWNLOAD_TILES,screen);
registerBooleanPreference(osmandSettings.MAP_VECTOR_DATA,screen);
registerEditTextPreference(osmandSettings.USER_NAME, screen);
registerEditTextPreference(osmandSettings.USER_PASSWORD, screen);
@ -319,19 +324,6 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
// Specific properties
routeServiceEnabled.setChecked(getMyApplication().getNavigationService() != null);
Map<String, String> entriesMap = osmandSettings.getTileSourceEntries();
String[] entries = new String[entriesMap.size() + 1];
String[] values = new String[entriesMap.size() + 1];
values[0] = VECTOR_MAP;
entries[0] = getString(R.string.vector_data);
int ki = 1;
for(Map.Entry<String, String> es : entriesMap.entrySet()){
entries[ki] = es.getValue();
values[ki] = es.getKey();
ki++;
}
String value = osmandSettings.isUsingMapVectorData()? VECTOR_MAP : osmandSettings.getMapTileSourceName();
fill(tileSourcePreference, entries, values, value);
updateTileSourceSummary();
@ -339,8 +331,21 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
}
private void updateTileSourceSummary() {
String mapName = " " + (osmandSettings.isUsingMapVectorData() ? getString(R.string.vector_data) : //$NON-NLS-1$
osmandSettings.getMapTileSourceName());
Map<String, String> entriesMap = osmandSettings.getTileSourceEntries();
String[] entries = new String[entriesMap.size() + 1];
String[] values = new String[entriesMap.size() + 1];
int ki = 0;
for(Map.Entry<String, String> es : entriesMap.entrySet()){
entries[ki] = es.getValue();
values[ki] = es.getKey();
ki++;
}
entries[ki] = getString(R.string.more_external_layer);
values[ki] = MORE_VALUE;
String value = osmandSettings.getMapTileSourceName();
fill(tileSourcePreference, entries, values, value);
String mapName = " " + osmandSettings.getMapTileSourceName(); //$NON-NLS-1$
String summary = tileSourcePreference.getSummary().toString();
if (summary.lastIndexOf(':') != -1) {
summary = summary.substring(0, summary.lastIndexOf(':') + 1);
@ -364,6 +369,13 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
OsmandPreference<String> editPref = editTextPreferences.get(preference.getKey());
if(boolPref != null){
boolPref.set((Boolean)newValue);
if (boolPref.getId().equals(osmandSettings.MAP_VECTOR_DATA.getId())) {
MapRenderRepositories r = ((OsmandApplication)getApplication()).getResourceManager().getRenderer();
if(r.isEmpty()){
Toast.makeText(this, getString(R.string.no_vector_map_loaded), Toast.LENGTH_LONG).show();
return false;
}
}
} else if (editPref != null) {
editPref.set((String) newValue);
} else if (listPref != null) {
@ -410,17 +422,23 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
}
}
} else if (preference == tileSourcePreference) {
if(VECTOR_MAP.equals((String) newValue)){
osmandSettings.setUsingMapVectorData(true);
} else {
osmandSettings.setUsingMapVectorData(false);
osmandSettings.setMapTileSource((String) newValue);
}
if(MORE_VALUE.equals(newValue)){
SettingsActivity.installMapLayers(this, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
updateTileSourceSummary();
}
});
} else {
osmandSettings.setMapTileSource((String) newValue);
updateTileSourceSummary();
}
}
return true;
}
private void warnAboutChangingStorage(final String newValue) {
final String newDir = newValue != null ? newValue.trim(): newValue;
File path = new File(newDir);
@ -545,4 +563,55 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
}
return false;
}
public static void installMapLayers(final Activity activity, final DialogInterface.OnClickListener onClickListener){
final OsmandSettings settings = ((OsmandApplication) activity.getApplication()).getSettings();
final Map<String, String> entriesMap = settings.getTileSourceEntries();
if(!settings.isInternetConnectionAvailable(true)){
Toast.makeText(activity, R.string.internet_not_available, Toast.LENGTH_LONG).show();
return;
}
final List<TileSourceTemplate> downloaded = TileSourceManager.downloadTileSourceTemplates();
if(downloaded == null || downloaded.isEmpty()){
Toast.makeText(activity, R.string.error_io_error, Toast.LENGTH_SHORT).show();
return;
}
Builder builder = new AlertDialog.Builder(activity);
String[] names = new String[downloaded.size()];
for(int i=0; i<names.length; i++){
names[i] = downloaded.get(i).getName();
}
final boolean[] selected = new boolean[downloaded.size()];
builder.setMultiChoiceItems(names, selected, new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
selected[which] = isChecked;
if(entriesMap.containsKey(downloaded.get(which).getName()) && isChecked){
Toast.makeText(activity, R.string.tile_source_already_installed, Toast.LENGTH_SHORT).show();
}
}
});
builder.setNegativeButton(R.string.default_buttons_cancel, null);
builder.setTitle(R.string.select_tile_source_to_install);
builder.setPositiveButton(R.string.default_buttons_apply, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
List<TileSourceTemplate> toInstall = new ArrayList<TileSourceTemplate>();
for(int i=0; i<selected.length; i++){
if(selected[i]){
toInstall.add(downloaded.get(i));
}
}
for(TileSourceTemplate ts : toInstall){
settings.installTileSource(ts);
}
if(onClickListener != null){
onClickListener.onClick(dialog, which);
}
}
});
builder.show();
}
}

View file

@ -7,26 +7,34 @@
<tile_source name="GoogleMaps Satellite" url_template="http://khm1.google.com/kh/v=65&amp;x={1}&amp;y={2}&amp;z={0}" ext=".jpg" min_zoom="7" max_zoom="20" tile_size="256" img_density="32" avg_img_size="18000"/>
<tile_source name="GoogleMaps Terrain" url_template="http://mt3.google.com/vt/v=w2p.111&amp;hl=en&amp;x={1}&amp;y={2}&amp;z={0}" ext=".jpg" min_zoom="5" max_zoom="15" tile_size="256" img_density="32" avg_img_size="18000"/>
<tile_source rule="cykloatlas_cz" name="Cykloatlas CZ" url_template="http://services.tmapserver.cz/tiles/gm/shc/{0}/{1}/{2}.png" ext=".png" min_zoom="7" max_zoom="16" tile_size="256" img_density="16" avg_img_size="26000"/>
<tile_source rule="microsoft" name="Microsoft Maps" map_type="r" map_ext="png" ext=".png" min_zoom="1" max_zoom="19" tile_size="256" img_density="16" avg_img_size="18000"/>
<tile_source rule="microsoft" name="Microsoft Hybrid" map_type="h" map_ext="jpg" ext=".jpg" min_zoom="1" max_zoom="19" tile_size="256" img_density="32" avg_img_size="18000"/>
<tile_source rule="microsoft" name="Microsoft Earth" map_type="a" map_ext="jpg" ext=".jpg" min_zoom="1" max_zoom="19" tile_size="256" img_density="32" avg_img_size="18000"/>
<tile_source name="ÖPNV Transit" url_template="http://tile.xn--pnvkarte-m4a.de/tilegen/{0}/{1}/{2}.png" ext=".png" min_zoom="1" max_zoom="18" tile_size="256" img_density="16" avg_img_size="18000"/>
<tile_source name="OpenCycleMap" url_template="http://c.tile.opencyclemap.org/cycle/{0}/{1}/{2}.png" ext=".png" min_zoom="1" max_zoom="18" tile_size="256" img_density="16" avg_img_size="18000"/>
<tile_source name="HikeBikeMap DE" url_template="http://toolserver.org/tiles/hikebike/{0}/{1}/{2}.png" ext=".png" min_zoom="1" max_zoom="17" tile_size="256" img_density="8" avg_img_size="18000"/>
<tile_source name="OpenAerialMap" url_template="http://tile.openaerialmap.org/tiles/1.0.0/openaerialmap-900913/{0}/{1}/{2}.jpg" ext=".jpg" min_zoom="1" max_zoom="13" tile_size="256" img_density="16" avg_img_size="18000"/>
<tile_source name="MapSurfer" url_template="http://tiles1.mapsurfer.net/tms_r.ashx?z={0}&amp;x={1}&amp;y={2}" ext=".png" min_zoom="1" max_zoom="19" tile_size="256" img_density="16" avg_img_size="18000"/>
<tile_source name="HikeBikeMap DE" url_template="http://toolserver.org/tiles/hikebike/{0}/{1}/{2}.png" ext=".png" min_zoom="1" max_zoom="17" tile_size="256" img_density="8" avg_img_size="18000"/>
<tile_source name="NavigationDebug" url_template="http://ec2-184-73-15-218.compute-1.amazonaws.com/6700/256/{0}/{1}/{2}.png" ext=".png" min_zoom="1" max_zoom="18" tile_size="256" img_density="16" avg_img_size="18000"/>
<tile_source name="OpenPisteMap" url_template="http://openpistemap.org/tiles/contours/{0}/{1}/{2}.png" ext=".png" min_zoom="5" max_zoom="17" tile_size="256" img_density="32" avg_img_size="18000"/>
<tile_source name="Relief" url_template="http://www.maps-for-free.com/layer/relief/z{0}/row{2}/{0}_{1}-{2}.jpg" ext=".jpg" min_zoom="1" max_zoom="12" tile_size="256" img_density="32" avg_img_size="24000"/>
<tile_source rule="cykloatlas_cz" name="Cykloatlas CZ" url_template="http://services.tmapserver.cz/tiles/gm/shc/{0}/{1}/{2}.png" ext=".png" min_zoom="7" max_zoom="16" tile_size="256" img_density="16" avg_img_size="26000"/>
<tile_source name="MTB Map CZ" url_template="http://tchor.fi.muni.cz:8080/mtbmap_tiles/{0}/{1}/{2}.png" ext=".png" min_zoom="7" max_zoom="16" tile_size="256" img_density="32" avg_img_size="18000"/>
<tile_source name="Yandex RU" url_template="http://vec01.maps.yandex.ru/tiles?l=map&amp;v=2.15.0&amp;x={1}&amp;y={2}&amp;z={0}" ext=".jpg" min_zoom="1" max_zoom="18" tile_size="256" img_density="16" avg_img_size="18000" ellipsoid="true"/>
<tile_source name="Yandex Satellite RU" url_template="http://sat01.maps.yandex.ru/tiles?l=sat&amp;v=1.19.0&amp;x={1}&amp;y={2}&amp;z={0}" ext=".jpg" min_zoom="1" max_zoom="18" tile_size="256" img_density="32" avg_img_size="18000" ellipsoid="true"/>
<tile_source rule="yandex_traffic" name="Yandex Traffic RU"/>
<tile_source rule="microsoft" name="Microsoft Maps" map_type="r" map_ext="png" ext=".png" min_zoom="1" max_zoom="19" tile_size="256" img_density="16" avg_img_size="18000"/>
<tile_source rule="microsoft" name="Microsoft Hybrid" map_type="h" map_ext="jpg" ext=".jpg" min_zoom="1" max_zoom="19" tile_size="256" img_density="32" avg_img_size="18000"/>
<tile_source rule="microsoft" name="Microsoft Earth" map_type="a" map_ext="jpg" ext=".jpg" min_zoom="1" max_zoom="19" tile_size="256" img_density="32" avg_img_size="18000"/>
<tile_source name="OpenFietskaart (NL)" url_template="http://overlay.openstreetmap.nl/openfietskaart-overlay/{0}/{1}/{2}.png" ext=".png" min_zoom="7" max_zoom="18" tile_size="256" img_density="16" avg_img_size="18000"/>
<tile_source name="OpenFietskaartBaseLayer (NL)" url_template="http://overlay.openstreetmap.nl/basemap/{0}/{1}/{2}.png" ext=".png" min_zoom="1" max_zoom="18" tile_size="256" img_density="16" avg_img_size="18000"/>
<tile_source name="OpenFietskaartRoads (NL)" url_template="http://overlay.openstreetmap.nl/roads/{0}/{1}/{2}.png" ext=".png" min_zoom="7" max_zoom="18" tile_size="256" img_density="16" avg_img_size="18000"/>
<tile_source name="Wanderreitkarte Topo (DE, NL)" url_template="http://www.wanderreitkarte.de/topo/{0}/{1}/{2}.png" ext=".png" min_zoom="1" max_zoom="18" tile_size="256" img_density="16" avg_img_size="18000"/>
<tile_source name="Wanderreitkarte HillShade (DE, NL)" url_template="http://www.wanderreitkarte.de/hills/{0}/{1}/{2}.png" ext=".png" min_zoom="8" max_zoom="18" tile_size="256" img_density="16" avg_img_size="18000"/>
<tile_source name="Wanderreitkarte BaseLayer (DE, NL)" url_template="http://www.wanderreitkarte.de/base/{0}/{1}/{2}.png" ext=".png" min_zoom="1" max_zoom="18" tile_size="256" img_density="16" avg_img_size="18000"/>
<!--
<tile_source rule="wms_tile" url_template="http://wms.latlon.org" name="Genshtab (BLR)" layer="gshtab" ext=".jpg" min_zoom="5" max_zoom="17" tile_size="256" img_density="32" avg_img_size="18000"/> NOT WORK ?-->