source: josm/trunk/src/org/openstreetmap/josm/gui/ImageryMenu.java@ 10063

Last change on this file since 10063 was 9261, checked in by stoecker, 8 years ago

I18n cleanup

  • Property svn:eol-style set to native
File size: 10.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5import static org.openstreetmap.josm.tools.I18n.trc;
6
7import java.awt.Component;
8import java.awt.GraphicsEnvironment;
9import java.awt.MenuComponent;
10import java.awt.event.ActionEvent;
11import java.util.ArrayList;
12import java.util.Collection;
13import java.util.Collections;
14import java.util.Comparator;
15import java.util.Iterator;
16import java.util.List;
17import java.util.Locale;
18
19import javax.swing.Action;
20import javax.swing.JComponent;
21import javax.swing.JMenu;
22import javax.swing.JMenuItem;
23import javax.swing.JPopupMenu;
24import javax.swing.event.MenuEvent;
25import javax.swing.event.MenuListener;
26
27import org.openstreetmap.josm.Main;
28import org.openstreetmap.josm.actions.AddImageryLayerAction;
29import org.openstreetmap.josm.actions.JosmAction;
30import org.openstreetmap.josm.actions.MapRectifierWMSmenuAction;
31import org.openstreetmap.josm.data.coor.LatLon;
32import org.openstreetmap.josm.data.imagery.ImageryInfo;
33import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
34import org.openstreetmap.josm.data.imagery.Shape;
35import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
36import org.openstreetmap.josm.gui.layer.ImageryLayer;
37import org.openstreetmap.josm.gui.layer.Layer;
38import org.openstreetmap.josm.gui.preferences.imagery.ImageryPreference;
39import org.openstreetmap.josm.tools.ImageProvider;
40
41/**
42 * Imagery menu, holding entries for imagery preferences, offset actions and dynamic imagery entries
43 * depending on current maview coordinates.
44 * @since 3737
45 */
46public class ImageryMenu extends JMenu implements LayerChangeListener {
47
48 /**
49 * Compare ImageryInfo objects alphabetically by name.
50 *
51 * ImageryInfo objects are normally sorted by country code first
52 * (for the preferences). We don't want this in the imagery menu.
53 */
54 public static final Comparator<ImageryInfo> alphabeticImageryComparator = new Comparator<ImageryInfo>() {
55 @Override
56 public int compare(ImageryInfo ii1, ImageryInfo ii2) {
57 return ii1.getName().toLowerCase(Locale.ENGLISH).compareTo(ii2.getName().toLowerCase(Locale.ENGLISH));
58 }
59 };
60
61 private final transient Action offsetAction = new JosmAction(
62 tr("Imagery offset"), "mapmode/adjustimg", tr("Adjust imagery offset"), null, false, false) {
63 {
64 putValue("toolbar", "imagery-offset");
65 Main.toolbar.register(this);
66 }
67
68 @Override
69 public void actionPerformed(ActionEvent e) {
70 Collection<ImageryLayer> layers = Main.map.mapView.getLayersOfType(ImageryLayer.class);
71 if (layers.isEmpty()) {
72 setEnabled(false);
73 return;
74 }
75 Component source = null;
76 if (e.getSource() instanceof Component) {
77 source = (Component) e.getSource();
78 }
79 JPopupMenu popup = new JPopupMenu();
80 if (layers.size() == 1) {
81 JComponent c = layers.iterator().next().getOffsetMenuItem(popup);
82 if (c instanceof JMenuItem) {
83 ((JMenuItem) c).getAction().actionPerformed(e);
84 } else {
85 if (source == null) return;
86 popup.show(source, source.getWidth()/2, source.getHeight()/2);
87 }
88 return;
89 }
90 if (source == null) return;
91 for (ImageryLayer layer : layers) {
92 JMenuItem layerMenu = layer.getOffsetMenuItem();
93 layerMenu.setText(layer.getName());
94 layerMenu.setIcon(layer.getIcon());
95 popup.add(layerMenu);
96 }
97 popup.show(source, source.getWidth()/2, source.getHeight()/2);
98 }
99 };
100
101 private final JMenuItem singleOffset = new JMenuItem(offsetAction);
102 private JMenuItem offsetMenuItem = singleOffset;
103 private final MapRectifierWMSmenuAction rectaction = new MapRectifierWMSmenuAction();
104
105 /**
106 * Constructs a new {@code ImageryMenu}.
107 * @param subMenu submenu in that contains plugin-managed additional imagery layers
108 */
109 public ImageryMenu(JMenu subMenu) {
110 /* I18N: mnemonic: I */
111 super(trc("menu", "Imagery"));
112 setupMenuScroller();
113 MapView.addLayerChangeListener(this);
114 // build dynamically
115 addMenuListener(new MenuListener() {
116 @Override
117 public void menuSelected(MenuEvent e) {
118 refreshImageryMenu();
119 }
120
121 @Override
122 public void menuDeselected(MenuEvent e) {
123 }
124
125 @Override
126 public void menuCanceled(MenuEvent e) {
127 }
128 });
129 MainMenu.add(subMenu, rectaction);
130 }
131
132 private void setupMenuScroller() {
133 if (!GraphicsEnvironment.isHeadless()) {
134 MenuScroller.setScrollerFor(this, 150, 2);
135 }
136 }
137
138 /**
139 * Refresh imagery menu.
140 *
141 * Outside this class only called in {@link ImageryPreference#initialize()}.
142 * (In order to have actions ready for the toolbar, see #8446.)
143 */
144 public void refreshImageryMenu() {
145 removeDynamicItems();
146
147 addDynamic(offsetMenuItem);
148 addDynamicSeparator();
149
150 // for each configured ImageryInfo, add a menu entry.
151 final List<ImageryInfo> savedLayers = new ArrayList<>(ImageryLayerInfo.instance.getLayers());
152 Collections.sort(savedLayers, alphabeticImageryComparator);
153 for (final ImageryInfo u : savedLayers) {
154 addDynamic(new AddImageryLayerAction(u));
155 }
156
157 // list all imagery entries where the current map location
158 // is within the imagery bounds
159 if (Main.isDisplayingMapView()) {
160 MapView mv = Main.map.mapView;
161 LatLon pos = mv.getProjection().eastNorth2latlon(mv.getCenter());
162 final List<ImageryInfo> inViewLayers = new ArrayList<>();
163
164 for (ImageryInfo i : ImageryLayerInfo.instance.getDefaultLayers()) {
165 if (i.getBounds() != null && i.getBounds().contains(pos)) {
166 inViewLayers.add(i);
167 }
168 }
169 // Do not suggest layers already in use
170 inViewLayers.removeAll(ImageryLayerInfo.instance.getLayers());
171 // For layers containing complex shapes, check that center is in one
172 // of its shapes (fix #7910)
173 for (Iterator<ImageryInfo> iti = inViewLayers.iterator(); iti.hasNext();) {
174 List<Shape> shapes = iti.next().getBounds().getShapes();
175 if (shapes != null && !shapes.isEmpty()) {
176 boolean found = false;
177 for (Iterator<Shape> its = shapes.iterator(); its.hasNext() && !found;) {
178 found = its.next().contains(pos);
179 }
180 if (!found) {
181 iti.remove();
182 }
183 }
184 }
185 if (!inViewLayers.isEmpty()) {
186 Collections.sort(inViewLayers, alphabeticImageryComparator);
187 addDynamicSeparator();
188 for (ImageryInfo i : inViewLayers) {
189 addDynamic(new AddImageryLayerAction(i));
190 }
191 }
192 }
193
194 addDynamicSeparator();
195 JMenu subMenu = Main.main.menu.imagerySubMenu;
196 int heightUnrolled = 30*(getItemCount()+subMenu.getItemCount());
197 if (heightUnrolled < Main.panel.getHeight()) {
198 // add all items of submenu if they will fit on screen
199 int n = subMenu.getItemCount();
200 for (int i = 0; i < n; i++) {
201 addDynamic(subMenu.getItem(i).getAction());
202 }
203 } else {
204 // or add the submenu itself
205 addDynamic(subMenu);
206 }
207 }
208
209 private JMenuItem getNewOffsetMenu() {
210 if (!Main.isDisplayingMapView()) {
211 offsetAction.setEnabled(false);
212 return singleOffset;
213 }
214 Collection<ImageryLayer> layers = Main.map.mapView.getLayersOfType(ImageryLayer.class);
215 if (layers.isEmpty()) {
216 offsetAction.setEnabled(false);
217 return singleOffset;
218 }
219 offsetAction.setEnabled(true);
220 JMenu newMenu = new JMenu(trc("layer", "Offset"));
221 newMenu.setIcon(ImageProvider.get("mapmode", "adjustimg"));
222 newMenu.setAction(offsetAction);
223 if (layers.size() == 1)
224 return (JMenuItem) layers.iterator().next().getOffsetMenuItem(newMenu);
225 for (ImageryLayer layer : layers) {
226 JMenuItem layerMenu = layer.getOffsetMenuItem();
227 layerMenu.setText(layer.getName());
228 layerMenu.setIcon(layer.getIcon());
229 newMenu.add(layerMenu);
230 }
231 return newMenu;
232 }
233
234 public void refreshOffsetMenu() {
235 offsetMenuItem = getNewOffsetMenu();
236 }
237
238 @Override
239 public void activeLayerChange(Layer oldLayer, Layer newLayer) {
240 }
241
242 @Override
243 public void layerAdded(Layer newLayer) {
244 if (newLayer instanceof ImageryLayer) {
245 refreshOffsetMenu();
246 }
247 }
248
249 @Override
250 public void layerRemoved(Layer oldLayer) {
251 if (oldLayer instanceof ImageryLayer) {
252 refreshOffsetMenu();
253 }
254 }
255
256 /**
257 * Collection to store temporary menu items. They will be deleted
258 * (and possibly recreated) when refreshImageryMenu() is called.
259 * @since 5803
260 */
261 private final List<Object> dynamicItems = new ArrayList<>(20);
262
263 /**
264 * Remove all the items in @field dynamicItems collection
265 * @since 5803
266 */
267 private void removeDynamicItems() {
268 for (Object item : dynamicItems) {
269 if (item instanceof JMenuItem) {
270 remove((JMenuItem) item);
271 }
272 if (item instanceof MenuComponent) {
273 remove((MenuComponent) item);
274 }
275 if (item instanceof Component) {
276 remove((Component) item);
277 }
278 }
279 dynamicItems.clear();
280 }
281
282 private void addDynamicSeparator() {
283 JPopupMenu.Separator s = new JPopupMenu.Separator();
284 dynamicItems.add(s);
285 add(s);
286 }
287
288 private void addDynamic(Action a) {
289 dynamicItems.add(this.add(a));
290 }
291
292 private void addDynamic(JMenuItem it) {
293 dynamicItems.add(this.add(it));
294 }
295}
Note: See TracBrowser for help on using the repository browser.