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

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

Checkstyle 6.19: enable SingleSpaceSeparator and fix violations

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