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

Last change on this file since 17360 was 17279, checked in by Don-vip, 3 years ago

see #16567 - revert r17275 for CycleLayerActionTest / MinimapDialogTest

They depend on fakeImagery, which does not work yet with JUnit 5

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