001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.dialogs; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.BorderLayout; 007import java.awt.Component; 008import java.awt.event.ActionEvent; 009import java.awt.event.KeyEvent; 010import java.awt.event.MouseEvent; 011import java.util.ArrayList; 012import java.util.Arrays; 013import java.util.Collection; 014import java.util.Collections; 015import java.util.HashSet; 016import java.util.List; 017import java.util.Set; 018 019import javax.swing.AbstractAction; 020import javax.swing.AbstractListModel; 021import javax.swing.DefaultListSelectionModel; 022import javax.swing.FocusManager; 023import javax.swing.JComponent; 024import javax.swing.JList; 025import javax.swing.JMenuItem; 026import javax.swing.JPanel; 027import javax.swing.JPopupMenu; 028import javax.swing.JScrollPane; 029import javax.swing.KeyStroke; 030import javax.swing.ListSelectionModel; 031 032import org.openstreetmap.josm.Main; 033import org.openstreetmap.josm.actions.ExpertToggleAction; 034import org.openstreetmap.josm.actions.relation.AddSelectionToRelations; 035import org.openstreetmap.josm.actions.relation.DeleteRelationsAction; 036import org.openstreetmap.josm.actions.relation.DownloadMembersAction; 037import org.openstreetmap.josm.actions.relation.DownloadSelectedIncompleteMembersAction; 038import org.openstreetmap.josm.actions.relation.DuplicateRelationAction; 039import org.openstreetmap.josm.actions.relation.EditRelationAction; 040import org.openstreetmap.josm.actions.relation.RecentRelationsAction; 041import org.openstreetmap.josm.actions.relation.SelectMembersAction; 042import org.openstreetmap.josm.actions.relation.SelectRelationAction; 043import org.openstreetmap.josm.actions.search.SearchCompiler; 044import org.openstreetmap.josm.data.osm.DataSet; 045import org.openstreetmap.josm.data.osm.OsmPrimitive; 046import org.openstreetmap.josm.data.osm.Relation; 047import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent; 048import org.openstreetmap.josm.data.osm.event.DataChangedEvent; 049import org.openstreetmap.josm.data.osm.event.DataSetListener; 050import org.openstreetmap.josm.data.osm.event.DatasetEventManager; 051import org.openstreetmap.josm.data.osm.event.DatasetEventManager.FireMode; 052import org.openstreetmap.josm.data.osm.event.NodeMovedEvent; 053import org.openstreetmap.josm.data.osm.event.PrimitivesAddedEvent; 054import org.openstreetmap.josm.data.osm.event.PrimitivesRemovedEvent; 055import org.openstreetmap.josm.data.osm.event.RelationMembersChangedEvent; 056import org.openstreetmap.josm.data.osm.event.TagsChangedEvent; 057import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent; 058import org.openstreetmap.josm.gui.DefaultNameFormatter; 059import org.openstreetmap.josm.gui.MapView; 060import org.openstreetmap.josm.gui.NavigatableComponent; 061import org.openstreetmap.josm.gui.OsmPrimitivRenderer; 062import org.openstreetmap.josm.gui.PopupMenuHandler; 063import org.openstreetmap.josm.gui.SideButton; 064import org.openstreetmap.josm.gui.dialogs.relation.RelationEditor; 065import org.openstreetmap.josm.gui.layer.Layer; 066import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent; 067import org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener; 068import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent; 069import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent; 070import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeEvent; 071import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener; 072import org.openstreetmap.josm.gui.layer.OsmDataLayer; 073import org.openstreetmap.josm.gui.util.GuiHelper; 074import org.openstreetmap.josm.gui.util.HighlightHelper; 075import org.openstreetmap.josm.gui.widgets.CompileSearchTextDecorator; 076import org.openstreetmap.josm.gui.widgets.DisableShortcutsOnFocusGainedTextField; 077import org.openstreetmap.josm.gui.widgets.JosmTextField; 078import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher; 079import org.openstreetmap.josm.tools.ImageProvider; 080import org.openstreetmap.josm.tools.InputMapUtils; 081import org.openstreetmap.josm.tools.Shortcut; 082import org.openstreetmap.josm.tools.SubclassFilteredCollection; 083 084/** 085 * A dialog showing all known relations, with buttons to add, edit, and delete them. 086 * 087 * We don't have such dialogs for nodes, segments, and ways, because those 088 * objects are visible on the map and can be selected there. Relations are not. 089 */ 090public class RelationListDialog extends ToggleDialog 091 implements DataSetListener, NavigatableComponent.ZoomChangeListener, ExpertToggleAction.ExpertModeChangeListener { 092 /** The display list. */ 093 private final JList<Relation> displaylist; 094 /** the list model used */ 095 private final RelationListModel model; 096 097 private final NewAction newAction; 098 099 /** the popup menu and its handler */ 100 private final JPopupMenu popupMenu = new JPopupMenu(); 101 private final transient PopupMenuHandler popupMenuHandler = new PopupMenuHandler(popupMenu); 102 103 private final JosmTextField filter; 104 105 // Actions 106 /** the edit action */ 107 private final EditRelationAction editAction = new EditRelationAction(); 108 /** the delete action */ 109 private final DeleteRelationsAction deleteRelationsAction = new DeleteRelationsAction(); 110 /** the duplicate action */ 111 private final DuplicateRelationAction duplicateAction = new DuplicateRelationAction(); 112 private final DownloadMembersAction downloadMembersAction = new DownloadMembersAction(); 113 private final DownloadSelectedIncompleteMembersAction downloadSelectedIncompleteMembersAction = 114 new DownloadSelectedIncompleteMembersAction(); 115 private final SelectMembersAction selectMembersAction = new SelectMembersAction(false); 116 private final SelectMembersAction addMembersToSelectionAction = new SelectMembersAction(true); 117 private final SelectRelationAction selectRelationAction = new SelectRelationAction(false); 118 private final SelectRelationAction addRelationToSelectionAction = new SelectRelationAction(true); 119 /** add all selected primitives to the given relations */ 120 private final AddSelectionToRelations addSelectionToRelations = new AddSelectionToRelations(); 121 private transient JMenuItem addSelectionToRelationMenuItem; 122 123 private final transient HighlightHelper highlightHelper = new HighlightHelper(); 124 private final boolean highlightEnabled = Main.pref.getBoolean("draw.target-highlight", true); 125 private final transient RecentRelationsAction recentRelationsAction; 126 127 /** 128 * Constructs <code>RelationListDialog</code> 129 */ 130 public RelationListDialog() { 131 super(tr("Relations"), "relationlist", tr("Open a list of all relations."), 132 Shortcut.registerShortcut("subwindow:relations", tr("Toggle: {0}", tr("Relations")), 133 KeyEvent.VK_R, Shortcut.ALT_SHIFT), 150, true); 134 135 // create the list of relations 136 // 137 DefaultListSelectionModel selectionModel = new DefaultListSelectionModel(); 138 model = new RelationListModel(selectionModel); 139 displaylist = new JList<>(model); 140 displaylist.setSelectionModel(selectionModel); 141 displaylist.setCellRenderer(new NoTooltipOsmRenderer()); 142 displaylist.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 143 displaylist.addMouseListener(new MouseEventHandler()); 144 145 // the new action 146 // 147 newAction = new NewAction(); 148 149 filter = setupFilter(); 150 151 displaylist.addListSelectionListener(e -> { 152 if (!e.getValueIsAdjusting()) updateActionsRelationLists(); 153 }); 154 155 // Setup popup menu handler 156 setupPopupMenuHandler(); 157 158 JPanel pane = new JPanel(new BorderLayout()); 159 pane.add(filter, BorderLayout.NORTH); 160 pane.add(new JScrollPane(displaylist), BorderLayout.CENTER); 161 162 SideButton editButton = new SideButton(editAction, false); 163 recentRelationsAction = new RecentRelationsAction(editButton); 164 165 createLayout(pane, false, Arrays.asList(new SideButton[]{ 166 new SideButton(newAction, false), 167 editButton, 168 new SideButton(duplicateAction, false), 169 new SideButton(deleteRelationsAction, false), 170 new SideButton(selectRelationAction, false) 171 })); 172 173 InputMapUtils.unassignCtrlShiftUpDown(displaylist, JComponent.WHEN_FOCUSED); 174 175 // Select relation on Enter 176 InputMapUtils.addEnterAction(displaylist, selectRelationAction); 177 178 // Edit relation on Ctrl-Enter 179 displaylist.getActionMap().put("edit", editAction); 180 displaylist.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, KeyEvent.CTRL_MASK), "edit"); 181 182 // Do not hide copy action because of default JList override (fix #9815) 183 displaylist.getActionMap().put("copy", Main.main.menu.copy); 184 displaylist.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_C, GuiHelper.getMenuShortcutKeyMaskEx()), "copy"); 185 186 updateActionsRelationLists(); 187 } 188 189 @Override 190 public void destroy() { 191 model.clear(); 192 super.destroy(); 193 } 194 195 public void enableRecentRelations() { 196 recentRelationsAction.enableArrow(); 197 } 198 199 // inform all actions about list of relations they need 200 private void updateActionsRelationLists() { 201 List<Relation> sel = model.getSelectedRelations(); 202 popupMenuHandler.setPrimitives(sel); 203 204 Component focused = FocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); 205 206 //update highlights 207 if (highlightEnabled && focused == displaylist && Main.isDisplayingMapView() && highlightHelper.highlightOnly(sel)) { 208 Main.map.mapView.repaint(); 209 } 210 } 211 212 @Override 213 public void showNotify() { 214 Main.getLayerManager().addLayerChangeListener(newAction); 215 Main.getLayerManager().addActiveLayerChangeListener(newAction); 216 MapView.addZoomChangeListener(this); 217 newAction.updateEnabledState(); 218 DatasetEventManager.getInstance().addDatasetListener(this, FireMode.IN_EDT); 219 DataSet.addSelectionListener(addSelectionToRelations); 220 dataChanged(null); 221 ExpertToggleAction.addExpertModeChangeListener(this); 222 expertChanged(ExpertToggleAction.isExpert()); 223 } 224 225 @Override 226 public void hideNotify() { 227 Main.getLayerManager().removeActiveLayerChangeListener(newAction); 228 Main.getLayerManager().removeLayerChangeListener(newAction); 229 MapView.removeZoomChangeListener(this); 230 DatasetEventManager.getInstance().removeDatasetListener(this); 231 DataSet.removeSelectionListener(addSelectionToRelations); 232 ExpertToggleAction.removeExpertModeChangeListener(this); 233 } 234 235 private void resetFilter() { 236 filter.setText(null); 237 } 238 239 /** 240 * Initializes the relation list dialog from a layer. If <code>layer</code> is null 241 * or if it isn't an {@link OsmDataLayer} the dialog is reset to an empty dialog. 242 * Otherwise it is initialized with the list of non-deleted and visible relations 243 * in the layer's dataset. 244 * 245 * @param layer the layer. May be null. 246 */ 247 protected void initFromLayer(Layer layer) { 248 if (!(layer instanceof OsmDataLayer)) { 249 model.setRelations(null); 250 return; 251 } 252 OsmDataLayer l = (OsmDataLayer) layer; 253 model.setRelations(l.data.getRelations()); 254 model.updateTitle(); 255 updateActionsRelationLists(); 256 } 257 258 /** 259 * @return The selected relation in the list 260 */ 261 private Relation getSelected() { 262 if (model.getSize() == 1) { 263 displaylist.setSelectedIndex(0); 264 } 265 return displaylist.getSelectedValue(); 266 } 267 268 /** 269 * Selects the relation <code>relation</code> in the list of relations. 270 * 271 * @param relation the relation 272 */ 273 public void selectRelation(Relation relation) { 274 selectRelations(Collections.singleton(relation)); 275 } 276 277 /** 278 * Selects the relations in the list of relations. 279 * @param relations the relations to be selected 280 */ 281 public void selectRelations(Collection<Relation> relations) { 282 if (relations == null || relations.isEmpty()) { 283 model.setSelectedRelations(null); 284 } else { 285 model.setSelectedRelations(relations); 286 Integer i = model.getVisibleRelationIndex(relations.iterator().next()); 287 if (i != null) { 288 // Not all relations have to be in the list 289 // (for example when the relation list is hidden, it's not updated with new relations) 290 displaylist.scrollRectToVisible(displaylist.getCellBounds(i, i)); 291 } 292 } 293 } 294 295 private JosmTextField setupFilter() { 296 final JosmTextField f = new DisableShortcutsOnFocusGainedTextField(); 297 f.setToolTipText(tr("Relation list filter")); 298 final CompileSearchTextDecorator decorator = CompileSearchTextDecorator.decorate(f); 299 f.addPropertyChangeListener("filter", evt -> model.setFilter(decorator.getMatch())); 300 return f; 301 } 302 303 static final class NoTooltipOsmRenderer extends OsmPrimitivRenderer { 304 @Override 305 protected String getComponentToolTipText(OsmPrimitive value) { 306 // Don't show the default tooltip in the relation list 307 return null; 308 } 309 } 310 311 class MouseEventHandler extends PopupMenuLauncher { 312 313 MouseEventHandler() { 314 super(popupMenu); 315 } 316 317 @Override 318 public void mouseExited(MouseEvent me) { 319 if (highlightEnabled) highlightHelper.clear(); 320 } 321 322 protected void setCurrentRelationAsSelection() { 323 Main.getLayerManager().getEditDataSet().setSelected(displaylist.getSelectedValue()); 324 } 325 326 protected void editCurrentRelation() { 327 EditRelationAction.launchEditor(getSelected()); 328 } 329 330 @Override 331 public void mouseClicked(MouseEvent e) { 332 if (Main.getLayerManager().getEditLayer() == null) return; 333 if (isDoubleClick(e)) { 334 if (e.isControlDown()) { 335 editCurrentRelation(); 336 } else { 337 setCurrentRelationAsSelection(); 338 } 339 } 340 } 341 } 342 343 /** 344 * The action for creating a new relation. 345 */ 346 static class NewAction extends AbstractAction implements LayerChangeListener, ActiveLayerChangeListener { 347 NewAction() { 348 putValue(SHORT_DESCRIPTION, tr("Create a new relation")); 349 putValue(NAME, tr("New")); 350 new ImageProvider("dialogs", "addrelation").getResource().attachImageIcon(this, true); 351 updateEnabledState(); 352 } 353 354 public void run() { 355 RelationEditor.getEditor(Main.getLayerManager().getEditLayer(), null, null).setVisible(true); 356 } 357 358 @Override 359 public void actionPerformed(ActionEvent e) { 360 run(); 361 } 362 363 protected void updateEnabledState() { 364 setEnabled(Main.getLayerManager().getEditLayer() != null); 365 } 366 367 @Override 368 public void activeOrEditLayerChanged(ActiveLayerChangeEvent e) { 369 updateEnabledState(); 370 } 371 372 @Override 373 public void layerAdded(LayerAddEvent e) { 374 updateEnabledState(); 375 } 376 377 @Override 378 public void layerRemoving(LayerRemoveEvent e) { 379 updateEnabledState(); 380 } 381 382 @Override 383 public void layerOrderChanged(LayerOrderChangeEvent e) { 384 // Do nothing 385 } 386 } 387 388 /** 389 * The list model for the list of relations displayed in the relation list dialog. 390 */ 391 private class RelationListModel extends AbstractListModel<Relation> { 392 private final transient List<Relation> relations = new ArrayList<>(); 393 private transient List<Relation> filteredRelations; 394 private final DefaultListSelectionModel selectionModel; 395 private transient SearchCompiler.Match filter; 396 397 RelationListModel(DefaultListSelectionModel selectionModel) { 398 this.selectionModel = selectionModel; 399 } 400 401 /** 402 * Clears the model. 403 */ 404 public void clear() { 405 relations.clear(); 406 if (filteredRelations != null) 407 filteredRelations.clear(); 408 filter = null; 409 } 410 411 /** 412 * Sorts the model using {@link DefaultNameFormatter} relation comparator. 413 */ 414 public void sort() { 415 relations.sort(DefaultNameFormatter.getInstance().getRelationComparator()); 416 } 417 418 private boolean isValid(Relation r) { 419 return !r.isDeleted() && r.isVisible() && !r.isIncomplete(); 420 } 421 422 public void setRelations(Collection<Relation> relations) { 423 List<Relation> sel = getSelectedRelations(); 424 this.relations.clear(); 425 this.filteredRelations = null; 426 if (relations == null) { 427 selectionModel.clearSelection(); 428 fireContentsChanged(this, 0, getSize()); 429 return; 430 } 431 for (Relation r: relations) { 432 if (isValid(r)) { 433 this.relations.add(r); 434 } 435 } 436 sort(); 437 updateFilteredRelations(); 438 fireIntervalAdded(this, 0, getSize()); 439 setSelectedRelations(sel); 440 } 441 442 /** 443 * Add all relations in <code>addedPrimitives</code> to the model for the 444 * relation list dialog 445 * 446 * @param addedPrimitives the collection of added primitives. May include nodes, 447 * ways, and relations. 448 */ 449 public void addRelations(Collection<? extends OsmPrimitive> addedPrimitives) { 450 boolean added = false; 451 for (OsmPrimitive p: addedPrimitives) { 452 if (!(p instanceof Relation)) { 453 continue; 454 } 455 456 Relation r = (Relation) p; 457 if (relations.contains(r)) { 458 continue; 459 } 460 if (isValid(r)) { 461 relations.add(r); 462 added = true; 463 } 464 } 465 if (added) { 466 List<Relation> sel = getSelectedRelations(); 467 sort(); 468 updateFilteredRelations(); 469 fireIntervalAdded(this, 0, getSize()); 470 setSelectedRelations(sel); 471 } 472 } 473 474 /** 475 * Removes all relations in <code>removedPrimitives</code> from the model 476 * 477 * @param removedPrimitives the removed primitives. May include nodes, ways, 478 * and relations 479 */ 480 public void removeRelations(Collection<? extends OsmPrimitive> removedPrimitives) { 481 if (removedPrimitives == null) return; 482 // extract the removed relations 483 // 484 Set<Relation> removedRelations = new HashSet<>(); 485 for (OsmPrimitive p: removedPrimitives) { 486 if (!(p instanceof Relation)) { 487 continue; 488 } 489 removedRelations.add((Relation) p); 490 } 491 if (removedRelations.isEmpty()) 492 return; 493 int size = relations.size(); 494 relations.removeAll(removedRelations); 495 if (filteredRelations != null) { 496 filteredRelations.removeAll(removedRelations); 497 } 498 if (size != relations.size()) { 499 List<Relation> sel = getSelectedRelations(); 500 sort(); 501 fireContentsChanged(this, 0, getSize()); 502 setSelectedRelations(sel); 503 } 504 } 505 506 private void updateFilteredRelations() { 507 if (filter != null) { 508 filteredRelations = new ArrayList<>(SubclassFilteredCollection.filter(relations, filter::match)); 509 } else if (filteredRelations != null) { 510 filteredRelations = null; 511 } 512 } 513 514 public void setFilter(final SearchCompiler.Match filter) { 515 this.filter = filter; 516 updateFilteredRelations(); 517 List<Relation> sel = getSelectedRelations(); 518 fireContentsChanged(this, 0, getSize()); 519 setSelectedRelations(sel); 520 updateTitle(); 521 } 522 523 private List<Relation> getVisibleRelations() { 524 return filteredRelations == null ? relations : filteredRelations; 525 } 526 527 private Relation getVisibleRelation(int index) { 528 if (index < 0 || index >= getVisibleRelations().size()) return null; 529 return getVisibleRelations().get(index); 530 } 531 532 @Override 533 public Relation getElementAt(int index) { 534 return getVisibleRelation(index); 535 } 536 537 @Override 538 public int getSize() { 539 return getVisibleRelations().size(); 540 } 541 542 /** 543 * Replies the list of selected relations. Empty list, 544 * if there are no selected relations. 545 * 546 * @return the list of selected, non-new relations. 547 */ 548 public List<Relation> getSelectedRelations() { 549 List<Relation> ret = new ArrayList<>(); 550 for (int i = 0; i < getSize(); i++) { 551 if (!selectionModel.isSelectedIndex(i)) { 552 continue; 553 } 554 ret.add(getVisibleRelation(i)); 555 } 556 return ret; 557 } 558 559 /** 560 * Sets the selected relations. 561 * 562 * @param sel the list of selected relations 563 */ 564 public void setSelectedRelations(Collection<Relation> sel) { 565 selectionModel.setValueIsAdjusting(true); 566 selectionModel.clearSelection(); 567 if (sel != null && !sel.isEmpty()) { 568 if (!getVisibleRelations().containsAll(sel)) { 569 resetFilter(); 570 } 571 for (Relation r: sel) { 572 Integer i = getVisibleRelationIndex(r); 573 if (i != null) { 574 selectionModel.addSelectionInterval(i, i); 575 } 576 } 577 } 578 selectionModel.setValueIsAdjusting(false); 579 } 580 581 private Integer getVisibleRelationIndex(Relation rel) { 582 int i = getVisibleRelations().indexOf(rel); 583 if (i < 0) 584 return null; 585 return i; 586 } 587 588 public void updateTitle() { 589 if (!relations.isEmpty() && relations.size() != getSize()) { 590 RelationListDialog.this.setTitle(tr("Relations: {0}/{1}", getSize(), relations.size())); 591 } else if (getSize() > 0) { 592 RelationListDialog.this.setTitle(tr("Relations: {0}", getSize())); 593 } else { 594 RelationListDialog.this.setTitle(tr("Relations")); 595 } 596 } 597 } 598 599 private void setupPopupMenuHandler() { 600 601 // -- select action 602 popupMenuHandler.addAction(selectRelationAction); 603 popupMenuHandler.addAction(addRelationToSelectionAction); 604 605 // -- select members action 606 popupMenuHandler.addAction(selectMembersAction); 607 popupMenuHandler.addAction(addMembersToSelectionAction); 608 609 popupMenuHandler.addSeparator(); 610 // -- download members action 611 popupMenuHandler.addAction(downloadMembersAction); 612 613 // -- download incomplete members action 614 popupMenuHandler.addAction(downloadSelectedIncompleteMembersAction); 615 616 popupMenuHandler.addSeparator(); 617 popupMenuHandler.addAction(editAction).setVisible(false); 618 popupMenuHandler.addAction(duplicateAction).setVisible(false); 619 popupMenuHandler.addAction(deleteRelationsAction).setVisible(false); 620 621 addSelectionToRelationMenuItem = popupMenuHandler.addAction(addSelectionToRelations); 622 } 623 624 /* ---------------------------------------------------------------------------------- */ 625 /* Methods that can be called from plugins */ 626 /* ---------------------------------------------------------------------------------- */ 627 628 /** 629 * Replies the popup menu handler. 630 * @return The popup menu handler 631 */ 632 public PopupMenuHandler getPopupMenuHandler() { 633 return popupMenuHandler; 634 } 635 636 /** 637 * Replies the list of selected relations. Empty list, if there are no selected relations. 638 * @return the list of selected, non-new relations. 639 */ 640 public Collection<Relation> getSelectedRelations() { 641 return model.getSelectedRelations(); 642 } 643 644 /* ---------------------------------------------------------------------------------- */ 645 /* DataSetListener */ 646 /* ---------------------------------------------------------------------------------- */ 647 648 @Override 649 public void nodeMoved(NodeMovedEvent event) { 650 /* irrelevant in this context */ 651 } 652 653 @Override 654 public void wayNodesChanged(WayNodesChangedEvent event) { 655 /* irrelevant in this context */ 656 } 657 658 @Override 659 public void primitivesAdded(final PrimitivesAddedEvent event) { 660 model.addRelations(event.getPrimitives()); 661 model.updateTitle(); 662 } 663 664 @Override 665 public void primitivesRemoved(final PrimitivesRemovedEvent event) { 666 model.removeRelations(event.getPrimitives()); 667 model.updateTitle(); 668 } 669 670 @Override 671 public void relationMembersChanged(final RelationMembersChangedEvent event) { 672 List<Relation> sel = model.getSelectedRelations(); 673 model.sort(); 674 model.setSelectedRelations(sel); 675 displaylist.repaint(); 676 } 677 678 @Override 679 public void tagsChanged(TagsChangedEvent event) { 680 OsmPrimitive prim = event.getPrimitive(); 681 if (!(prim instanceof Relation)) 682 return; 683 // trigger a sort of the relation list because the display name may have changed 684 // 685 List<Relation> sel = model.getSelectedRelations(); 686 model.sort(); 687 model.setSelectedRelations(sel); 688 displaylist.repaint(); 689 } 690 691 @Override 692 public void dataChanged(DataChangedEvent event) { 693 initFromLayer(Main.getLayerManager().getEditLayer()); 694 } 695 696 @Override 697 public void otherDatasetChange(AbstractDatasetChangedEvent event) { 698 /* ignore */ 699 } 700 701 @Override 702 public void zoomChanged() { 703 // re-filter relations 704 if (model.filter != null) { 705 model.setFilter(model.filter); 706 } 707 } 708 709 @Override 710 public void expertChanged(boolean isExpert) { 711 addSelectionToRelationMenuItem.setVisible(isExpert); 712 } 713}