Ticket #13412: patch-draw-action.patch
File patch-draw-action.patch, 46.4 KB (added by , 6 years ago) |
---|
-
src/org/openstreetmap/josm/actions/PreferenceToggleAction.java
diff --git a/src/org/openstreetmap/josm/actions/PreferenceToggleAction.java b/src/org/openstreetmap/josm/actions/PreferenceToggleAction.java index dec48ff..2afa61f 100644
a b 2 2 package org.openstreetmap.josm.actions; 3 3 4 4 import java.awt.event.ActionEvent; 5 5 6 import javax.swing.JCheckBoxMenuItem; 7 6 8 import org.openstreetmap.josm.Main; 7 9 import org.openstreetmap.josm.data.Preferences; 8 10 import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener; 11 import org.openstreetmap.josm.data.preferences.BooleanProperty; 9 12 10 13 public class PreferenceToggleAction extends JosmAction implements PreferenceChangedListener { 11 14 12 15 private final JCheckBoxMenuItem checkbox; 13 private final String prefKey; 14 private final boolean prefDefault; 16 private final BooleanProperty pref; 15 17 16 18 public PreferenceToggleAction(String name, String tooltip, String prefKey, boolean prefDefault) { 17 19 super(name, null, tooltip, null, false); 18 20 putValue("toolbar", "toggle-" + prefKey); 19 this.pref Key = prefKey;20 this.prefDefault = prefDefault; 21 this.checkbox = new JCheckBoxMenuItem(this);22 this.checkbox.setSelected(Main.pref.getBoolean(prefKey, prefDefault));23 Main.pref.add PreferenceChangeListener(this);21 this.pref = new BooleanProperty(prefKey, prefDefault); 22 23 checkbox = new JCheckBoxMenuItem(this); 24 checkbox.setSelected(pref.get()); 25 Main.pref.addWeakKeyPreferenceChangeListener(prefKey, this); 24 26 } 25 27 26 28 @Override 27 29 public void actionPerformed(ActionEvent e) { 28 Main.pref.put(prefKey,checkbox.isSelected());30 pref.put(checkbox.isSelected()); 29 31 } 30 32 33 /** 34 * Get the checkbox that can be used for this action. It can only be used at one place. 35 * @return The checkbox. 36 */ 31 37 public JCheckBoxMenuItem getCheckbox() { 32 38 return checkbox; 33 39 } 34 40 35 41 @Override 36 42 public void preferenceChanged(Preferences.PreferenceChangeEvent e) { 37 if (prefKey.equals(e.getKey())) { 38 checkbox.setSelected(Main.pref.getBoolean(prefKey, prefDefault)); 39 } 43 checkbox.setSelected(pref.get()); 40 44 } 41 45 } -
src/org/openstreetmap/josm/actions/mapmode/DrawAction.java
diff --git a/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java b/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java index 58c0b34..35feecd 100644
a b import java.awt.Color; 11 11 import java.awt.Cursor; 12 12 import java.awt.Graphics2D; 13 13 import java.awt.Point; 14 import java.awt.Stroke;15 14 import java.awt.event.ActionEvent; 16 15 import java.awt.event.KeyEvent; 17 16 import java.awt.event.MouseEvent; … … import java.util.ArrayList; 20 19 import java.util.Arrays; 21 20 import java.util.Collection; 22 21 import java.util.Collections; 22 import java.util.Comparator; 23 23 import java.util.HashMap; 24 24 import java.util.HashSet; 25 25 import java.util.Iterator; … … import java.util.LinkedList; 27 27 import java.util.List; 28 28 import java.util.Map; 29 29 import java.util.Set; 30 import java.util.stream.DoubleStream; 30 31 31 32 import javax.swing.AbstractAction; 32 33 import javax.swing.JCheckBoxMenuItem; … … import org.openstreetmap.josm.data.osm.WaySegment; 52 53 import org.openstreetmap.josm.data.osm.visitor.paint.ArrowPaintHelper; 53 54 import org.openstreetmap.josm.data.osm.visitor.paint.MapPath2D; 54 55 import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors; 56 import org.openstreetmap.josm.data.preferences.AbstractToStringProperty; 57 import org.openstreetmap.josm.data.preferences.BooleanProperty; 58 import org.openstreetmap.josm.data.preferences.CachingProperty; 55 59 import org.openstreetmap.josm.data.preferences.ColorProperty; 60 import org.openstreetmap.josm.data.preferences.DoubleProperty; 61 import org.openstreetmap.josm.data.preferences.StrokeProperty; 56 62 import org.openstreetmap.josm.gui.MainMenu; 57 63 import org.openstreetmap.josm.gui.MapFrame; 58 64 import org.openstreetmap.josm.gui.MapView; 65 import org.openstreetmap.josm.gui.MapViewState; 59 66 import org.openstreetmap.josm.gui.MapViewState.MapViewPoint; 60 67 import org.openstreetmap.josm.gui.NavigatableComponent; 61 68 import org.openstreetmap.josm.gui.layer.Layer; 62 69 import org.openstreetmap.josm.gui.layer.MapViewPaintable; 63 70 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 64 import org.openstreetmap.josm.gui.util.GuiHelper;65 71 import org.openstreetmap.josm.gui.util.KeyPressReleaseListener; 66 72 import org.openstreetmap.josm.gui.util.ModifierListener; 67 73 import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher; … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 80 86 81 87 private static final ArrowPaintHelper START_WAY_INDICATOR = new ArrowPaintHelper(Math.toRadians(90), 8); 82 88 89 private static final CachingProperty<Boolean> USE_REPEATED_SHORTCUT 90 = new BooleanProperty("draw.anglesnap.toggleOnRepeatedA", true).cached(); 91 private static final CachingProperty<BasicStroke> RUBBER_LINE_STROKE 92 = new StrokeProperty("draw.stroke.helper-line", "3").cached(); 93 94 private static final CachingProperty<BasicStroke> HIGHLIGHT_STROKE 95 = new StrokeProperty("draw.anglesnap.stroke.highlight", "10").cached(); 96 private static final CachingProperty<BasicStroke> HELPER_STROKE 97 = new StrokeProperty("draw.anglesnap.stroke.helper", "1 4").cached(); 98 99 private static final CachingProperty<Double> SNAP_ANGLE_TOLERANCE 100 = new DoubleProperty("draw.anglesnap.tolerance", 5.0).cached(); 101 private static final CachingProperty<Boolean> DRAW_CONSTRUCTION_GEOMETRY 102 = new BooleanProperty("draw.anglesnap.drawConstructionGeometry", true).cached(); 103 private static final CachingProperty<Boolean> SHOW_PROJECTED_POINT 104 = new BooleanProperty("draw.anglesnap.drawProjectedPoint", true).cached(); 105 private static final CachingProperty<Boolean> SNAP_TO_PROJECTIONS 106 = new BooleanProperty("draw.anglesnap.projectionsnap", true).cached(); 107 108 private static final CachingProperty<Boolean> SHOW_ANGLE 109 = new BooleanProperty("draw.anglesnap.showAngle", true).cached(); 110 111 private static final CachingProperty<Color> SNAP_HELPER_COLOR 112 = new ColorProperty(marktr("draw angle snap"), Color.ORANGE).cached(); 113 114 private static final CachingProperty<Color> HIGHLIGHT_COLOR 115 = new ColorProperty(marktr("draw angle snap highlight"), ORANGE_TRANSPARENT).cached(); 116 117 private static final AbstractToStringProperty<Color> RUBBER_LINE_COLOR 118 = PaintColors.SELECTED.getProperty().getChildColor(marktr("helper line")); 119 120 private static final CachingProperty<Boolean> DRAW_HELPER_LINE 121 = new BooleanProperty("draw.helper-line", true).cached(); 122 private static final CachingProperty<Boolean> DRAW_TARGET_HIGHLIGHT 123 = new BooleanProperty("draw.target-highlight", true).cached(); 124 private static final CachingProperty<Double> SNAP_TO_INTERSECTION_THRESHOLD 125 = new DoubleProperty("edit.snap-intersection-threshold", 10).cached(); 126 83 127 private final Cursor cursorJoinNode; 84 128 private final Cursor cursorJoinWay; 85 129 … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 96 140 // but haven’t been so far. The idea is to compare old and new and only 97 141 // repaint if there are changes. 98 142 private transient Set<OsmPrimitive> newHighlights = new HashSet<>(); 99 private boolean drawHelperLine;100 143 private boolean wayIsFinished; 101 private boolean drawTargetHighlight;102 144 private Point mousePos; 103 145 private Point oldMousePos; 104 private Color rubberLineColor;105 146 106 147 private transient Node currentBaseNode; 107 148 private transient Node previousNode; … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 116 157 117 158 private final SnapChangeAction snapChangeAction; 118 159 private final JCheckBoxMenuItem snapCheckboxMenuItem; 119 private boolean useRepeatedShortcut;120 private transient Stroke rubberLineStroke;121 160 private static final BasicStroke BASIC_STROKE = new BasicStroke(1); 122 161 123 private static int snapToIntersectionThreshold;162 private Point rightClickPressPos; 124 163 125 164 /** 126 165 * Constructs a new {@code DrawAction}. … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 142 181 cursorJoinNode = ImageProvider.getCursor("crosshair", "joinnode"); 143 182 cursorJoinWay = ImageProvider.getCursor("crosshair", "joinway"); 144 183 145 readPreferences();146 184 snapHelper.init(); 147 readPreferences();148 185 } 149 186 150 187 private JCheckBoxMenuItem addMenuItem() { … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 165 202 private boolean redrawIfRequired() { 166 203 updateStatusLine(); 167 204 // repaint required if the helper line is active. 168 boolean needsRepaint = drawHelperLine&& !wayIsFinished;169 if ( drawTargetHighlight) {205 boolean needsRepaint = DRAW_HELPER_LINE.get() && !wayIsFinished; 206 if (DRAW_TARGET_HIGHLIGHT.get()) { 170 207 // move newHighlights to oldHighlights; only update changed primitives 171 208 for (OsmPrimitive x : newHighlights) { 172 209 if (oldHighlights.contains(x)) { … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 184 221 // required in order to print correct help text 185 222 oldHighlights = newHighlights; 186 223 187 if (!needsRepaint && ! drawTargetHighlight)224 if (!needsRepaint && !DRAW_TARGET_HIGHLIGHT.get()) 188 225 return false; 189 226 190 227 // update selection to reflect which way being modified … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 245 282 } 246 283 247 284 @Override 248 protected void readPreferences() {249 rubberLineColor = new ColorProperty(marktr("helper line"), (Color) null).get();250 if (rubberLineColor == null)251 rubberLineColor = PaintColors.SELECTED.get();252 253 rubberLineStroke = GuiHelper.getCustomizedStroke(Main.pref.get("draw.stroke.helper-line", "3"));254 drawHelperLine = Main.pref.getBoolean("draw.helper-line", true);255 drawTargetHighlight = Main.pref.getBoolean("draw.target-highlight", true);256 snapToIntersectionThreshold = Main.pref.getInteger("edit.snap-intersection-threshold", 10);257 }258 259 @Override260 285 public void exitMode() { 261 286 super.exitMode(); 262 287 Main.map.mapView.removeMouseListener(this); … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 297 322 298 323 @Override 299 324 public void doKeyPressed(KeyEvent e) { 300 if (!snappingShortcut.isEvent(e) && !( useRepeatedShortcut&& getShortcut().isEvent(e)))325 if (!snappingShortcut.isEvent(e) && !(USE_REPEATED_SHORTCUT.get() && getShortcut().isEvent(e))) 301 326 return; 302 327 snapHelper.setFixedMode(); 303 328 computeHelperLine(); … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 306 331 307 332 @Override 308 333 public void doKeyReleased(KeyEvent e) { 309 if (!snappingShortcut.isEvent(e) && !( useRepeatedShortcut&& getShortcut().isEvent(e)))334 if (!snappingShortcut.isEvent(e) && !(USE_REPEATED_SHORTCUT.get() && getShortcut().isEvent(e))) 310 335 return; 311 336 if (ignoreNextKeyRelease) { 312 337 ignoreNextKeyRelease = false; … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 352 377 removeHighlighting(); 353 378 } 354 379 355 private Point rightClickPressPos;356 357 380 @Override 358 381 public void mousePressed(MouseEvent e) { 359 382 if (e.getButton() == MouseEvent.BUTTON3) { … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 590 613 newSelection.add(wayToSelect); 591 614 } 592 615 } 616 if (!extendedWay && !newNode) { 617 return; // We didn't do anything. 618 } 619 620 String title = getTitle(newNode, n, newSelection, reuseWays, extendedWay); 593 621 622 Command c = new SequenceCommand(title, cmds); 623 624 Main.main.undoRedo.add(c); 625 if (!wayIsFinished) { 626 lastUsedNode = n; 627 } 628 629 ds.setSelected(newSelection); 630 631 // "viewport following" mode for tracing long features 632 // from aerial imagery or GPS tracks. 633 if (Main.map.mapView.viewportFollowing) { 634 Main.map.mapView.smoothScrollTo(n.getEastNorth()); 635 } 636 computeHelperLine(); 637 removeHighlighting(); 638 } 639 640 private String getTitle(boolean newNode, Node n, Collection<OsmPrimitive> newSelection, List<Way> reuseWays, 641 boolean extendedWay) { 594 642 String title; 595 643 if (!extendedWay) { 596 if (!newNode) 597 return; // We didn't do anything. 598 else if (reuseWays.isEmpty()) { 644 if (reuseWays.isEmpty()) { 599 645 title = tr("Add node"); 600 646 } else { 601 647 title = tr("Add node into way"); … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 612 658 } else { 613 659 title = tr("Add node into way and connect"); 614 660 } 615 616 Command c = new SequenceCommand(title, cmds); 617 618 Main.main.undoRedo.add(c); 619 if (!wayIsFinished) { 620 lastUsedNode = n; 621 } 622 623 ds.setSelected(newSelection); 624 625 // "viewport following" mode for tracing long features 626 // from aerial imagery or GPS tracks. 627 if (n != null && Main.map.mapView.viewportFollowing) { 628 Main.map.mapView.smoothScrollTo(n.getEastNorth()); 629 } 630 computeHelperLine(); 631 removeHighlighting(); 661 return title; 632 662 } 633 663 634 664 private void insertNodeIntoAllNearbySegments(List<WaySegment> wss, Node n, Collection<OsmPrimitive> newSelection, … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 1032 1062 // only adjust to intersection if within snapToIntersectionThreshold pixel of mouse click; otherwise 1033 1063 // fall through to default action. 1034 1064 // (for semi-parallel lines, intersection might be miles away!) 1035 if (Main.map.mapView.getPoint2D(n).distance(Main.map.mapView.getPoint2D(intersection)) < snapToIntersectionThreshold) {1065 if (Main.map.mapView.getPoint2D(n).distance(Main.map.mapView.getPoint2D(intersection)) < SNAP_TO_INTERSECTION_THRESHOLD.get()) { 1036 1066 n.setEastNorth(intersection); 1037 1067 return; 1038 1068 } … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 1134 1164 return; 1135 1165 1136 1166 Graphics2D g2 = g; 1137 snapHelper.drawIfNeeded(g2, mv );1138 if (! drawHelperLine|| wayIsFinished || shift)1167 snapHelper.drawIfNeeded(g2, mv.getState()); 1168 if (!DRAW_HELPER_LINE.get() || wayIsFinished || shift) 1139 1169 return; 1140 1170 1141 if (!snapHelper.isActive()) { // else use color and stoke from snapHelper.draw 1142 g2.setColor(rubberLineColor); 1143 g2.setStroke(rubberLineStroke); 1144 } else if (!snapHelper.drawConstructionGeometry) 1145 return; 1171 if (!snapHelper.isActive()) { 1172 g2.setColor(RUBBER_LINE_COLOR.get()); 1173 g2.setStroke(RUBBER_LINE_STROKE.get()); 1174 paintConstructionGeometry(mv, g2); 1175 } else if (DRAW_CONSTRUCTION_GEOMETRY.get()) { 1176 // else use color and stoke from snapHelper.draw 1177 paintConstructionGeometry(mv, g2); 1178 } 1179 } 1180 1181 private void paintConstructionGeometry(MapView mv, Graphics2D g2) { 1146 1182 MapPath2D b = new MapPath2D(); 1147 1183 MapViewPoint p1 = mv.getState().getPointFor(getCurrentBaseNode()); 1148 1184 MapViewPoint p2 = mv.getState().getPointFor(currentMouseEastNorth); … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 1304 1340 } 1305 1341 1306 1342 private class SnapHelper { 1343 private static final String DRAW_ANGLESNAP_ANGLES = "draw.anglesnap.angles"; 1344 1307 1345 private final class AnglePopupMenu extends JPopupMenu { 1308 1346 1309 1347 private final JCheckBoxMenuItem repeatedCb = new JCheckBoxMenuItem( … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 1311 1349 @Override 1312 1350 public void actionPerformed(ActionEvent e) { 1313 1351 boolean sel = ((JCheckBoxMenuItem) e.getSource()).getState(); 1314 Main.pref.put("draw.anglesnap.toggleOnRepeatedA", sel); 1315 init(); 1352 USE_REPEATED_SHORTCUT.put(sel); 1316 1353 } 1317 1354 }); 1318 1355 … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 1321 1358 @Override 1322 1359 public void actionPerformed(ActionEvent e) { 1323 1360 boolean sel = ((JCheckBoxMenuItem) e.getSource()).getState(); 1324 Main.pref.put("draw.anglesnap.drawConstructionGeometry", sel); 1325 Main.pref.put("draw.anglesnap.drawProjectedPoint", sel); 1326 Main.pref.put("draw.anglesnap.showAngle", sel); 1327 init(); 1361 DRAW_CONSTRUCTION_GEOMETRY.put(sel); 1362 SHOW_PROJECTED_POINT.put(sel); 1363 SHOW_ANGLE.put(sel); 1328 1364 enableSnapping(); 1329 1365 } 1330 1366 }); … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 1334 1370 @Override 1335 1371 public void actionPerformed(ActionEvent e) { 1336 1372 boolean sel = ((JCheckBoxMenuItem) e.getSource()).getState(); 1337 Main.pref.put("draw.anglesnap.projectionsnap", sel); 1338 init(); 1373 SNAP_TO_PROJECTIONS.put(sel); 1339 1374 enableSnapping(); 1340 1375 } 1341 1376 }); 1342 1377 1343 1378 private AnglePopupMenu() { 1344 helperCb.setState( Main.pref.getBoolean("draw.anglesnap.drawConstructionGeometry", true));1345 projectionCb.setState( Main.pref.getBoolean("draw.anglesnap.projectionsnapgvff", true));1346 repeatedCb.setState( Main.pref.getBoolean("draw.anglesnap.toggleOnRepeatedA", true));1379 helperCb.setState(DRAW_CONSTRUCTION_GEOMETRY.get()); 1380 projectionCb.setState(SNAP_TO_PROJECTIONS.get()); 1381 repeatedCb.setState(USE_REPEATED_SHORTCUT.get()); 1347 1382 add(repeatedCb); 1348 1383 add(helperCb); 1349 1384 add(projectionCb); … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 1384 1419 private boolean fixed; // snap angle is fixed 1385 1420 private boolean absoluteFix; // snap angle is absolute 1386 1421 1387 private boolean drawConstructionGeometry;1388 private boolean showProjectedPoint;1389 private boolean showAngle;1390 1391 private boolean snapToProjections;1392 1393 1422 private EastNorth dir2; 1394 1423 private EastNorth projected; 1395 1424 private String labelText; … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 1401 1430 private EastNorth projectionSource; // point that we are projecting to the line 1402 1431 1403 1432 private double[] snapAngles; 1404 private double snapAngleTolerance;1405 1433 1406 1434 private double pe, pn; // (pe, pn) - direction of snapping line 1407 1435 private double e0, n0; // (e0, n0) - origin of snapping line 1408 1436 1409 1437 private final String fixFmt = "%d "+tr("FIX"); 1410 private Color snapHelperColor;1411 private Color highlightColor;1412 1413 private Stroke normalStroke;1414 private Stroke helperStroke;1415 private Stroke highlightStroke;1416 1438 1417 1439 private JCheckBoxMenuItem checkBox; 1418 1440 … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 1427 1449 } 1428 1450 }; 1429 1451 1452 /** 1453 * Set the initial state 1454 */ 1430 1455 public void init() { 1431 1456 snapOn = false; 1432 1457 checkBox.setState(snapOn); 1433 1458 fixed = false; 1434 1459 absoluteFix = false; 1435 1460 1436 Collection<String> angles = Main.pref.getCollection("draw.anglesnap.angles", 1437 Arrays.asList("0", "30", "45", "60", "90", "120", "135", "150", "180")); 1438 1439 snapAngles = new double[2*angles.size()]; 1440 int i = 0; 1441 for (String s: angles) { 1442 try { 1443 snapAngles[i] = Double.parseDouble(s); i++; 1444 snapAngles[i] = 360-Double.parseDouble(s); i++; 1445 } catch (NumberFormatException e) { 1446 Main.warn("Incorrect number in draw.anglesnap.angles preferences: "+s); 1447 snapAngles[i] = 0; i++; 1448 snapAngles[i] = 0; i++; 1449 } 1450 } 1451 snapAngleTolerance = Main.pref.getDouble("draw.anglesnap.tolerance", 5.0); 1452 drawConstructionGeometry = Main.pref.getBoolean("draw.anglesnap.drawConstructionGeometry", true); 1453 showProjectedPoint = Main.pref.getBoolean("draw.anglesnap.drawProjectedPoint", true); 1454 snapToProjections = Main.pref.getBoolean("draw.anglesnap.projectionsnap", true); 1455 1456 showAngle = Main.pref.getBoolean("draw.anglesnap.showAngle", true); 1457 useRepeatedShortcut = Main.pref.getBoolean("draw.anglesnap.toggleOnRepeatedA", true); 1461 computeSnapAngles(); 1462 Main.pref.addWeakKeyPreferenceChangeListener(DRAW_ANGLESNAP_ANGLES, e -> this.computeSnapAngles()); 1463 } 1458 1464 1459 normalStroke = rubberLineStroke; 1460 snapHelperColor = new ColorProperty(marktr("draw angle snap"), Color.ORANGE).get(); 1465 private void computeSnapAngles() { 1466 snapAngles = Main.pref.getCollection(DRAW_ANGLESNAP_ANGLES, 1467 Arrays.asList("0", "30", "45", "60", "90", "120", "135", "150", "180")) 1468 .stream() 1469 .mapToDouble(this::parseSnapAngle) 1470 .flatMap(s -> DoubleStream.of(s, 360-s)) 1471 .toArray(); 1472 } 1461 1473 1462 highlightColor = new ColorProperty(marktr("draw angle snap highlight"), ORANGE_TRANSPARENT).get(); 1463 highlightStroke = GuiHelper.getCustomizedStroke(Main.pref.get("draw.anglesnap.stroke.highlight", "10")); 1464 helperStroke = GuiHelper.getCustomizedStroke(Main.pref.get("draw.anglesnap.stroke.helper", "1 4")); 1474 private double parseSnapAngle(String string) { 1475 try { 1476 return Double.parseDouble(string); 1477 } catch (NumberFormatException e) { 1478 Main.warn("Incorrect number in draw.anglesnap.angles preferences: {0}", string); 1479 return 0; 1480 } 1465 1481 } 1466 1482 1483 /** 1484 * Save the snap angles 1485 * @param angles The angles 1486 */ 1467 1487 public void saveAngles(String ... angles) { 1468 Main.pref.putCollection( "draw.anglesnap.angles", Arrays.asList(angles));1488 Main.pref.putCollection(DRAW_ANGLESNAP_ANGLES, Arrays.asList(angles)); 1469 1489 } 1470 1490 1471 1491 public void setMenuCheckBox(JCheckBoxMenuItem checkBox) { 1472 1492 this.checkBox = checkBox; 1473 1493 } 1474 1494 1475 public void drawIfNeeded(Graphics2D g2, MapView mv) { 1495 /** 1496 * Draw the snap hint line. 1497 * @param g2 1498 * @param mv 1499 */ 1500 public void drawIfNeeded(Graphics2D g2, MapViewState mv) { 1476 1501 if (!snapOn || !active) 1477 1502 return; 1478 MapViewPoint p1 = mv.get State().getPointFor(getCurrentBaseNode());1479 MapViewPoint p2 = mv.get State().getPointFor(dir2);1480 MapViewPoint p3 = mv.get State().getPointFor(projected);1481 if ( drawConstructionGeometry) {1482 g2.setColor( snapHelperColor);1483 g2.setStroke( helperStroke);1503 MapViewPoint p1 = mv.getPointFor(getCurrentBaseNode()); 1504 MapViewPoint p2 = mv.getPointFor(dir2); 1505 MapViewPoint p3 = mv.getPointFor(projected); 1506 if (DRAW_CONSTRUCTION_GEOMETRY.get()) { 1507 g2.setColor(SNAP_HELPER_COLOR.get()); 1508 g2.setStroke(HELPER_STROKE.get()); 1484 1509 1485 1510 MapPath2D b = new MapPath2D(); 1486 1511 b.moveTo(p2); 1487 1512 if (absoluteFix) { 1488 b.lineTo( 2d*p1.getInViewX()-p2.getInViewX(), 2d*p1.getInViewY()-p2.getInViewY()); // bi-directional line1513 b.lineTo(p2.interpolate(p1, 2)); // bi-directional line 1489 1514 } else { 1490 1515 b.lineTo(p3); 1491 1516 } 1492 1517 g2.draw(b); 1493 1518 } 1494 1519 if (projectionSource != null) { 1495 g2.setColor( snapHelperColor);1496 g2.setStroke( helperStroke);1520 g2.setColor(SNAP_HELPER_COLOR.get()); 1521 g2.setStroke(HELPER_STROKE.get()); 1497 1522 MapPath2D b = new MapPath2D(); 1498 1523 b.moveTo(p3); 1499 b.lineTo(mv.get State().getPointFor(projectionSource));1524 b.lineTo(mv.getPointFor(projectionSource)); 1500 1525 g2.draw(b); 1501 1526 } 1502 1527 1503 1528 if (customBaseHeading >= 0) { 1504 g2.setColor( highlightColor);1505 g2.setStroke( highlightStroke);1529 g2.setColor(HIGHLIGHT_COLOR.get()); 1530 g2.setStroke(HIGHLIGHT_STROKE.get()); 1506 1531 MapPath2D b = new MapPath2D(); 1507 b.moveTo(mv.get State().getPointFor(segmentPoint1));1508 b.lineTo(mv.get State().getPointFor(segmentPoint2));1532 b.moveTo(mv.getPointFor(segmentPoint1)); 1533 b.lineTo(mv.getPointFor(segmentPoint2)); 1509 1534 g2.draw(b); 1510 1535 } 1511 1536 1512 g2.setColor( rubberLineColor);1513 g2.setStroke( normalStroke);1537 g2.setColor(RUBBER_LINE_COLOR.get()); 1538 g2.setStroke(RUBBER_LINE_STROKE.get()); 1514 1539 MapPath2D b = new MapPath2D(); 1515 1540 b.moveTo(p1); 1516 1541 b.lineTo(p3); 1517 1542 g2.draw(b); 1518 1543 1519 1544 g2.drawString(labelText, (int) p3.getInViewX()-5, (int) p3.getInViewY()+20); 1520 if ( showProjectedPoint) {1521 g2.setStroke( normalStroke);1545 if (SHOW_PROJECTED_POINT.get()) { 1546 g2.setStroke(RUBBER_LINE_STROKE.get()); 1522 1547 g2.drawOval((int) p3.getInViewX()-5, (int) p3.getInViewY()-5, 10, 10); // projected point 1523 1548 } 1524 1549 1525 g2.setColor( snapHelperColor);1526 g2.setStroke( helperStroke);1550 g2.setColor(SNAP_HELPER_COLOR.get()); 1551 g2.setStroke(HELPER_STROKE.get()); 1527 1552 } 1528 1553 1529 /* If mouse position is close to line at 15-30-45-... angle, remembers this direction 1554 /** 1555 * If mouse position is close to line at 15-30-45-... angle, remembers this direction 1556 * @param currentEN Current position 1557 * @param baseHeading The heading 1558 * @param curHeading The current mouse heading 1530 1559 */ 1531 1560 public void checkAngleSnapping(EastNorth currentEN, double baseHeading, double curHeading) { 1532 1561 EastNorth p0 = getCurrentBaseNode().getEastNorth(); … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 1550 1579 active = true; 1551 1580 } else { 1552 1581 nearestAngle = getNearestAngle(angle); 1553 if (getAngleDelta(nearestAngle, angle) < snapAngleTolerance) {1582 if (getAngleDelta(nearestAngle, angle) < SNAP_ANGLE_TOLERANCE.get()) { 1554 1583 active = customBaseHeading >= 0 || Math.abs(nearestAngle - 180) > 1e-3; 1555 1584 // if angle is to previous segment, exclude 180 degrees 1556 1585 lastAngle = nearestAngle; … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 1596 1625 } 1597 1626 1598 1627 private void buildLabelText(double nearestAngle) { 1599 if ( showAngle) {1628 if (SHOW_ANGLE.get()) { 1600 1629 if (fixed) { 1601 1630 if (absoluteFix) { 1602 1631 labelText = "="; … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 1619 1648 } 1620 1649 } 1621 1650 1651 /** 1652 * Gets a snap point close to p. Stores the result for display. 1653 * @param p The point 1654 * @return The snap point close to p. 1655 */ 1622 1656 public EastNorth getSnapPoint(EastNorth p) { 1623 1657 if (!active) 1624 1658 return p; … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 1632 1666 } // do not go backward! 1633 1667 1634 1668 projectionSource = null; 1635 if ( snapToProjections) {1669 if (SNAP_TO_PROJECTIONS.get()) { 1636 1670 DataSet ds = getLayerManager().getEditDataSet(); 1637 1671 Collection<Way> selectedWays = ds.getSelectedWays(); 1638 1672 if (selectedWays.size() == 1) { … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 1667 1701 return projected; 1668 1702 } 1669 1703 1704 /** 1705 * Disables snapping 1706 */ 1670 1707 public void noSnapNow() { 1671 1708 active = false; 1672 1709 dir2 = null; … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 1690 1727 customBaseHeading = hdg; 1691 1728 } 1692 1729 1730 /** 1731 * Enable snapping. 1732 */ 1693 1733 private void enableSnapping() { 1694 1734 snapOn = true; 1695 1735 checkBox.setState(snapOn); … … public class DrawAction extends MapMode implements MapViewPaintable, SelectionCh 1726 1766 } 1727 1767 1728 1768 private double getNearestAngle(double angle) { 1729 double delta, minDelta = 1e5, bestAngle = 0.0; 1730 for (double snapAngle : snapAngles) { 1731 delta = getAngleDelta(angle, snapAngle); 1732 if (delta < minDelta) { 1733 minDelta = delta; 1734 bestAngle = snapAngle; 1735 } 1736 } 1769 double bestAngle = DoubleStream.of(snapAngles).boxed() 1770 .min(Comparator.comparing(snapAngle -> getAngleDelta(angle, snapAngle))).orElse(0.0); 1771 1737 1772 if (Math.abs(bestAngle-360) < 1e-3) { 1738 1773 bestAngle = 0; 1739 1774 } -
src/org/openstreetmap/josm/actions/mapmode/ParallelWayAction.java
diff --git a/src/org/openstreetmap/josm/actions/mapmode/ParallelWayAction.java b/src/org/openstreetmap/josm/actions/mapmode/ParallelWayAction.java index 68a0f6f..16f985f 100644
a b import static org.openstreetmap.josm.gui.help.HelpUtil.ht; 5 5 import static org.openstreetmap.josm.tools.I18n.marktr; 6 6 import static org.openstreetmap.josm.tools.I18n.tr; 7 7 8 import java.awt.BasicStroke; 8 9 import java.awt.Color; 9 10 import java.awt.Cursor; 10 11 import java.awt.Graphics2D; 11 12 import java.awt.Point; 12 import java.awt.Stroke;13 13 import java.awt.event.KeyEvent; 14 14 import java.awt.event.MouseEvent; 15 15 import java.util.Collection; … … import org.openstreetmap.josm.data.preferences.CachingProperty; 40 40 import org.openstreetmap.josm.data.preferences.ColorProperty; 41 41 import org.openstreetmap.josm.data.preferences.DoubleProperty; 42 42 import org.openstreetmap.josm.data.preferences.IntegerProperty; 43 import org.openstreetmap.josm.data.preferences.Str ingProperty;43 import org.openstreetmap.josm.data.preferences.StrokeProperty; 44 44 import org.openstreetmap.josm.gui.MapFrame; 45 45 import org.openstreetmap.josm.gui.MapView; 46 46 import org.openstreetmap.josm.gui.Notification; 47 47 import org.openstreetmap.josm.gui.layer.Layer; 48 48 import org.openstreetmap.josm.gui.layer.MapViewPaintable; 49 49 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 50 import org.openstreetmap.josm.gui.util.GuiHelper;51 50 import org.openstreetmap.josm.gui.util.ModifierListener; 52 51 import org.openstreetmap.josm.tools.CheckParameterUtil; 53 52 import org.openstreetmap.josm.tools.Geometry; … … import org.openstreetmap.josm.tools.Shortcut; 93 92 */ 94 93 public class ParallelWayAction extends MapMode implements ModifierListener, MapViewPaintable { 95 94 96 private static final StringProperty HELPER_LINE_STROKE = new StringProperty(prefKey("stroke.hepler-line"), "1");97 private static final StringProperty REF_LINE_STROKE = new StringProperty(prefKey("stroke.ref-line"), "1 2 2");95 private static final CachingProperty<BasicStroke> HELPER_LINE_STROKE = new StrokeProperty(prefKey("stroke.hepler-line"), "1").cached(); 96 private static final CachingProperty<BasicStroke> REF_LINE_STROKE = new StrokeProperty(prefKey("stroke.ref-line"), "2 2 3").cached(); 98 97 99 98 // @formatter:off 100 99 // CHECKSTYLE.OFF: SingleSpaceSeparator … … public class ParallelWayAction extends MapMode implements ModifierListener, MapV 146 145 private EastNorth helperLineStart; 147 146 private EastNorth helperLineEnd; 148 147 149 private transient Stroke helpLineStroke;150 private transient Stroke refLineStroke;151 152 148 /** 153 149 * Constructs a new {@code ParallelWayAction}. 154 150 * @param mapFrame Map frame … … public class ParallelWayAction extends MapMode implements ModifierListener, MapV 174 170 mv.addMouseMotionListener(this); 175 171 mv.addTemporaryLayer(this); 176 172 177 helpLineStroke = GuiHelper.getCustomizedStroke(HELPER_LINE_STROKE.get());178 refLineStroke = GuiHelper.getCustomizedStroke(REF_LINE_STROKE.get());179 180 173 //// Needed to update the mouse cursor if modifiers are changed when the mouse is motionless 181 174 Main.map.keyDetector.addModifierListener(this); 182 175 sourceWays = new LinkedHashSet<>(getLayerManager().getEditDataSet().getSelectedWays()); … … public class ParallelWayAction extends MapMode implements ModifierListener, MapV 472 465 } 473 466 474 467 // FIXME: should clip the line (gets insanely slow when zoomed in on a very long line 475 g.setStroke( refLineStroke);468 g.setStroke(REF_LINE_STROKE.get()); 476 469 g.setColor(mainColor); 477 470 MapPath2D line = new MapPath2D(); 478 471 line.moveTo(mv.getState().getPointFor(referenceSegment.getFirstNode())); 479 472 line.lineTo(mv.getState().getPointFor(referenceSegment.getSecondNode())); 480 473 g.draw(line); 481 474 482 g.setStroke( helpLineStroke);475 g.setStroke(HELPER_LINE_STROKE.get()); 483 476 g.setColor(mainColor); 484 477 line = new MapPath2D(); 485 478 line.moveTo(mv.getState().getPointFor(helperLineStart)); -
src/org/openstreetmap/josm/data/osm/visitor/paint/PaintColors.java
diff --git a/src/org/openstreetmap/josm/data/osm/visitor/paint/PaintColors.java b/src/org/openstreetmap/josm/data/osm/visitor/paint/PaintColors.java index 8f277b4..c5654e7 100644
a b public enum PaintColors { 33 33 34 34 private final String name; 35 35 private final Color defaultColor; 36 private final ColorProperty baseProperty; 36 37 private final CachingProperty<Color> property; 37 38 38 39 private static volatile Color backgroundColorCache; … … public enum PaintColors { 55 56 } 56 57 57 58 PaintColors(String name, Color defaultColor) { 58 property = new ColorProperty(name, defaultColor).cached(); 59 baseProperty = new ColorProperty(name, defaultColor); 60 property = baseProperty.cached(); 59 61 this.name = name; 60 62 this.defaultColor = defaultColor; 61 63 } … … public enum PaintColors { 95 97 return backgroundColorCache; 96 98 } 97 99 } 100 101 /** 102 * Get the color property 103 * @return The property that is used to access the color. 104 */ 105 public ColorProperty getProperty() { 106 return baseProperty; 107 } 98 108 } -
new file src/org/openstreetmap/josm/data/preferences/StrokeProperty.java
diff --git a/src/org/openstreetmap/josm/data/preferences/StrokeProperty.java b/src/org/openstreetmap/josm/data/preferences/StrokeProperty.java new file mode 100644 index 0000000..574c819
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.data.preferences; 3 4 import java.awt.BasicStroke; 5 import java.util.Collections; 6 import java.util.List; 7 import java.util.regex.Pattern; 8 import java.util.stream.Collectors; 9 10 import org.openstreetmap.josm.Main; 11 12 /** 13 * A property that stores a {@link BasicStroke} 14 * @author Michael Zangl 15 * @since xxx 16 */ 17 public class StrokeProperty extends AbstractToStringProperty<BasicStroke> { 18 19 /** 20 * Create a new stroke property from a string. 21 * @param key The key to use 22 * @param defaultValue The default stroke as string 23 */ 24 public StrokeProperty(String key, String defaultValue) { 25 super(key, getFromString(defaultValue)); 26 } 27 28 /** 29 * Create a new stroke property from a stroke object. 30 * @param key The key 31 * @param defaultStroke The default stroke. 32 */ 33 public StrokeProperty(String key, BasicStroke defaultStroke) { 34 super(key, defaultStroke); 35 } 36 37 @Override 38 protected BasicStroke fromString(String string) { 39 return getFromString(string); 40 } 41 42 @Override 43 protected String toString(BasicStroke t) { 44 StringBuilder string = new StringBuilder(); 45 string.append(t.getLineWidth()); 46 47 float[] dashes = t.getDashArray(); 48 if (dashes != null) { 49 for (float d : dashes) { 50 string.append(' ').append(d); 51 } 52 } 53 54 return string.toString(); 55 } 56 57 /** 58 * Return s new BasicStroke object with given thickness and style 59 * @param code = 3.5 -> thickness=3.5px; 3.5 10 5 -> thickness=3.5px, dashed: 10px filled + 5px empty 60 * @return stroke for drawing 61 */ 62 public static BasicStroke getFromString(String code) { 63 Pattern floatPattern = Pattern.compile("(\\.\\d+|\\d+(\\.\\d+)?)"); 64 65 List<Double> captures = Pattern.compile("[^\\d.]+").splitAsStream(code) 66 .filter(s -> floatPattern.matcher(s).matches()) 67 .map(Double::valueOf).collect(Collectors.toList()); 68 69 double w = 1; 70 List<Double> dashes = Collections.emptyList(); 71 if (!captures.isEmpty()) { 72 w = captures.get(0); 73 dashes = captures.subList(1, captures.size()); 74 } 75 76 if (!dashes.isEmpty()) { 77 double sumAbs = dashes.stream().mapToDouble(Math::abs).sum(); 78 79 if (sumAbs < 1e-1) { 80 Main.error("Error in stroke dash format (all zeros): " + code); 81 dashes = Collections.emptyList(); 82 } 83 } 84 85 int cap; 86 int join; 87 if (w > 1) { 88 // thick stroke 89 cap = BasicStroke.CAP_ROUND; 90 join = BasicStroke.JOIN_ROUND; 91 } else { 92 // thin stroke 93 cap = BasicStroke.CAP_BUTT; 94 join = BasicStroke.JOIN_MITER; 95 } 96 97 return new BasicStroke((float) w, cap, join, 10.0f, toDashArray(dashes), 0.0f); 98 } 99 100 private static float[] toDashArray(List<Double> dashes) { 101 if (dashes.isEmpty()) { 102 return null; 103 } else { 104 float[] array = new float[dashes.size()]; 105 for (int i = 0; i < array.length; i++) { 106 array[i] = (float) (double) dashes.get(i); 107 } 108 return array; 109 } 110 } 111 112 } -
src/org/openstreetmap/josm/gui/MapViewState.java
diff --git a/src/org/openstreetmap/josm/gui/MapViewState.java b/src/org/openstreetmap/josm/gui/MapViewState.java index 97e6037..9969eb0 100644
a b public final class MapViewState { 522 522 public double distanceToInView(MapViewPoint p2) { 523 523 return Math.sqrt(distanceToInViewSq(p2)); 524 524 } 525 526 /** 527 * Do a linear interpolation to the other point 528 * @param p1 The other point 529 * @param i The interpolation factor. 0 is at the current point, 1 at the other point. 530 * @return The new point 531 */ 532 public MapViewPoint interpolate(MapViewPoint p1, int i) { 533 return new MapViewViewPoint((1 - i) * getInViewX() + i * p1.getInViewX(), (1 - i) * getInViewY() + i * p1.getInViewY()); 534 } 525 535 } 526 536 527 537 private class MapViewViewPoint extends MapViewPoint { -
src/org/openstreetmap/josm/gui/util/GuiHelper.java
diff --git a/src/org/openstreetmap/josm/gui/util/GuiHelper.java b/src/org/openstreetmap/josm/gui/util/GuiHelper.java index d964701..9f59dc3 100644
a b package org.openstreetmap.josm.gui.util; 3 3 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 import java.awt.BasicStroke;7 6 import java.awt.Color; 8 7 import java.awt.Component; 9 8 import java.awt.Container; … … import javax.swing.UIManager; 49 48 import javax.swing.plaf.FontUIResource; 50 49 51 50 import org.openstreetmap.josm.Main; 51 import org.openstreetmap.josm.data.preferences.StrokeProperty; 52 52 import org.openstreetmap.josm.gui.ExtendedDialog; 53 53 import org.openstreetmap.josm.gui.widgets.HtmlPanel; 54 54 import org.openstreetmap.josm.tools.CheckParameterUtil; … … public final class GuiHelper { 299 299 * Return s new BasicStroke object with given thickness and style 300 300 * @param code = 3.5 -> thickness=3.5px; 3.5 10 5 -> thickness=3.5px, dashed: 10px filled + 5px empty 301 301 * @return stroke for drawing 302 * @see StrokeProperty 302 303 */ 303 304 public static Stroke getCustomizedStroke(String code) { 304 String[] s = code.trim().split("[^\\.0-9]+"); 305 306 if (s.length == 0) return new BasicStroke(); 307 float w; 308 try { 309 w = Float.parseFloat(s[0]); 310 } catch (NumberFormatException ex) { 311 w = 1.0f; 312 } 313 if (s.length > 1) { 314 float[] dash = new float[s.length-1]; 315 float sumAbs = 0; 316 try { 317 for (int i = 0; i < s.length-1; i++) { 318 dash[i] = Float.parseFloat(s[i+1]); 319 sumAbs += Math.abs(dash[i]); 320 } 321 } catch (NumberFormatException ex) { 322 Main.error("Error in stroke preference format: "+code); 323 dash = new float[]{5.0f}; 324 } 325 if (sumAbs < 1e-1) { 326 Main.error("Error in stroke dash format (all zeros): "+code); 327 return new BasicStroke(w); 328 } 329 // dashed stroke 330 return new BasicStroke(w, BasicStroke.CAP_BUTT, 331 BasicStroke.JOIN_MITER, 10.0f, dash, 0.0f); 332 } else { 333 if (w > 1) { 334 // thick stroke 335 return new BasicStroke(w, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); 336 } else { 337 // thin stroke 338 return new BasicStroke(w); 339 } 340 } 305 return StrokeProperty.getFromString(code); 341 306 } 342 307 343 308 /** -
new file test/unit/org/openstreetmap/josm/data/preferences/StrokePropertyTest.java
diff --git a/test/unit/org/openstreetmap/josm/data/preferences/StrokePropertyTest.java b/test/unit/org/openstreetmap/josm/data/preferences/StrokePropertyTest.java new file mode 100644 index 0000000..ba7e68b
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.data.preferences; 3 4 import static org.junit.Assert.assertArrayEquals; 5 import static org.junit.Assert.assertEquals; 6 7 import java.awt.BasicStroke; 8 9 import org.junit.Rule; 10 import org.junit.Test; 11 import org.openstreetmap.josm.Main; 12 import org.openstreetmap.josm.testutils.JOSMTestRules; 13 14 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 15 16 /** 17 * Test {@link StrokeProperty} 18 * @author Michael Zangl 19 * @since xxx 20 */ 21 public class StrokePropertyTest { 22 /** 23 * This is a preference test 24 */ 25 @Rule 26 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") 27 public JOSMTestRules test = new JOSMTestRules().preferences(); 28 29 /** 30 * Test {@link StrokeProperty#get()} 31 */ 32 @Test 33 public void testGetValue() { 34 StrokeProperty property = new StrokeProperty("x", "1"); 35 36 Main.pref.put("x", "11"); 37 BasicStroke bs = property.get(); 38 assertWide(bs); 39 assertEquals(11, bs.getLineWidth(), 1e-10); 40 assertEquals(null, bs.getDashArray()); 41 42 Main.pref.put("x", ".5"); 43 bs = property.get(); 44 assertThin(bs); 45 assertEquals(.5, bs.getLineWidth(), 1e-10); 46 assertEquals(null, bs.getDashArray()); 47 48 Main.pref.put("x", "2 1"); 49 bs = property.get(); 50 assertWide(bs); 51 assertEquals(2, bs.getLineWidth(), 1e-10); 52 assertArrayEquals(new float[] {1}, bs.getDashArray(), 1e-10f); 53 54 Main.pref.put("x", "2 0.1 1 10"); 55 bs = property.get(); 56 assertWide(bs); 57 assertEquals(2, bs.getLineWidth(), 1e-10); 58 assertArrayEquals(new float[] {0.1f, 1, 10}, bs.getDashArray(), 1e-10f); 59 60 Main.pref.put("x", "x"); 61 bs = property.get(); 62 assertThin(bs); 63 assertEquals(1, bs.getLineWidth(), 1e-10); 64 assertEquals(null, bs.getDashArray()); 65 66 // ignore dashes 67 Main.pref.put("x", "11 0 0 0.0001"); 68 bs = property.get(); 69 assertWide(bs); 70 assertEquals(11, bs.getLineWidth(), 1e-10); 71 assertEquals(null, bs.getDashArray()); 72 } 73 74 /** 75 * Test {@link StrokeProperty#put(BasicStroke)} 76 */ 77 @Test 78 public void testPutValue() { 79 StrokeProperty property = new StrokeProperty("x", new BasicStroke(12)); 80 BasicStroke bs = property.get(); 81 82 assertWide(bs); 83 assertEquals(12, bs.getLineWidth(), 1e-10); 84 assertEquals(null, bs.getDashArray()); 85 86 property.put(new BasicStroke(2, 0, 0, 1, new float[] {0.1f, 1, 10}, 0)); 87 bs = property.get(); 88 assertWide(bs); 89 assertEquals(2, bs.getLineWidth(), 1e-10); 90 assertArrayEquals(new float[] {0.1f, 1, 10}, bs.getDashArray(), 1e-10f); 91 } 92 93 private void assertThin(BasicStroke bs) { 94 assertBase(bs); 95 assertEquals(BasicStroke.CAP_BUTT, bs.getEndCap()); 96 assertEquals(BasicStroke.JOIN_MITER, bs.getLineJoin()); 97 } 98 99 private void assertWide(BasicStroke bs) { 100 assertBase(bs); 101 assertEquals(BasicStroke.CAP_ROUND, bs.getEndCap()); 102 assertEquals(BasicStroke.JOIN_ROUND, bs.getLineJoin()); 103 } 104 105 private void assertBase(BasicStroke bs) { 106 assertEquals(10, bs.getMiterLimit(), 1e-10); 107 assertEquals(0, bs.getDashPhase(), 1e-10); 108 } 109 }