001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.bbox; 003 004import java.awt.Color; 005import java.awt.Dimension; 006import java.awt.Font; 007import java.awt.FontMetrics; 008import java.awt.Graphics; 009import java.awt.Graphics2D; 010import java.awt.Point; 011import java.awt.RenderingHints; 012import java.awt.event.MouseAdapter; 013import java.awt.event.MouseEvent; 014import java.awt.event.MouseListener; 015import java.util.Collection; 016 017import javax.swing.ImageIcon; 018import javax.swing.JComponent; 019 020import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; 021import org.openstreetmap.josm.tools.CheckParameterUtil; 022import org.openstreetmap.josm.tools.ImageProvider; 023 024public class SourceButton extends JComponent { 025 026 private static final int LAYER_HEIGHT = 20; 027 private static final int LEFT_PADDING = 5; 028 private static final int TOP_PADDING = 5; 029 private static final int BOTTOM_PADDING = 5; 030 031 private transient TileSource[] sources; 032 033 private final ImageIcon enlargeImage; 034 private final ImageIcon shrinkImage; 035 private final Dimension hiddenDimension; 036 037 // Calculated after component is added to container 038 private int barWidth; 039 private Dimension shownDimension; 040 private Font font; 041 042 private boolean isEnlarged; 043 044 private int currentMap; 045 private final SlippyMapBBoxChooser slippyMapBBoxChooser; 046 047 public SourceButton(SlippyMapBBoxChooser slippyMapBBoxChooser, Collection<TileSource> sources) { 048 this.slippyMapBBoxChooser = slippyMapBBoxChooser; 049 setSources(sources); 050 enlargeImage = ImageProvider.get("layer-switcher-maximize"); 051 shrinkImage = ImageProvider.get("layer-switcher-minimize"); 052 053 hiddenDimension = new Dimension(enlargeImage.getIconWidth(), enlargeImage.getIconHeight()); 054 setPreferredSize(hiddenDimension); 055 056 addMouseListener(mouseListener); 057 } 058 059 private final transient MouseListener mouseListener = new MouseAdapter() { 060 @Override 061 public void mouseReleased(MouseEvent e) { 062 if (e.getButton() == MouseEvent.BUTTON1) { 063 Point point = e.getPoint(); 064 if (isEnlarged) { 065 if (barWidth < point.x && point.y < shrinkImage.getIconHeight()) { 066 toggle(); 067 } else { 068 int result = (point.y - 5) / LAYER_HEIGHT; 069 if (result >= 0 && result < SourceButton.this.sources.length) { 070 SourceButton.this.slippyMapBBoxChooser.toggleMapSource(SourceButton.this.sources[result]); 071 currentMap = result; 072 toggle(); 073 } 074 } 075 } else { 076 toggle(); 077 } 078 } 079 } 080 }; 081 082 /** 083 * Set the tile sources. 084 * @param sources The tile sources to display 085 * @since 6364 086 */ 087 public final void setSources(Collection<TileSource> sources) { 088 CheckParameterUtil.ensureParameterNotNull(sources, "sources"); 089 this.sources = sources.toArray(new TileSource[sources.size()]); 090 shownDimension = null; 091 } 092 093 @Override 094 protected void paintComponent(Graphics graphics) { 095 Graphics2D g = (Graphics2D) graphics.create(); 096 try { 097 calculateShownDimension(); 098 g.setFont(font); 099 if (isEnlarged) { 100 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 101 int radioButtonSize = 10; 102 103 g.setColor(new Color(0, 0, 139, 179)); 104 g.fillRoundRect(0, 0, barWidth + shrinkImage.getIconWidth(), 105 sources.length * LAYER_HEIGHT + TOP_PADDING + BOTTOM_PADDING, 10, 10); 106 for (int i = 0; i < sources.length; i++) { 107 g.setColor(Color.WHITE); 108 g.fillOval(LEFT_PADDING, TOP_PADDING + i * LAYER_HEIGHT + 6, radioButtonSize, radioButtonSize); 109 g.drawString(sources[i].getName(), LEFT_PADDING + radioButtonSize + LEFT_PADDING, 110 TOP_PADDING + i * LAYER_HEIGHT + g.getFontMetrics().getHeight()); 111 if (currentMap == i) { 112 g.setColor(Color.BLACK); 113 g.fillOval(LEFT_PADDING + 1, TOP_PADDING + 7 + i * LAYER_HEIGHT, radioButtonSize - 2, radioButtonSize - 2); 114 } 115 } 116 117 g.drawImage(shrinkImage.getImage(), barWidth, 0, null); 118 } else { 119 g.drawImage(enlargeImage.getImage(), 0, 0, null); 120 } 121 } finally { 122 g.dispose(); 123 } 124 } 125 126 public void toggle() { 127 this.isEnlarged = !this.isEnlarged; 128 calculateShownDimension(); 129 setPreferredSize(isEnlarged ? shownDimension : hiddenDimension); 130 revalidate(); 131 } 132 133 public void setCurrentMap(TileSource tileSource) { 134 for (int i = 0; i < sources.length; i++) { 135 if (sources[i].equals(tileSource)) { 136 currentMap = i; 137 return; 138 } 139 } 140 currentMap = 0; 141 } 142 143 private void calculateShownDimension() { 144 if (shownDimension == null) { 145 font = getFont().deriveFont(Font.BOLD).deriveFont(15.0f); 146 int textWidth = 0; 147 FontMetrics fm = getFontMetrics(font); 148 for (TileSource source: sources) { 149 int width = fm.stringWidth(source.getName()); 150 if (width > textWidth) { 151 textWidth = width; 152 } 153 } 154 barWidth = textWidth + 50; 155 shownDimension = new Dimension(barWidth + shrinkImage.getIconWidth(), sources.length * LAYER_HEIGHT + TOP_PADDING + BOTTOM_PADDING); 156 } 157 } 158}