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

Last change on this file since 10755 was 10619, checked in by Don-vip, 8 years ago

see #11390 - Java 8: use List.sort(Comparator) instead of Collections.sort(list, Comparator)

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