source: josm/trunk/test/unit/org/openstreetmap/josm/gui/dialogs/MinimapDialogTest.java@ 14624

Last change on this file since 14624 was 14624, checked in by Don-vip, 5 years ago

fix various SonarQube issues

  • Property svn:eol-style set to native
File size: 36.2 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.dialogs;
3
4import static java.util.concurrent.TimeUnit.MILLISECONDS;
5import static org.junit.Assert.assertArrayEquals;
6import static org.junit.Assert.assertEquals;
7import static org.junit.Assert.assertFalse;
8import static org.junit.Assert.assertTrue;
9import static org.junit.Assert.fail;
10import static org.openstreetmap.josm.tools.I18n.tr;
11
12import java.awt.Color;
13import java.awt.Component;
14import java.awt.Graphics2D;
15import java.awt.event.ComponentEvent;
16import java.awt.image.BufferedImage;
17import java.util.ArrayList;
18import java.util.Arrays;
19import java.util.Map;
20import java.util.Objects;
21import java.util.concurrent.Callable;
22import java.util.regex.Matcher;
23
24import javax.swing.JCheckBoxMenuItem;
25import javax.swing.JMenuItem;
26import javax.swing.JPopupMenu;
27
28import org.awaitility.Awaitility;
29import org.junit.Rule;
30import org.junit.Test;
31import org.openstreetmap.josm.TestUtils;
32import org.openstreetmap.josm.data.Bounds;
33import org.openstreetmap.josm.data.DataSource;
34import org.openstreetmap.josm.data.imagery.ImageryInfo;
35import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
36import org.openstreetmap.josm.data.osm.DataSet;
37import org.openstreetmap.josm.data.projection.ProjectionRegistry;
38import org.openstreetmap.josm.data.projection.Projections;
39import org.openstreetmap.josm.gui.MainApplication;
40import org.openstreetmap.josm.gui.MapView;
41import org.openstreetmap.josm.gui.bbox.SlippyMapBBoxChooser;
42import org.openstreetmap.josm.gui.bbox.SourceButton;
43import org.openstreetmap.josm.gui.layer.ImageryLayer;
44import org.openstreetmap.josm.gui.layer.LayerManagerTest.TestLayer;
45import org.openstreetmap.josm.gui.layer.OsmDataLayer;
46import org.openstreetmap.josm.gui.util.GuiHelper;
47import org.openstreetmap.josm.spi.preferences.Config;
48import org.openstreetmap.josm.testutils.ImagePatternMatching;
49import org.openstreetmap.josm.testutils.JOSMTestRules;
50
51import com.google.common.collect.ImmutableMap;
52
53import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
54
55/**
56 * Unit tests of {@link MinimapDialog} class.
57 */
58public class MinimapDialogTest {
59
60 /**
61 * Setup tests
62 */
63 @Rule
64 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
65 public JOSMTestRules josmTestRules = new JOSMTestRules().main().projection().fakeImagery();
66
67 /**
68 * Unit test of {@link MinimapDialog} class.
69 */
70 @Test
71 public void testMinimapDialog() {
72 MinimapDialog dlg = new MinimapDialog();
73 dlg.showDialog();
74 assertTrue(dlg.isVisible());
75 dlg.hideDialog();
76 assertFalse(dlg.isVisible());
77 }
78
79 @FunctionalInterface
80 protected interface ThrowingRunnable {
81 void run() throws Throwable;
82 }
83
84 protected static Runnable uncheckExceptions(final ThrowingRunnable tr) {
85 return (() -> {
86 try {
87 tr.run();
88 } catch (Throwable e) {
89 throw new RuntimeException(e);
90 }
91 });
92 }
93
94 protected void assertSingleSelectedSourceLabel(final String label) {
95 JPopupMenu menu = this.sourceButton.getPopupMenu();
96 boolean found = false;
97 for (Component c: menu.getComponents()) {
98 if (JPopupMenu.Separator.class.isInstance(c)) {
99 break;
100 } else {
101 boolean equalText = ((JMenuItem) c).getText().equals(label);
102 boolean isSelected = ((JMenuItem) c).isSelected();
103 assertEquals(equalText, isSelected);
104 if (equalText) {
105 assertFalse("Second selected source found", found);
106 found = true;
107 }
108 }
109 }
110 assertTrue("Selected source not found in menu", found);
111 }
112
113 protected void clickSourceMenuItemByLabel(final String label) {
114 try {
115 GuiHelper.runInEDTAndWaitWithException(() -> {
116 JPopupMenu menu = this.sourceButton.getPopupMenu();
117 for (Component c: menu.getComponents()) {
118 if (JPopupMenu.Separator.class.isInstance(c)) {
119 // sources should all come before any separators
120 break;
121 } else if (Objects.equals(((JMenuItem) c).getText(), label)) {
122 ((JMenuItem) c).doClick();
123 return;
124 }
125 // else continue...
126 }
127 fail();
128 });
129 } catch (Throwable e) {
130 throw new RuntimeException(String.format("Failed to find menu item with label %s: %s", label, e), e);
131 }
132 }
133
134 protected void assertSourceLabelsVisible(final String... labels) {
135 GuiHelper.runInEDTAndWaitWithException(() -> {
136 final ArrayList<String> menuLabels = new ArrayList<>();
137 final JPopupMenu menu = this.sourceButton.getPopupMenu();
138 for (Component c: menu.getComponents()) {
139 if (c instanceof JPopupMenu.Separator) {
140 break;
141 }
142 menuLabels.add(((JMenuItem) c).getText());
143 }
144
145 assertArrayEquals(
146 labels,
147 menuLabels.toArray()
148 );
149 });
150 }
151
152 private MinimapDialog minimap;
153 private SlippyMapBBoxChooser slippyMap;
154 private SourceButton sourceButton;
155 private Callable<Boolean> slippyMapTasksFinished;
156
157 private static BufferedImage paintedSlippyMap;
158
159 protected void setUpMiniMap() {
160 GuiHelper.runInEDTAndWaitWithException(uncheckExceptions(() -> {
161 this.minimap = new MinimapDialog();
162 this.minimap.setSize(300, 200);
163 this.minimap.showDialog();
164 this.slippyMap = (SlippyMapBBoxChooser) TestUtils.getPrivateField(this.minimap, "slippyMap");
165 this.sourceButton = (SourceButton) TestUtils.getPrivateField(this.slippyMap, "iSourceButton");
166
167 // get minimap in a paintable state
168 this.minimap.addNotify();
169 this.minimap.doLayout();
170 }));
171
172 this.slippyMapTasksFinished = () -> !this.slippyMap.getTileController().getTileLoader().hasOutstandingTasks();
173 }
174
175 protected void paintSlippyMap() {
176 if (paintedSlippyMap == null ||
177 paintedSlippyMap.getWidth() != this.slippyMap.getSize().width ||
178 paintedSlippyMap.getHeight() != this.slippyMap.getSize().height) {
179 paintedSlippyMap = new BufferedImage(
180 this.slippyMap.getSize().width,
181 this.slippyMap.getSize().height,
182 BufferedImage.TYPE_INT_RGB
183 );
184 } // else reuse existing one - allocation is expensive
185
186 // clear background to a recognizably "wrong" color & dispose our Graphics2D so we don't risk carrying over
187 // any state
188 Graphics2D g = paintedSlippyMap.createGraphics();
189 g.setBackground(Color.BLUE);
190 g.clearRect(0, 0, paintedSlippyMap.getWidth(), paintedSlippyMap.getHeight());
191 g.dispose();
192
193 g = paintedSlippyMap.createGraphics();
194 this.slippyMap.paintAll(g);
195 }
196
197 /**
198 * Tests to switch imagery source.
199 * @throws Exception if any error occurs
200 */
201 @Test
202 public void testSourceSwitching() throws Exception {
203 // relevant prefs starting out empty, should choose the first source and have shown download area enabled
204 // (not that there's a data layer for it to use)
205
206 this.setUpMiniMap();
207
208 // an initial paint operation is required to trigger the tile fetches
209 this.paintSlippyMap();
210
211 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
212
213 this.paintSlippyMap();
214
215 assertEquals(0xffffffff, paintedSlippyMap.getRGB(0, 0));
216
217 this.assertSingleSelectedSourceLabel("White Tiles");
218
219 this.clickSourceMenuItemByLabel("Magenta Tiles");
220 this.assertSingleSelectedSourceLabel("Magenta Tiles");
221 // call paint to trigger new tile fetch
222 this.paintSlippyMap();
223
224 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
225
226 this.paintSlippyMap();
227
228 assertEquals(0xffff00ff, paintedSlippyMap.getRGB(0, 0));
229
230 this.clickSourceMenuItemByLabel("Green Tiles");
231 this.assertSingleSelectedSourceLabel("Green Tiles");
232 // call paint to trigger new tile fetch
233 this.paintSlippyMap();
234
235 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
236
237 this.paintSlippyMap();
238
239 assertEquals(0xff00ff00, paintedSlippyMap.getRGB(0, 0));
240
241 assertEquals("Green Tiles", Config.getPref().get("slippy_map_chooser.mapstyle", "Fail"));
242 }
243
244 /**
245 * Tests that the apparently-selected TileSource survives the tile sources being refreshed.
246 * @throws Exception if any error occurs
247 */
248 @Test
249 public void testRefreshSourcesRetainsSelection() throws Exception {
250 // relevant prefs starting out empty, should choose the first source and have shown download area enabled
251 // (not that there's a data layer for it to use)
252
253 this.setUpMiniMap();
254
255 this.clickSourceMenuItemByLabel("Magenta Tiles");
256 this.assertSingleSelectedSourceLabel("Magenta Tiles");
257
258 // call paint to trigger new tile fetch
259 this.paintSlippyMap();
260
261 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
262
263 this.paintSlippyMap();
264
265 assertEquals(0xffff00ff, paintedSlippyMap.getRGB(0, 0));
266
267 this.slippyMap.refreshTileSources();
268
269 this.assertSingleSelectedSourceLabel("Magenta Tiles");
270
271 // call paint to trigger new tile fetch
272 this.paintSlippyMap();
273
274 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
275
276 this.paintSlippyMap();
277
278 assertEquals(0xffff00ff, paintedSlippyMap.getRGB(0, 0));
279 }
280
281 /**
282 * Tests that the currently selected source being removed from ImageryLayerInfo will remain present and
283 * selected in the source menu even after the tile sources have been refreshed.
284 * @throws Exception if any error occurs
285 */
286 @Test
287 public void testRemovedSourceStillSelected() throws Exception {
288 // relevant prefs starting out empty, should choose the first source and have shown download area enabled
289 // (not that there's a data layer for it to use)
290
291 this.setUpMiniMap();
292
293 this.clickSourceMenuItemByLabel("Green Tiles");
294
295 ImageryLayerInfo.instance.remove(
296 ImageryLayerInfo.instance.getLayers().stream().filter(i -> i.getName().equals("Green Tiles")).findAny().get()
297 );
298
299 this.assertSingleSelectedSourceLabel("Green Tiles");
300
301 this.slippyMap.refreshTileSources();
302
303 this.assertSingleSelectedSourceLabel("Green Tiles");
304
305 // call paint to trigger new tile fetch
306 this.paintSlippyMap();
307
308 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
309
310 this.paintSlippyMap();
311
312 assertEquals(0xff00ff00, paintedSlippyMap.getRGB(0, 0));
313 }
314
315 /**
316 * Tests the tile source list includes sources only present in the LayerManager
317 * @throws Exception if any error occurs
318 */
319 @Test
320 public void testTileSourcesFromCurrentLayers() throws Exception {
321 // relevant prefs starting out empty, should choose the first (ImageryLayerInfo) source and have shown download area enabled
322 // (not that there's a data layer for it to use)
323
324 final ImageryInfo magentaTilesInfo = ImageryLayerInfo.instance.getLayers().stream().filter(
325 i -> i.getName().equals("Magenta Tiles")
326 ).findAny().get();
327 final ImageryInfo blackTilesInfo = ImageryLayerInfo.instance.getLayers().stream().filter(
328 i -> i.getName().equals("Black Tiles")
329 ).findAny().get();
330
331 // first we will remove "Magenta Tiles" from ImageryLayerInfo
332 ImageryLayerInfo.instance.remove(magentaTilesInfo);
333
334 this.setUpMiniMap();
335
336 assertSourceLabelsVisible(
337 "White Tiles",
338 "Black Tiles",
339 "Green Tiles"
340 );
341
342 final ImageryLayer magentaTilesLayer = ImageryLayer.create(magentaTilesInfo);
343 GuiHelper.runInEDT(() -> MainApplication.getLayerManager().addLayer(magentaTilesLayer));
344
345 assertSourceLabelsVisible(
346 "White Tiles",
347 "Black Tiles",
348 "Green Tiles",
349 "Magenta Tiles"
350 );
351
352 this.clickSourceMenuItemByLabel("Magenta Tiles");
353 this.assertSingleSelectedSourceLabel("Magenta Tiles");
354
355 // call paint to trigger new tile fetch
356 this.paintSlippyMap();
357
358 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
359
360 this.paintSlippyMap();
361
362 assertEquals(0xffff00ff, paintedSlippyMap.getRGB(0, 0));
363
364 final ImageryLayer blackTilesLayer = ImageryLayer.create(blackTilesInfo);
365 GuiHelper.runInEDT(() -> MainApplication.getLayerManager().addLayer(blackTilesLayer));
366
367 assertSourceLabelsVisible(
368 "White Tiles",
369 "Black Tiles",
370 "Green Tiles",
371 "Magenta Tiles"
372 );
373
374 this.clickSourceMenuItemByLabel("Black Tiles");
375 this.assertSingleSelectedSourceLabel("Black Tiles");
376
377 // call paint to trigger new tile fetch
378 this.paintSlippyMap();
379
380 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
381
382 this.paintSlippyMap();
383
384 assertEquals(0xff000000, paintedSlippyMap.getRGB(0, 0));
385
386 // removing magentaTilesLayer while it is *not* the selected TileSource should make it disappear
387 // immediately
388 GuiHelper.runInEDT(() -> MainApplication.getLayerManager().removeLayer(magentaTilesLayer));
389
390 assertSourceLabelsVisible(
391 "White Tiles",
392 "Black Tiles",
393 "Green Tiles"
394 );
395 this.assertSingleSelectedSourceLabel("Black Tiles");
396
397 final ImageryLayer magentaTilesLayer2 = ImageryLayer.create(magentaTilesInfo);
398 GuiHelper.runInEDT(() -> MainApplication.getLayerManager().addLayer(magentaTilesLayer2));
399
400 assertSourceLabelsVisible(
401 "White Tiles",
402 "Black Tiles",
403 "Green Tiles",
404 "Magenta Tiles"
405 );
406
407 this.clickSourceMenuItemByLabel("Magenta Tiles");
408 this.assertSingleSelectedSourceLabel("Magenta Tiles");
409
410 // call paint to trigger new tile fetch
411 this.paintSlippyMap();
412
413 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
414
415 this.paintSlippyMap();
416
417 assertEquals(0xffff00ff, paintedSlippyMap.getRGB(0, 0));
418
419 // removing magentaTilesLayer while it *is* the selected TileSource...
420 GuiHelper.runInEDT(() -> MainApplication.getLayerManager().removeLayer(magentaTilesLayer2));
421
422 assertSourceLabelsVisible(
423 "White Tiles",
424 "Black Tiles",
425 "Green Tiles",
426 "Magenta Tiles"
427 );
428 this.assertSingleSelectedSourceLabel("Magenta Tiles");
429
430 this.clickSourceMenuItemByLabel("Green Tiles");
431 this.assertSingleSelectedSourceLabel("Green Tiles");
432 assertSourceLabelsVisible(
433 "White Tiles",
434 "Black Tiles",
435 "Green Tiles"
436 );
437
438 // removing blackTilesLayer shouldn't remove it from the menu as it is already in ImageryLayerInfo
439 GuiHelper.runInEDT(() -> MainApplication.getLayerManager().removeLayer(blackTilesLayer));
440
441 this.assertSingleSelectedSourceLabel("Green Tiles");
442 assertSourceLabelsVisible(
443 "White Tiles",
444 "Black Tiles",
445 "Green Tiles"
446 );
447 }
448
449 /**
450 * Tests minimap obeys a saved "mapstyle" preference on startup.
451 * @throws Exception if any error occurs
452 */
453 @Test
454 public void testSourcePrefObeyed() throws Exception {
455 Config.getPref().put("slippy_map_chooser.mapstyle", "Green Tiles");
456
457 this.setUpMiniMap();
458
459 this.assertSingleSelectedSourceLabel("Green Tiles");
460
461 // an initial paint operation is required to trigger the tile fetches
462 this.paintSlippyMap();
463
464 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
465
466 this.paintSlippyMap();
467
468 assertEquals(0xff00ff00, paintedSlippyMap.getRGB(0, 0));
469
470 this.clickSourceMenuItemByLabel("Magenta Tiles");
471 this.assertSingleSelectedSourceLabel("Magenta Tiles");
472
473 assertEquals("Magenta Tiles", Config.getPref().get("slippy_map_chooser.mapstyle", "Fail"));
474 }
475
476 /**
477 * Tests minimap handles an unrecognized "mapstyle" preference on startup
478 * @throws Exception if any error occurs
479 */
480 @Test
481 public void testSourcePrefInvalid() throws Exception {
482 Config.getPref().put("slippy_map_chooser.mapstyle", "Hooloovoo Tiles");
483
484 this.setUpMiniMap();
485
486 this.assertSingleSelectedSourceLabel("White Tiles");
487
488 // an initial paint operation is required to trigger the tile fetches
489 this.paintSlippyMap();
490
491 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
492
493 this.paintSlippyMap();
494
495 assertEquals(0xffffffff, paintedSlippyMap.getRGB(0, 0));
496 }
497
498 /**
499 * test viewport marker rectangle matches the mapView's aspect ratio
500 * @throws Exception if any error occurs
501 */
502 @Test
503 public void testViewportAspectRatio() throws Exception {
504 // Add a test layer to the layer manager to get the MapFrame & MapView
505 MainApplication.getLayerManager().addLayer(new TestLayer());
506
507 Config.getPref().put("slippy_map_chooser.mapstyle", "White Tiles");
508 // ensure projection matches JMapViewer's
509 ProjectionRegistry.setProjection(Projections.getProjectionByCode("EPSG:3857"));
510
511 MapView mapView = MainApplication.getMap().mapView;
512 GuiHelper.runInEDTAndWaitWithException(() -> {
513 mapView.setVisible(true);
514 mapView.addNotify();
515 mapView.doLayout();
516 // ensure we have a square mapView viewport
517 mapView.setBounds(0, 0, 350, 350);
518 });
519
520 this.setUpMiniMap();
521
522 // attempt to set viewport to cover a non-square area
523 mapView.zoomTo(new Bounds(26.27, -18.23, 26.275, -18.229));
524
525 // an initial paint operation is required to trigger the tile fetches
526 this.paintSlippyMap();
527
528 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
529
530 this.paintSlippyMap();
531
532 Map<Integer, String> paletteMap = ImmutableMap.<Integer, String>builder()
533 .put(0xffffffff, "w") // white
534 .put(0xff000000, "b") // black
535 .put(0xfff0d1d1, "p") // pink
536 .build();
537
538 Matcher rowMatcher = ImagePatternMatching.rowMatch(
539 paintedSlippyMap,
540 paintedSlippyMap.getHeight()/2,
541 paletteMap,
542 "^(w+)b(p+)b(w+)$",
543 true
544 );
545
546 // (within a tolerance for numerical error) the number of pixels on the left of the viewport marker
547 // should equal the number on the right
548 assertTrue(
549 "Viewport marker not horizontally centered",
550 Math.abs(rowMatcher.group(1).length() - rowMatcher.group(3).length()) < 4
551 );
552
553 Matcher colMatcher = ImagePatternMatching.columnMatch(
554 paintedSlippyMap,
555 paintedSlippyMap.getWidth()/2,
556 paletteMap,
557 "^(w+)b(p+)b(w+)$",
558 true
559 );
560
561 // (within a tolerance for numerical error) the number of pixels on the top of the viewport marker
562 // should equal the number on the bottom
563 assertTrue(
564 "Viewport marker not vertically centered",
565 Math.abs(colMatcher.group(1).length() - colMatcher.group(3).length()) < 4
566 );
567
568 // (within a tolerance for numerical error) the viewport marker should be square
569 assertTrue(
570 "Viewport marker not square",
571 Math.abs(colMatcher.group(2).length() - rowMatcher.group(2).length()) < 4
572 );
573
574 // now change the mapView size
575 GuiHelper.runInEDTAndWaitWithException(() -> {
576 mapView.setBounds(0, 0, 150, 300);
577 Arrays.stream(mapView.getComponentListeners()).forEach(
578 cl -> cl.componentResized(new ComponentEvent(mapView, ComponentEvent.COMPONENT_RESIZED))
579 );
580 });
581 // minimap doesn't (yet?) listen for component resize events to update its viewport marker, so
582 // trigger a zoom change
583 mapView.zoomTo(mapView.getCenter().add(1., 0.));
584 this.paintSlippyMap();
585
586 rowMatcher = ImagePatternMatching.rowMatch(
587 paintedSlippyMap,
588 paintedSlippyMap.getHeight()/2,
589 paletteMap,
590 "^(w+)b(p+)b(w+)$",
591 true
592 );
593 assertTrue(
594 "Viewport marker not horizontally centered",
595 Math.abs(rowMatcher.group(1).length() - rowMatcher.group(3).length()) < 4
596 );
597
598 colMatcher = ImagePatternMatching.columnMatch(
599 paintedSlippyMap,
600 paintedSlippyMap.getWidth()/2,
601 paletteMap,
602 "^(w+)b(p+)b(w+)$",
603 true
604 );
605 assertTrue(
606 "Viewport marker not vertically centered",
607 Math.abs(colMatcher.group(1).length() - colMatcher.group(3).length()) < 4
608 );
609
610 try {
611 javax.imageio.ImageIO.write(paintedSlippyMap, "png", new java.io.File("failed.png"));
612 } catch (java.io.IOException ioe) {
613 System.err.println("Failed writing image");
614 }
615
616 assertTrue(
617 "Viewport marker not 2:1 aspect ratio",
618 Math.abs(colMatcher.group(2).length() - (rowMatcher.group(2).length()*2.0)) < 5
619 );
620 }
621
622 protected JCheckBoxMenuItem getShowDownloadedAreaMenuItem() {
623 JPopupMenu menu = this.sourceButton.getPopupMenu();
624 boolean afterSeparator = false;
625 for (Component c: menu.getComponents()) {
626 if (JPopupMenu.Separator.class.isInstance(c)) {
627 assertFalse("More than one separator before target item", afterSeparator);
628 afterSeparator = true;
629 } else if (((JMenuItem) c).getText().equals(tr("Show downloaded area"))) {
630 assertTrue("Separator not found before target item", afterSeparator);
631 assertTrue("Target item doesn't appear to be a JCheckBoxMenuItem", JCheckBoxMenuItem.class.isInstance(c));
632 return (JCheckBoxMenuItem) c;
633 }
634 }
635 fail("'Show downloaded area' menu item not found");
636 return null;
637 }
638
639 /**
640 * test downloaded area is shown shaded
641 * @throws Exception if any error occurs
642 */
643 @Test
644 public void testShowDownloadedArea() throws Exception {
645 Config.getPref().put("slippy_map_chooser.mapstyle", "Green Tiles");
646 Config.getPref().putBoolean("slippy_map_chooser.show_downloaded_area", false);
647
648 DataSet dataSet = new DataSet();
649 dataSet.addDataSource(new DataSource(new Bounds(51.725, -0.0209, 51.746, 0.0162), "Somewhere"));
650
651 OsmDataLayer dataLayer = new OsmDataLayer(
652 dataSet,
653 "Test Layer 123",
654 null
655 );
656 MainApplication.getLayerManager().addLayer(dataLayer);
657 MainApplication.getLayerManager().setActiveLayer(dataLayer);
658
659 MapView mapView = MainApplication.getMap().mapView;
660 GuiHelper.runInEDTAndWaitWithException(() -> {
661 mapView.setVisible(true);
662 mapView.addNotify();
663 mapView.doLayout();
664 mapView.setBounds(0, 0, 500, 500);
665 });
666
667 this.setUpMiniMap();
668
669 // assert "show downloaded areas" checkbox is unchecked
670 assertFalse(this.getShowDownloadedAreaMenuItem().isSelected());
671
672 // we won't end up with exactly this viewport as it doesn't *precisely* match the aspect ratio
673 mapView.zoomTo(new Bounds(51.732, -0.0269, 51.753, 0.0102));
674
675 // an initial paint operation is required to trigger the tile fetches
676 this.paintSlippyMap();
677
678 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
679
680 this.paintSlippyMap();
681
682 Map<Integer, String> paletteMap = ImmutableMap.<Integer, String>builder()
683 .put(0xff00ff00, "g") // green
684 .put(0xff000000, "b") // black
685 .put(0xff8ad16b, "v") // viewport marker inner (pink+green mix)
686 .put(0xff00df00, "d") // (shaded green)
687 .put(0xff8ac46b, "q") // (shaded pink+green mix)
688 .build();
689
690 // assert downloaded areas are not drawn
691 ImagePatternMatching.rowMatch(
692 paintedSlippyMap,
693 paintedSlippyMap.getHeight()/2,
694 paletteMap,
695 "^g+bv+bg+$",
696 true
697 );
698 ImagePatternMatching.columnMatch(
699 paintedSlippyMap,
700 paintedSlippyMap.getWidth()/2,
701 paletteMap,
702 "^g+bv+bg+$",
703 true
704 );
705
706 // enable "show downloaded areas"
707 GuiHelper.runInEDTAndWaitWithException(() -> this.getShowDownloadedAreaMenuItem().doClick());
708 assertTrue(this.getShowDownloadedAreaMenuItem().isSelected());
709
710 // assert downloaded areas are drawn
711 this.paintSlippyMap();
712
713 ImagePatternMatching.rowMatch(
714 paintedSlippyMap,
715 paintedSlippyMap.getHeight()/2,
716 paletteMap,
717 "^d+bq+v+bg+d+$",
718 true
719 );
720 ImagePatternMatching.columnMatch(
721 paintedSlippyMap,
722 paintedSlippyMap.getWidth()/2,
723 paletteMap,
724 "^d+bq+v+bg+d+$",
725 true
726 );
727
728 // also assert the leftmost column doesn't (yet) have any downloaded area marks (i.e. fully shaded)
729 ImagePatternMatching.columnMatch(
730 paintedSlippyMap,
731 0,
732 paletteMap,
733 "^d+$",
734 true
735 );
736
737 // add another downloaded area, going off the left of the widget
738 dataSet.addDataSource(new DataSource(new Bounds(51.745, -1., 51.765, 0.0162), "Somewhere else"));
739 // and redraw
740 this.paintSlippyMap();
741
742 // the middle row should be as before
743 ImagePatternMatching.rowMatch(
744 paintedSlippyMap,
745 paintedSlippyMap.getHeight()/2,
746 paletteMap,
747 "^d+bq+v+bg+d+$",
748 true
749 );
750 // the middle column should have its unshaded region extended beyond the viewport marker
751 ImagePatternMatching.columnMatch(
752 paintedSlippyMap,
753 paintedSlippyMap.getWidth()/2,
754 paletteMap,
755 "^d+g+bv+bg+d+$",
756 true
757 );
758 // but the leftmost column should now have an unshaded mark
759 ImagePatternMatching.columnMatch(
760 paintedSlippyMap,
761 0,
762 paletteMap,
763 "^d+g+d+$",
764 true
765 );
766 // and the rightmost column should be untouched
767 ImagePatternMatching.columnMatch(
768 paintedSlippyMap,
769 paintedSlippyMap.getWidth()-1,
770 paletteMap,
771 "^d+$",
772 true
773 );
774
775 // and now if we pan to the left (in EastNorth units)
776 mapView.zoomTo(mapView.getCenter().add(-5000., 0.));
777 // and redraw
778 this.paintSlippyMap();
779
780 // the middle row should have its unshaded region outside the viewport marker
781 ImagePatternMatching.rowMatch(
782 paintedSlippyMap,
783 paintedSlippyMap.getHeight()/2,
784 paletteMap,
785 "^d+bq+bd+g+d*$",
786 true
787 );
788 // the middle column should have a shaded region inside the viewport marker
789 ImagePatternMatching.columnMatch(
790 paintedSlippyMap,
791 paintedSlippyMap.getWidth()/2,
792 paletteMap,
793 "^d+g+bv+q+bd+$",
794 true
795 );
796 }
797
798 /**
799 * test display of downloaded area follows active layer switching
800 * @throws Exception if any error occurs
801 */
802 @Test
803 public void testShowDownloadedAreaLayerSwitching() throws Exception {
804 Config.getPref().put("slippy_map_chooser.mapstyle", "Green Tiles");
805 Config.getPref().putBoolean("slippy_map_chooser.show_downloaded_area", true);
806
807 DataSet dataSetA = new DataSet();
808 // dataSetA has a long thin horizontal downloaded area (extending off the left & right of the map)
809 dataSetA.addDataSource(new DataSource(new Bounds(-18., -61.02, -15., -60.98), "Elsewhere"));
810
811 OsmDataLayer dataLayerA = new OsmDataLayer(
812 dataSetA,
813 "Test Layer A",
814 null
815 );
816 MainApplication.getLayerManager().addLayer(dataLayerA);
817
818 DataSet dataSetB = new DataSet();
819 // dataSetB has a long thin vertical downloaded area (extending off the top & bottom of the map)
820 dataSetB.addDataSource(new DataSource(new Bounds(-16.38, -62., -16.34, -60.), "Nowhere"));
821
822 OsmDataLayer dataLayerB = new OsmDataLayer(
823 dataSetB,
824 "Test Layer B",
825 null
826 );
827 MainApplication.getLayerManager().addLayer(dataLayerB);
828
829 MainApplication.getLayerManager().setActiveLayer(dataLayerB);
830
831 MapView mapView = MainApplication.getMap().mapView;
832 GuiHelper.runInEDTAndWaitWithException(() -> {
833 mapView.setVisible(true);
834 mapView.addNotify();
835 mapView.doLayout();
836 mapView.setBounds(0, 0, 400, 400);
837 });
838
839 this.setUpMiniMap();
840
841 // assert "show downloaded areas" checkbox is checked
842 assertTrue(this.getShowDownloadedAreaMenuItem().isSelected());
843
844 // again, we won't end up with exactly this viewport as it doesn't *precisely* match the aspect ratio
845 mapView.zoomTo(new Bounds(-16.423, -61.076, -16.299, -60.932));
846
847 // an initial paint operation is required to trigger the tile fetches
848 this.paintSlippyMap();
849
850 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
851
852 this.paintSlippyMap();
853
854 Map<Integer, String> paletteMap = ImmutableMap.<Integer, String>builder()
855 .put(0xff00ff00, "g") // green
856 .put(0xff000000, "b") // black
857 .put(0xff8ad16b, "v") // viewport marker inner (pink+green mix)
858 .put(0xff00df00, "d") // (shaded green)
859 .put(0xff8ac46b, "q") // (shaded pink+green mix)
860 .build();
861
862 // the middle row should be entirely unshaded
863 ImagePatternMatching.rowMatch(
864 paintedSlippyMap,
865 paintedSlippyMap.getHeight()/2,
866 paletteMap,
867 "^g+bv+bg+$",
868 true
869 );
870 // the middle column should have an unshaded band within the viewport marker
871 Matcher centerMatcher = ImagePatternMatching.columnMatch(
872 paintedSlippyMap,
873 paintedSlippyMap.getWidth()/2,
874 paletteMap,
875 "^(d+bq+)(v+)(q+bd+)$",
876 true
877 );
878 // the leftmost and rightmost columns should have an unshaded band
879 Matcher leftMatcher = ImagePatternMatching.columnMatch(
880 paintedSlippyMap,
881 0,
882 paletteMap,
883 "^(d+)(g+)(d+)$",
884 true
885 );
886 Matcher rightMatcher = ImagePatternMatching.columnMatch(
887 paintedSlippyMap,
888 paintedSlippyMap.getWidth()-1,
889 paletteMap,
890 "^(d+)(g+)(d+)$",
891 true
892 );
893 // the three columns should have the unshaded band in the same place
894 assertEquals(centerMatcher.group(1).length(), leftMatcher.group(1).length());
895 assertEquals(centerMatcher.group(1).length(), rightMatcher.group(1).length());
896 assertEquals(centerMatcher.group(2).length(), leftMatcher.group(2).length());
897 assertEquals(centerMatcher.group(2).length(), rightMatcher.group(2).length());
898
899 // switch active layer
900 MainApplication.getLayerManager().setActiveLayer(dataLayerA);
901 this.paintSlippyMap();
902
903 // the middle column should be entirely unshaded
904 ImagePatternMatching.columnMatch(
905 paintedSlippyMap,
906 paintedSlippyMap.getWidth()/2,
907 paletteMap,
908 "^g+bv+bg+$",
909 true
910 );
911 // the middle row should have an unshaded band within the viewport marker
912 centerMatcher = ImagePatternMatching.rowMatch(
913 paintedSlippyMap,
914 paintedSlippyMap.getHeight()/2,
915 paletteMap,
916 "^(d+bq+)(v+)(q+bd+)$",
917 true
918 );
919 // the topmost and bottommost rows should have an unshaded band
920 Matcher topMatcher = ImagePatternMatching.rowMatch(
921 paintedSlippyMap,
922 0,
923 paletteMap,
924 "^(d+)(g+)(d+)$",
925 true
926 );
927 Matcher BottomMatcher = ImagePatternMatching.rowMatch(
928 paintedSlippyMap,
929 paintedSlippyMap.getHeight()-1,
930 paletteMap,
931 "^(d+)(g+)(d+)$",
932 true
933 );
934 // the three rows should have the unshaded band in the same place
935 assertEquals(centerMatcher.group(1).length(), topMatcher.group(1).length());
936 assertEquals(centerMatcher.group(1).length(), BottomMatcher.group(1).length());
937 assertEquals(centerMatcher.group(2).length(), topMatcher.group(2).length());
938 assertEquals(centerMatcher.group(2).length(), BottomMatcher.group(2).length());
939
940 // deleting dataLayerA should hopefully switch our active layer back to dataLayerB
941 MainApplication.getLayerManager().removeLayer(dataLayerA);
942 this.paintSlippyMap();
943
944 // now we're really just repeating the same assertions we made originally when dataLayerB was active
945 // the middle row should be entirely unshaded
946 ImagePatternMatching.rowMatch(
947 paintedSlippyMap,
948 paintedSlippyMap.getHeight()/2,
949 paletteMap,
950 "^g+bv+bg+$",
951 true
952 );
953 // the middle column should have an unshaded band within the viewport marker
954 centerMatcher = ImagePatternMatching.columnMatch(
955 paintedSlippyMap,
956 paintedSlippyMap.getWidth()/2,
957 paletteMap,
958 "^(d+bq+)(v+)(q+bd+)$",
959 true
960 );
961 // the leftmost and rightmost columns should have an unshaded band
962 leftMatcher = ImagePatternMatching.columnMatch(
963 paintedSlippyMap,
964 0,
965 paletteMap,
966 "^(d+)(g+)(d+)$",
967 true
968 );
969 rightMatcher = ImagePatternMatching.columnMatch(
970 paintedSlippyMap,
971 paintedSlippyMap.getWidth()-1,
972 paletteMap,
973 "^(d+)(g+)(d+)$",
974 true
975 );
976 // the three columns should have the unshaded band in the same place
977 assertEquals(centerMatcher.group(1).length(), leftMatcher.group(1).length());
978 assertEquals(centerMatcher.group(1).length(), rightMatcher.group(1).length());
979 assertEquals(centerMatcher.group(2).length(), leftMatcher.group(2).length());
980 assertEquals(centerMatcher.group(2).length(), rightMatcher.group(2).length());
981
982 // but now if we expand its downloaded area to cover most of the southern hemisphere...
983 dataSetB.addDataSource(new DataSource(new Bounds(-75., -100., 0., 100.), "Everywhere"));
984 this.paintSlippyMap();
985
986 // we should see it all as unshaded.
987 ImagePatternMatching.rowMatch(
988 paintedSlippyMap,
989 0,
990 paletteMap,
991 "^g+$",
992 true
993 );
994 ImagePatternMatching.rowMatch(
995 paintedSlippyMap,
996 paintedSlippyMap.getHeight()/2,
997 paletteMap,
998 "^g+bv+bg+$",
999 true
1000 );
1001 ImagePatternMatching.rowMatch(
1002 paintedSlippyMap,
1003 paintedSlippyMap.getHeight()-1,
1004 paletteMap,
1005 "^g+$",
1006 true
1007 );
1008 ImagePatternMatching.columnMatch(
1009 paintedSlippyMap,
1010 0,
1011 paletteMap,
1012 "^g+$",
1013 true
1014 );
1015 ImagePatternMatching.columnMatch(
1016 paintedSlippyMap,
1017 paintedSlippyMap.getWidth()/2,
1018 paletteMap,
1019 "^g+bv+bg+$",
1020 true
1021 );
1022 ImagePatternMatching.columnMatch(
1023 paintedSlippyMap,
1024 paintedSlippyMap.getWidth()-1,
1025 paletteMap,
1026 "^g+$",
1027 true
1028 );
1029 }
1030}
Note: See TracBrowser for help on using the repository browser.