From faadcb49231b0a639a0e1e47783423381b8c9022 Mon Sep 17 00:00:00 2001
From: Michael Zangl <michael.zangl@student.kit.edu>
Date: Thu, 6 Aug 2015 14:02:04 +0200
Subject: [PATCH 1/3] Revert "Temporary fix lockups on data layer removal when
Validation layer is present"
This reverts commit f3f0ab13d3c24ceb75494616fb4fbb187dc1eac0.
---
src/org/openstreetmap/josm/gui/MapView.java | 220 +++++++++++++++++++---------
1 file changed, 154 insertions(+), 66 deletions(-)
diff --git a/src/org/openstreetmap/josm/gui/MapView.java b/src/org/openstreetmap/josm/gui/MapView.java
index bbe824a..ef6d0e8 100644
|
a
|
b
|
import java.util.List;
|
| 31 | 31 | import java.util.ListIterator; |
| 32 | 32 | import java.util.Set; |
| 33 | 33 | import java.util.concurrent.CopyOnWriteArrayList; |
| | 34 | import java.util.concurrent.locks.ReentrantReadWriteLock; |
| 34 | 35 | |
| 35 | 36 | import javax.swing.AbstractButton; |
| 36 | 37 | import javax.swing.ActionMap; |
| … |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
| 200 | 201 | * @param newLayer The new active layer. |
| 201 | 202 | */ |
| 202 | 203 | protected void fireActiveLayerChanged(Layer oldLayer, Layer newLayer) { |
| | 204 | checkLayerLockNotHeld(); |
| 203 | 205 | for (LayerChangeListener l : layerChangeListeners) { |
| 204 | 206 | l.activeLayerChange(oldLayer, newLayer); |
| 205 | 207 | } |
| 206 | 208 | } |
| 207 | 209 | |
| 208 | 210 | protected void fireLayerAdded(Layer newLayer) { |
| | 211 | checkLayerLockNotHeld(); |
| 209 | 212 | for (MapView.LayerChangeListener l : MapView.layerChangeListeners) { |
| 210 | 213 | l.layerAdded(newLayer); |
| 211 | 214 | } |
| 212 | 215 | } |
| 213 | 216 | |
| 214 | 217 | protected void fireLayerRemoved(Layer layer) { |
| | 218 | checkLayerLockNotHeld(); |
| 215 | 219 | for (MapView.LayerChangeListener l : MapView.layerChangeListeners) { |
| 216 | 220 | l.layerRemoved(layer); |
| 217 | 221 | } |
| 218 | 222 | } |
| 219 | 223 | |
| 220 | 224 | protected void fireEditLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) { |
| | 225 | checkLayerLockNotHeld(); |
| 221 | 226 | for (EditLayerChangeListener l : editLayerChangeListeners) { |
| 222 | 227 | l.editLayerChanged(oldLayer, newLayer); |
| 223 | 228 | } |
| 224 | 229 | } |
| 225 | 230 | |
| 226 | 231 | /** |
| | 232 | * This is a simple invariant check that tests if the {@link #layerLock} is not write locked. |
| | 233 | * This should be the case whenever a layer listener is invoked. |
| | 234 | */ |
| | 235 | private void checkLayerLockNotHeld() { |
| | 236 | if (layerLock.isWriteLockedByCurrentThread()) { |
| | 237 | Main.warn("layerLock is write-held while a listener was called."); |
| | 238 | } |
| | 239 | } |
| | 240 | |
| | 241 | /** |
| 227 | 242 | * A list of all layers currently loaded. Locked by {@link #layerLock}. |
| 228 | 243 | */ |
| 229 | 244 | private final transient List<Layer> layers = new ArrayList<>(); |
| … |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
| 234 | 249 | * <p> |
| 235 | 250 | * The read lock is always held while those fields are read or while layer change listeners are fired. |
| 236 | 251 | */ |
| 237 | | //private final ReentrantReadWriteLock layerLock = new ReentrantReadWriteLock(); |
| | 252 | private final ReentrantReadWriteLock layerLock = new ReentrantReadWriteLock(); |
| 238 | 253 | |
| 239 | 254 | /** |
| 240 | 255 | * The play head marker: there is only one of these so it isn't in any specific layer |
| … |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
| 360 | 375 | * @param layer the GPX layer |
| 361 | 376 | */ |
| 362 | 377 | protected void addGpxLayer(GpxLayer layer) { |
| 363 | | synchronized (layers) { |
| | 378 | layerLock.writeLock().lock(); |
| | 379 | try { |
| 364 | 380 | if (layers.isEmpty()) { |
| 365 | 381 | layers.add(layer); |
| 366 | 382 | return; |
| … |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
| 376 | 392 | } |
| 377 | 393 | } |
| 378 | 394 | layers.add(0, layer); |
| | 395 | } finally { |
| | 396 | layerLock.writeLock().unlock(); |
| 379 | 397 | } |
| 380 | 398 | } |
| 381 | 399 | |
| … |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
| 390 | 408 | Layer oldActiveLayer = activeLayer; |
| 391 | 409 | OsmDataLayer oldEditLayer = editLayer; |
| 392 | 410 | |
| 393 | | synchronized (layers) { |
| 394 | | if (layer instanceof MarkerLayer && playHeadMarker == null) { |
| 395 | | playHeadMarker = PlayHeadMarker.create(); |
| 396 | | } |
| | 411 | layerLock.writeLock().lock(); |
| | 412 | layerLock.readLock().lock(); |
| | 413 | try { |
| | 414 | try { |
| | 415 | if (layer instanceof MarkerLayer && playHeadMarker == null) { |
| | 416 | playHeadMarker = PlayHeadMarker.create(); |
| | 417 | } |
| 397 | 418 | |
| 398 | | if (layer instanceof GpxLayer) { |
| 399 | | addGpxLayer((GpxLayer) layer); |
| 400 | | } else if (layers.isEmpty()) { |
| 401 | | layers.add(layer); |
| 402 | | } else if (layer.isBackgroundLayer()) { |
| 403 | | int i = 0; |
| 404 | | for (; i < layers.size(); i++) { |
| 405 | | if (layers.get(i).isBackgroundLayer()) { |
| 406 | | break; |
| | 419 | if (layer instanceof GpxLayer) { |
| | 420 | addGpxLayer((GpxLayer) layer); |
| | 421 | } else if (layers.isEmpty()) { |
| | 422 | layers.add(layer); |
| | 423 | } else if (layer.isBackgroundLayer()) { |
| | 424 | int i = 0; |
| | 425 | for (; i < layers.size(); i++) { |
| | 426 | if (layers.get(i).isBackgroundLayer()) { |
| | 427 | break; |
| | 428 | } |
| 407 | 429 | } |
| | 430 | layers.add(i, layer); |
| | 431 | } else { |
| | 432 | layers.add(0, layer); |
| 408 | 433 | } |
| 409 | | layers.add(i, layer); |
| 410 | | } else { |
| 411 | | layers.add(0, layer); |
| 412 | | } |
| 413 | 434 | |
| 414 | | if (isOsmDataLayer || oldActiveLayer == null) { |
| 415 | | // autoselect the new layer |
| 416 | | listenersToFire.addAll(setActiveLayer(layer, true)); |
| | 435 | if (isOsmDataLayer || oldActiveLayer == null) { |
| | 436 | // autoselect the new layer |
| | 437 | listenersToFire.addAll(setActiveLayer(layer, true)); |
| | 438 | } |
| | 439 | } finally { |
| | 440 | layerLock.writeLock().unlock(); |
| 417 | 441 | } |
| 418 | 442 | |
| 419 | 443 | fireLayerAdded(layer); |
| … |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
| 424 | 448 | layer.addPropertyChangeListener(this); |
| 425 | 449 | Main.addProjectionChangeListener(layer); |
| 426 | 450 | AudioPlayer.reset(); |
| | 451 | } finally { |
| | 452 | layerLock.readLock().unlock(); |
| 427 | 453 | } |
| 428 | 454 | if (!listenersToFire.isEmpty()) { |
| 429 | 455 | repaint(); |
| … |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
| 432 | 458 | |
| 433 | 459 | @Override |
| 434 | 460 | protected DataSet getCurrentDataSet() { |
| 435 | | synchronized (layers) { |
| | 461 | layerLock.readLock().lock(); |
| | 462 | try { |
| 436 | 463 | if (editLayer != null) |
| 437 | 464 | return editLayer.data; |
| 438 | 465 | else |
| 439 | 466 | return null; |
| | 467 | } finally { |
| | 468 | layerLock.readLock().unlock(); |
| 440 | 469 | } |
| 441 | 470 | } |
| 442 | 471 | |
| … |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
| 446 | 475 | * @return true if the active data layer (edit layer) is drawable, false otherwise |
| 447 | 476 | */ |
| 448 | 477 | public boolean isActiveLayerDrawable() { |
| 449 | | synchronized (layers) { |
| | 478 | layerLock.readLock().lock(); |
| | 479 | try { |
| 450 | 480 | return editLayer != null; |
| | 481 | } finally { |
| | 482 | layerLock.readLock().unlock(); |
| 451 | 483 | } |
| 452 | 484 | } |
| 453 | 485 | |
| … |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
| 457 | 489 | * @return true if the active data layer (edit layer) is visible, false otherwise |
| 458 | 490 | */ |
| 459 | 491 | public boolean isActiveLayerVisible() { |
| 460 | | synchronized (layers) { |
| | 492 | layerLock.readLock().lock(); |
| | 493 | try { |
| 461 | 494 | return isActiveLayerDrawable() && editLayer.isVisible(); |
| | 495 | } finally { |
| | 496 | layerLock.readLock().unlock(); |
| 462 | 497 | } |
| 463 | 498 | } |
| 464 | 499 | |
| … |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
| 499 | 534 | Layer oldActiveLayer = activeLayer; |
| 500 | 535 | OsmDataLayer oldEditLayer = editLayer; |
| 501 | 536 | |
| 502 | | synchronized (layers) { |
| 503 | | List<Layer> layersList = new ArrayList<>(layers); |
| | 537 | layerLock.writeLock().lock(); |
| | 538 | layerLock.readLock().lock(); |
| | 539 | try { |
| | 540 | try { |
| | 541 | List<Layer> layersList = new ArrayList<>(layers); |
| 504 | 542 | |
| 505 | | if (!layersList.remove(layer)) |
| 506 | | return; |
| | 543 | if (!layersList.remove(layer)) |
| | 544 | return; |
| 507 | 545 | |
| 508 | | listenersToFire = setEditLayer(layersList); |
| | 546 | listenersToFire = setEditLayer(layersList); |
| 509 | 547 | |
| 510 | | if (layer == activeLayer) { |
| 511 | | listenersToFire.addAll(setActiveLayer(determineNextActiveLayer(layersList), false)); |
| 512 | | } |
| | 548 | if (layer == activeLayer) { |
| | 549 | listenersToFire.addAll(setActiveLayer(determineNextActiveLayer(layersList), false)); |
| | 550 | } |
| 513 | 551 | |
| 514 | | if (layer instanceof OsmDataLayer) { |
| 515 | | ((OsmDataLayer) layer).removeLayerPropertyChangeListener(this); |
| 516 | | } |
| | 552 | if (layer instanceof OsmDataLayer) { |
| | 553 | ((OsmDataLayer) layer).removeLayerPropertyChangeListener(this); |
| | 554 | } |
| 517 | 555 | |
| 518 | | layers.remove(layer); |
| 519 | | Main.removeProjectionChangeListener(layer); |
| | 556 | layers.remove(layer); |
| | 557 | Main.removeProjectionChangeListener(layer); |
| 520 | 558 | |
| | 559 | } finally { |
| | 560 | layerLock.writeLock().unlock(); |
| | 561 | } |
| 521 | 562 | onActiveEditLayerChanged(oldActiveLayer, oldEditLayer, listenersToFire); |
| 522 | 563 | fireLayerRemoved(layer); |
| 523 | 564 | layer.removePropertyChangeListener(this); |
| 524 | 565 | layer.destroy(); |
| 525 | 566 | AudioPlayer.reset(); |
| | 567 | } finally { |
| | 568 | layerLock.readLock().unlock(); |
| 526 | 569 | } |
| 527 | 570 | repaint(); |
| 528 | 571 | } |
| … |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
| 562 | 605 | Layer oldActiveLayer = activeLayer; |
| 563 | 606 | OsmDataLayer oldEditLayer = editLayer; |
| 564 | 607 | |
| 565 | | synchronized (layers) { |
| 566 | | int curLayerPos = layers.indexOf(layer); |
| 567 | | if (curLayerPos == -1) |
| 568 | | throw new IllegalArgumentException(tr("Layer not in list.")); |
| 569 | | if (pos == curLayerPos) |
| 570 | | return; // already in place. |
| 571 | | layers.remove(curLayerPos); |
| 572 | | if (pos >= layers.size()) { |
| 573 | | layers.add(layer); |
| 574 | | } else { |
| 575 | | layers.add(pos, layer); |
| | 608 | layerLock.writeLock().lock(); |
| | 609 | layerLock.readLock().lock(); |
| | 610 | try { |
| | 611 | try { |
| | 612 | int curLayerPos = layers.indexOf(layer); |
| | 613 | if (curLayerPos == -1) |
| | 614 | throw new IllegalArgumentException(tr("Layer not in list.")); |
| | 615 | if (pos == curLayerPos) |
| | 616 | return; // already in place. |
| | 617 | layers.remove(curLayerPos); |
| | 618 | if (pos >= layers.size()) { |
| | 619 | layers.add(layer); |
| | 620 | } else { |
| | 621 | layers.add(pos, layer); |
| | 622 | } |
| | 623 | listenersToFire = setEditLayer(layers); |
| | 624 | } finally { |
| | 625 | layerLock.writeLock().unlock(); |
| 576 | 626 | } |
| 577 | | listenersToFire = setEditLayer(layers); |
| 578 | 627 | onActiveEditLayerChanged(oldActiveLayer, oldEditLayer, listenersToFire); |
| 579 | 628 | AudioPlayer.reset(); |
| | 629 | } finally { |
| | 630 | layerLock.readLock().unlock(); |
| 580 | 631 | } |
| 581 | 632 | repaint(); |
| 582 | 633 | } |
| … |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
| 589 | 640 | */ |
| 590 | 641 | public int getLayerPos(Layer layer) { |
| 591 | 642 | int curLayerPos; |
| 592 | | synchronized (layers) { |
| | 643 | layerLock.readLock().lock(); |
| | 644 | try { |
| 593 | 645 | curLayerPos = layers.indexOf(layer); |
| | 646 | } finally { |
| | 647 | layerLock.readLock().unlock(); |
| 594 | 648 | } |
| 595 | 649 | if (curLayerPos == -1) |
| 596 | 650 | throw new IllegalArgumentException(tr("Layer not in list.")); |
| … |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
| 607 | 661 | * first, layer with the highest Z-Order last. |
| 608 | 662 | */ |
| 609 | 663 | public List<Layer> getVisibleLayersInZOrder() { |
| 610 | | synchronized (layers) { |
| | 664 | layerLock.readLock().lock(); |
| | 665 | try { |
| 611 | 666 | List<Layer> ret = new ArrayList<>(); |
| 612 | 667 | // This is set while we delay the addition of the active layer. |
| 613 | 668 | boolean activeLayerDelayed = false; |
| … |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
| 632 | 687 | ret.add(activeLayer); |
| 633 | 688 | } |
| 634 | 689 | return ret; |
| | 690 | } finally { |
| | 691 | layerLock.readLock().unlock(); |
| 635 | 692 | } |
| 636 | 693 | } |
| 637 | 694 | |
| … |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
| 820 | 877 | * @return An unmodifiable collection of all layers |
| 821 | 878 | */ |
| 822 | 879 | public Collection<Layer> getAllLayers() { |
| 823 | | synchronized (layers) { |
| | 880 | layerLock.readLock().lock(); |
| | 881 | try { |
| 824 | 882 | return Collections.unmodifiableCollection(new ArrayList<>(layers)); |
| | 883 | } finally { |
| | 884 | layerLock.readLock().unlock(); |
| 825 | 885 | } |
| 826 | 886 | } |
| 827 | 887 | |
| … |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
| 829 | 889 | * @return An unmodifiable ordered list of all layers |
| 830 | 890 | */ |
| 831 | 891 | public List<Layer> getAllLayersAsList() { |
| 832 | | synchronized (layers) { |
| | 892 | layerLock.readLock().lock(); |
| | 893 | try { |
| 833 | 894 | return Collections.unmodifiableList(new ArrayList<>(layers)); |
| | 895 | } finally { |
| | 896 | layerLock.readLock().unlock(); |
| 834 | 897 | } |
| 835 | 898 | } |
| 836 | 899 | |
| … |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
| 855 | 918 | * @return the number of layers managed by this map view |
| 856 | 919 | */ |
| 857 | 920 | public int getNumLayers() { |
| 858 | | synchronized (layers) { |
| | 921 | layerLock.readLock().lock(); |
| | 922 | try { |
| 859 | 923 | return layers.size(); |
| | 924 | } finally { |
| | 925 | layerLock.readLock().unlock(); |
| 860 | 926 | } |
| 861 | 927 | } |
| 862 | 928 | |
| … |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
| 920 | 986 | * @throws IllegalArgumentException if layer is not in the lis of layers |
| 921 | 987 | */ |
| 922 | 988 | public void setActiveLayer(Layer layer) { |
| | 989 | layerLock.writeLock().lock(); |
| | 990 | layerLock.readLock().lock(); |
| 923 | 991 | EnumSet<LayerListenerType> listenersToFire; |
| 924 | | |
| 925 | | synchronized (layers) { |
| 926 | | Layer oldActiveLayer = activeLayer; |
| 927 | | OsmDataLayer oldEditLayer = editLayer; |
| 928 | | listenersToFire = setActiveLayer(layer, true); |
| | 992 | Layer oldActiveLayer = activeLayer; |
| | 993 | OsmDataLayer oldEditLayer = editLayer; |
| | 994 | try { |
| | 995 | try { |
| | 996 | listenersToFire = setActiveLayer(layer, true); |
| | 997 | } finally { |
| | 998 | layerLock.writeLock().unlock(); |
| | 999 | } |
| 929 | 1000 | onActiveEditLayerChanged(oldActiveLayer, oldEditLayer, listenersToFire); |
| | 1001 | } finally { |
| | 1002 | layerLock.readLock().unlock(); |
| 930 | 1003 | } |
| 931 | 1004 | repaint(); |
| 932 | 1005 | } |
| … |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
| 959 | 1032 | * @return the currently active layer (may be null) |
| 960 | 1033 | */ |
| 961 | 1034 | public Layer getActiveLayer() { |
| 962 | | synchronized (layers) { |
| | 1035 | layerLock.readLock().lock(); |
| | 1036 | try { |
| 963 | 1037 | return activeLayer; |
| | 1038 | } finally { |
| | 1039 | layerLock.readLock().unlock(); |
| 964 | 1040 | } |
| 965 | 1041 | } |
| 966 | 1042 | |
| … |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
| 1015 | 1091 | * @return the current edit layer. May be null. |
| 1016 | 1092 | */ |
| 1017 | 1093 | public OsmDataLayer getEditLayer() { |
| 1018 | | synchronized (layers) { |
| | 1094 | layerLock.readLock().lock(); |
| | 1095 | try { |
| 1019 | 1096 | return editLayer; |
| | 1097 | } finally { |
| | 1098 | layerLock.readLock().unlock(); |
| 1020 | 1099 | } |
| 1021 | 1100 | } |
| 1022 | 1101 | |
| … |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
| 1027 | 1106 | * @return true if the list of layers managed by this map view contain layer |
| 1028 | 1107 | */ |
| 1029 | 1108 | public boolean hasLayer(Layer layer) { |
| 1030 | | synchronized (layers) { |
| | 1109 | layerLock.readLock().lock(); |
| | 1110 | try { |
| 1031 | 1111 | return layers.contains(layer); |
| | 1112 | } finally { |
| | 1113 | layerLock.readLock().unlock(); |
| 1032 | 1114 | } |
| 1033 | 1115 | } |
| 1034 | 1116 | |
| … |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
| 1093 | 1175 | */ |
| 1094 | 1176 | protected void refreshTitle() { |
| 1095 | 1177 | if (Main.parent != null) { |
| 1096 | | synchronized (layers) { |
| | 1178 | layerLock.readLock().lock(); |
| | 1179 | try { |
| 1097 | 1180 | boolean dirty = editLayer != null && |
| 1098 | 1181 | (editLayer.requiresSaveToFile() || (editLayer.requiresUploadToServer() && !editLayer.isUploadDiscouraged())); |
| 1099 | 1182 | ((JFrame) Main.parent).setTitle((dirty ? "* " : "") + tr("Java OpenStreetMap Editor")); |
| 1100 | 1183 | ((JFrame) Main.parent).getRootPane().putClientProperty("Window.documentModified", dirty); |
| | 1184 | } finally { |
| | 1185 | layerLock.readLock().unlock(); |
| 1101 | 1186 | } |
| 1102 | 1187 | } |
| 1103 | 1188 | } |
| … |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
| 1123 | 1208 | if (mapMover != null) { |
| 1124 | 1209 | mapMover.destroy(); |
| 1125 | 1210 | } |
| 1126 | | synchronized (layers) { |
| | 1211 | layerLock.writeLock().lock(); |
| | 1212 | try { |
| 1127 | 1213 | activeLayer = null; |
| 1128 | 1214 | changedLayer = null; |
| 1129 | 1215 | editLayer = null; |
| 1130 | 1216 | layers.clear(); |
| 1131 | | nonChangedLayers.clear(); |
| | 1217 | } finally { |
| | 1218 | layerLock.writeLock().unlock(); |
| 1132 | 1219 | } |
| | 1220 | nonChangedLayers.clear(); |
| 1133 | 1221 | synchronized (temporaryLayers) { |
| 1134 | 1222 | temporaryLayers.clear(); |
| 1135 | 1223 | } |