001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.preferences.imagery; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.Color; 007import java.awt.GridBagLayout; 008import java.awt.event.ActionEvent; 009import java.awt.event.ActionListener; 010import java.io.File; 011import java.io.FilenameFilter; 012 013import javax.swing.JButton; 014import javax.swing.JColorChooser; 015import javax.swing.JLabel; 016import javax.swing.JOptionPane; 017import javax.swing.JPanel; 018import javax.swing.JSlider; 019import javax.swing.JSpinner; 020import javax.swing.SpinnerNumberModel; 021 022import org.openstreetmap.josm.data.cache.JCSCacheManager; 023import org.openstreetmap.josm.data.imagery.CachedTileLoaderFactory; 024import org.openstreetmap.josm.gui.layer.AbstractCachedTileSourceLayer; 025import org.openstreetmap.josm.gui.layer.AbstractTileSourceLayer; 026import org.openstreetmap.josm.gui.layer.ImageryLayer; 027import org.openstreetmap.josm.gui.widgets.JosmComboBox; 028import org.openstreetmap.josm.gui.widgets.JosmTextField; 029import org.openstreetmap.josm.tools.ColorHelper; 030import org.openstreetmap.josm.tools.GBC; 031import org.openstreetmap.josm.tools.Utils; 032 033/** 034 * {@code JPanel} giving access to common imagery settings. 035 * @since 5465 036 */ 037public class CommonSettingsPanel extends JPanel { 038 039 // Common Settings 040 private final JButton btnFadeColor; 041 private final JSlider fadeAmount = new JSlider(0, 100); 042 private final JosmComboBox<String> sharpen; 043 private final JosmTextField tilecacheDir = new JosmTextField(); 044 private final JSpinner maxElementsOnDisk; 045 private final JSlider tilesZoom = new JSlider(-2, 2, 0); 046 047 048 /** 049 * Constructs a new {@code CommonSettingsPanel}. 050 */ 051 public CommonSettingsPanel() { 052 super(new GridBagLayout()); 053 054 this.maxElementsOnDisk = new JSpinner(new SpinnerNumberModel( 055 AbstractCachedTileSourceLayer.MAX_DISK_CACHE_SIZE.get().intValue(), 0, Integer.MAX_VALUE, 1)); 056 057 058 this.btnFadeColor = new JButton(); 059 060 this.btnFadeColor.addActionListener(new ActionListener() { 061 @Override 062 public void actionPerformed(ActionEvent e) { 063 JColorChooser chooser = new JColorChooser(btnFadeColor.getBackground()); 064 int answer = JOptionPane.showConfirmDialog( 065 CommonSettingsPanel.this, chooser, 066 tr("Choose a color for {0}", tr("imagery fade")), 067 JOptionPane.OK_CANCEL_OPTION, 068 JOptionPane.PLAIN_MESSAGE); 069 if (answer == JOptionPane.OK_OPTION) { 070 Color colFadeColor = chooser.getColor(); 071 btnFadeColor.setBackground(colFadeColor); 072 btnFadeColor.setText(ColorHelper.color2html(colFadeColor)); 073 } 074 } 075 }); 076 077 add(new JLabel(tr("Fade Color: ")), GBC.std()); 078 add(GBC.glue(5, 0), GBC.std().fill(GBC.HORIZONTAL)); 079 add(this.btnFadeColor, GBC.eol().fill(GBC.HORIZONTAL)); 080 081 add(new JLabel(tr("Fade amount: ")), GBC.std()); 082 add(GBC.glue(5, 0), GBC.std().fill(GBC.HORIZONTAL)); 083 add(this.fadeAmount, GBC.eol().fill(GBC.HORIZONTAL)); 084 085 this.sharpen = new JosmComboBox<>(new String[] { 086 tr("None"), 087 tr("Soft"), 088 tr("Strong")}); 089 add(new JLabel(tr("Sharpen (requires layer re-add): "))); 090 add(GBC.glue(5, 0), GBC.std().fill(GBC.HORIZONTAL)); 091 add(this.sharpen, GBC.eol().fill(GBC.HORIZONTAL)); 092 093 add(new JLabel(tr("Tile cache directory: ")), GBC.std()); 094 add(GBC.glue(5, 0), GBC.std()); 095 add(tilecacheDir, GBC.eol().fill(GBC.HORIZONTAL)); 096 097 add(new JLabel(tr("Maximum size of disk cache (per imagery) in MB: ")), GBC.std()); 098 add(GBC.glue(5, 0), GBC.std()); 099 add(this.maxElementsOnDisk, GBC.eol()); 100 101 this.tilesZoom.setPaintLabels(true); 102 this.tilesZoom.setMajorTickSpacing(2); 103 this.tilesZoom.setMinorTickSpacing(1); 104 this.tilesZoom.setPaintTicks(true); 105 add(new JLabel(tr("Tiles zoom offset:"))); 106 add(GBC.glue(5, 0), GBC.std()); 107 add(this.tilesZoom, GBC.eol()); 108 } 109 110 /** 111 * Loads the common settings. 112 */ 113 public void loadSettings() { 114 Color colFadeColor = ImageryLayer.PROP_FADE_COLOR.get(); 115 this.btnFadeColor.setBackground(colFadeColor); 116 this.btnFadeColor.setText(ColorHelper.color2html(colFadeColor)); 117 this.fadeAmount.setValue(ImageryLayer.PROP_FADE_AMOUNT.get()); 118 this.sharpen.setSelectedIndex(Math.max(0, Math.min(2, ImageryLayer.PROP_SHARPEN_LEVEL.get()))); 119 this.tilecacheDir.setText(CachedTileLoaderFactory.PROP_TILECACHE_DIR.get()); 120 this.maxElementsOnDisk.setValue(AbstractCachedTileSourceLayer.MAX_DISK_CACHE_SIZE.get()); 121 this.tilesZoom.setValue(AbstractTileSourceLayer.ZOOM_OFFSET.get()); 122 } 123 124 /** 125 * Saves the common settings. 126 * @return true when restart is required 127 */ 128 public boolean saveSettings() { 129 ImageryLayer.PROP_FADE_AMOUNT.put(this.fadeAmount.getValue()); 130 ImageryLayer.PROP_FADE_COLOR.put(this.btnFadeColor.getBackground()); 131 ImageryLayer.PROP_SHARPEN_LEVEL.put(sharpen.getSelectedIndex()); 132 133 boolean restartRequired = false; 134 if (!AbstractCachedTileSourceLayer.MAX_DISK_CACHE_SIZE.get().equals(this.maxElementsOnDisk.getValue())) { 135 if (((Integer) this.maxElementsOnDisk.getValue()) < AbstractCachedTileSourceLayer.MAX_DISK_CACHE_SIZE.get() && 136 JCSCacheManager.USE_BLOCK_CACHE.get()) { 137 // reducing size of the cache, this requires deletion of the files 138 removeCacheFiles(CachedTileLoaderFactory.PROP_TILECACHE_DIR.get()); 139 } 140 AbstractCachedTileSourceLayer.MAX_DISK_CACHE_SIZE.put((Integer) this.maxElementsOnDisk.getValue()); 141 restartRequired = true; 142 } 143 144 145 if (!CachedTileLoaderFactory.PROP_TILECACHE_DIR.get().equals(this.tilecacheDir.getText())) { 146 restartRequired = true; 147 removeCacheFiles(CachedTileLoaderFactory.PROP_TILECACHE_DIR.get()); // clear old cache directory 148 CachedTileLoaderFactory.PROP_TILECACHE_DIR.put(this.tilecacheDir.getText()); 149 } 150 151 if (!AbstractTileSourceLayer.ZOOM_OFFSET.get().equals(this.tilesZoom.getValue())) { 152 // TODO: make warning about too small MEMORY_CACHE_SIZE? 153 AbstractTileSourceLayer.ZOOM_OFFSET.put(this.tilesZoom.getValue()); 154 restartRequired = true; 155 } 156 return restartRequired; 157 } 158 159 private void removeCacheFiles(String path) { 160 File directory = new File(path); 161 File[] cacheFiles = directory.listFiles(new FilenameFilter() { 162 @Override 163 public boolean accept(File dir, String name) { 164 return name.endsWith(".data") || name.endsWith(".key"); 165 } 166 167 }); 168 JCSCacheManager.shutdown(); // shutdown Cache - so files can by safely deleted 169 for (File cacheFile: cacheFiles) { 170 Utils.deleteFile(cacheFile); 171 } 172 } 173}