source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/ValidatorDialog.java@ 14846

Last change on this file since 14846 was 14846, checked in by GerdP, 5 years ago

fix findbugs issue: Should org.openstreetmap.josm.gui.dialogs.ValidatorDialog$AutofixCommand be a _static_ inner class?

  • Property svn:eol-style set to native
File size: 25.9 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.dialogs;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.event.ActionEvent;
7import java.awt.event.KeyEvent;
8import java.awt.event.MouseEvent;
9import java.io.IOException;
10import java.lang.reflect.InvocationTargetException;
11import java.util.ArrayList;
12import java.util.Collection;
13import java.util.Enumeration;
14import java.util.HashSet;
15import java.util.LinkedList;
16import java.util.List;
17import java.util.Set;
18import java.util.concurrent.atomic.AtomicBoolean;
19
20import javax.swing.AbstractAction;
21import javax.swing.Action;
22import javax.swing.JComponent;
23import javax.swing.JOptionPane;
24import javax.swing.JPopupMenu;
25import javax.swing.SwingUtilities;
26import javax.swing.event.TreeSelectionEvent;
27import javax.swing.event.TreeSelectionListener;
28import javax.swing.tree.DefaultMutableTreeNode;
29import javax.swing.tree.TreeNode;
30import javax.swing.tree.TreePath;
31
32import org.openstreetmap.josm.actions.AbstractSelectAction;
33import org.openstreetmap.josm.actions.AutoScaleAction;
34import org.openstreetmap.josm.actions.ValidateAction;
35import org.openstreetmap.josm.actions.relation.EditRelationAction;
36import org.openstreetmap.josm.command.Command;
37import org.openstreetmap.josm.command.SequenceCommand;
38import org.openstreetmap.josm.data.UndoRedoHandler;
39import org.openstreetmap.josm.data.osm.DataSelectionListener;
40import org.openstreetmap.josm.data.osm.DataSet;
41import org.openstreetmap.josm.data.osm.Node;
42import org.openstreetmap.josm.data.osm.OsmPrimitive;
43import org.openstreetmap.josm.data.osm.WaySegment;
44import org.openstreetmap.josm.data.osm.event.SelectionEventManager;
45import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
46import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
47import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper;
48import org.openstreetmap.josm.data.validation.OsmValidator;
49import org.openstreetmap.josm.data.validation.TestError;
50import org.openstreetmap.josm.data.validation.ValidatorVisitor;
51import org.openstreetmap.josm.gui.MainApplication;
52import org.openstreetmap.josm.gui.PleaseWaitRunnable;
53import org.openstreetmap.josm.gui.PopupMenuHandler;
54import org.openstreetmap.josm.gui.SideButton;
55import org.openstreetmap.josm.gui.dialogs.validator.ValidatorTreePanel;
56import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeEvent;
57import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener;
58import org.openstreetmap.josm.gui.layer.OsmDataLayer;
59import org.openstreetmap.josm.gui.layer.ValidatorLayer;
60import org.openstreetmap.josm.gui.preferences.validator.ValidatorPreference;
61import org.openstreetmap.josm.gui.progress.ProgressMonitor;
62import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
63import org.openstreetmap.josm.io.OsmTransferException;
64import org.openstreetmap.josm.spi.preferences.Config;
65import org.openstreetmap.josm.tools.ImageProvider;
66import org.openstreetmap.josm.tools.InputMapUtils;
67import org.openstreetmap.josm.tools.JosmRuntimeException;
68import org.openstreetmap.josm.tools.Pair;
69import org.openstreetmap.josm.tools.Shortcut;
70import org.xml.sax.SAXException;
71
72/**
73 * A small tool dialog for displaying the current errors. The selection manager
74 * respects clicks into the selection list. Ctrl-click will remove entries from
75 * the list while single click will make the clicked entry the only selection.
76 *
77 * @author frsantos
78 */
79public class ValidatorDialog extends ToggleDialog implements DataSelectionListener, ActiveLayerChangeListener {
80
81 /** The display tree */
82 public ValidatorTreePanel tree;
83
84 /** The validate action */
85 public static final ValidateAction validateAction = new ValidateAction();
86
87 /** The fix button */
88 private final SideButton fixButton;
89 /** The ignore button */
90 private final SideButton ignoreButton;
91 /** The reset ignorelist button */
92 private final SideButton ignorelistManagement;
93 /** The select button */
94 private final SideButton selectButton;
95 /** The lookup button */
96 private final SideButton lookupButton;
97
98 private final JPopupMenu popupMenu = new JPopupMenu();
99 private final transient PopupMenuHandler popupMenuHandler = new PopupMenuHandler(popupMenu);
100
101 /** Last selected element */
102 private DefaultMutableTreeNode lastSelectedNode;
103
104 /**
105 * Constructor
106 */
107 public ValidatorDialog() {
108 super(tr("Validation Results"), "validator", tr("Open the validation window."),
109 Shortcut.registerShortcut("subwindow:validator", tr("Toggle: {0}", tr("Validation Results")),
110 KeyEvent.VK_V, Shortcut.ALT_SHIFT), 150, false, ValidatorPreference.class);
111
112 popupMenuHandler.addAction(MainApplication.getMenu().autoScaleActions.get("problem"));
113 popupMenuHandler.addAction(new EditRelationAction());
114
115 tree = new ValidatorTreePanel();
116 tree.addMouseListener(new MouseEventHandler());
117 addTreeSelectionListener(new SelectionWatch());
118 InputMapUtils.unassignCtrlShiftUpDown(tree, JComponent.WHEN_FOCUSED);
119
120 List<SideButton> buttons = new LinkedList<>();
121
122 selectButton = new SideButton(new AbstractSelectAction() {
123 @Override
124 public void actionPerformed(ActionEvent e) {
125 setSelectedItems();
126 }
127 });
128 InputMapUtils.addEnterAction(tree, selectButton.getAction());
129
130 selectButton.setEnabled(false);
131 buttons.add(selectButton);
132
133 lookupButton = new SideButton(new LookupAction());
134 buttons.add(lookupButton);
135
136 buttons.add(new SideButton(validateAction));
137
138 fixButton = new SideButton(new AbstractAction() {
139 {
140 putValue(NAME, tr("Fix"));
141 putValue(SHORT_DESCRIPTION, tr("Fix the selected issue."));
142 new ImageProvider("dialogs", "fix").getResource().attachImageIcon(this, true);
143 }
144 @Override
145 public void actionPerformed(ActionEvent e) {
146 fixErrors();
147 }
148 });
149 fixButton.setEnabled(false);
150 buttons.add(fixButton);
151
152 if (ValidatorPrefHelper.PREF_USE_IGNORE.get()) {
153 ignoreButton = new SideButton(new AbstractAction() {
154 {
155 putValue(NAME, tr("Ignore"));
156 putValue(SHORT_DESCRIPTION, tr("Ignore the selected issue next time."));
157 new ImageProvider("dialogs", "fix").getResource().attachImageIcon(this, true);
158 }
159 @Override
160 public void actionPerformed(ActionEvent e) {
161 ignoreErrors();
162 }
163 });
164 ignoreButton.setEnabled(false);
165 buttons.add(ignoreButton);
166
167 ignorelistManagement = new SideButton(new AbstractAction() {
168 {
169 putValue(NAME, tr("Manage Ignore"));
170 putValue(SHORT_DESCRIPTION, tr("Manage the ignore list"));
171 new ImageProvider("dialogs", "fix").getResource().attachImageIcon(this, true);
172 }
173
174 @Override
175 public void actionPerformed(ActionEvent e) {
176 new ValidatorListManagementDialog("Ignore");
177 }
178 });
179 buttons.add(ignorelistManagement);
180 } else {
181 ignoreButton = null;
182 ignorelistManagement = null;
183 }
184
185 createLayout(tree, true, buttons);
186 }
187
188 /**
189 * The action to lookup the selection in the error tree.
190 */
191 class LookupAction extends AbstractAction implements DataSelectionListener {
192
193 LookupAction() {
194 putValue(NAME, tr("Lookup"));
195 putValue(SHORT_DESCRIPTION, tr("Looks up the selected primitives in the error list."));
196 new ImageProvider("dialogs", "search").getResource().attachImageIcon(this, true);
197 SelectionEventManager.getInstance().addSelectionListener(this);
198 updateEnabledState();
199 }
200
201 @Override
202 public void actionPerformed(ActionEvent e) {
203 final DataSet ds = MainApplication.getLayerManager().getActiveDataSet();
204 if (ds == null) {
205 return;
206 }
207 tree.selectRelatedErrors(ds.getSelected());
208 }
209
210 protected void updateEnabledState() {
211 boolean found = false;
212 for (TestError e : tree.getErrors()) {
213 for (OsmPrimitive p : e.getPrimitives()) {
214 if (p.isSelected()) {
215 found = true;
216 break;
217 }
218 }
219 }
220 setEnabled(found);
221 }
222
223 @Override
224 public void selectionChanged(SelectionChangeEvent event) {
225 updateEnabledState();
226 }
227 }
228
229 @Override
230 public void showNotify() {
231 SelectionEventManager.getInstance().addSelectionListener(this);
232 DataSet ds = MainApplication.getLayerManager().getActiveDataSet();
233 if (ds != null) {
234 updateSelection(ds.getAllSelected());
235 }
236 MainApplication.getLayerManager().addAndFireActiveLayerChangeListener(this);
237 }
238
239 @Override
240 public void hideNotify() {
241 MainApplication.getLayerManager().removeActiveLayerChangeListener(this);
242 SelectionEventManager.getInstance().removeSelectionListener(this);
243 }
244
245 @Override
246 public void setVisible(boolean v) {
247 if (tree != null) {
248 tree.setVisible(v);
249 }
250 super.setVisible(v);
251 }
252
253 /**
254 * Fix selected errors
255 */
256 private void fixErrors() {
257 TreePath[] selectionPaths = tree.getSelectionPaths();
258 if (selectionPaths == null)
259 return;
260
261 Set<DefaultMutableTreeNode> processedNodes = new HashSet<>();
262
263 List<TestError> errorsToFix = new LinkedList<>();
264 for (TreePath path : selectionPaths) {
265 DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
266 if (node != null) {
267 ValidatorTreePanel.visitTestErrors(node, errorsToFix::add, processedNodes);
268 }
269 }
270
271 // run fix task asynchronously
272 MainApplication.worker.submit(new FixTask(errorsToFix));
273 }
274
275 /**
276 * Set selected errors to ignore state
277 */
278 private void ignoreErrors() {
279 int asked = JOptionPane.DEFAULT_OPTION;
280 AtomicBoolean changed = new AtomicBoolean();
281 TreePath[] selectionPaths = tree.getSelectionPaths();
282 if (selectionPaths == null)
283 return;
284
285 Set<DefaultMutableTreeNode> processedNodes = new HashSet<>();
286 for (TreePath path : selectionPaths) {
287 DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
288 if (node == null) {
289 continue;
290 }
291
292 Object mainNodeInfo = node.getUserObject();
293 final int depth = node.getDepth();
294 if (depth <= 1) {
295 if (!(mainNodeInfo instanceof TestError)) {
296 Set<Pair<String, String>> state = new HashSet<>();
297 // ask if the whole set should be ignored
298 if (asked == JOptionPane.DEFAULT_OPTION) {
299 String[] a = new String[] {tr("Whole group"), tr("Single elements"), tr("Nothing")};
300 asked = JOptionPane.showOptionDialog(MainApplication.getMainFrame(), tr("Ignore whole group or individual elements?"),
301 tr("Ignoring elements"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE, null,
302 a, a[1]);
303 }
304 if (asked == JOptionPane.YES_NO_OPTION) {
305 ValidatorTreePanel.visitTestErrors(node, err -> {
306 err.setIgnored(true);
307 changed.set(true);
308 state.add(new Pair<>(node.getDepth() == 1 ? err.getIgnoreSubGroup() : err.getIgnoreGroup(), err.getMessage()));
309 }, processedNodes);
310 for (Pair<String, String> s : state) {
311 OsmValidator.addIgnoredError(s.a, s.b);
312 }
313 continue;
314 } else if (asked == JOptionPane.CANCEL_OPTION || asked == JOptionPane.CLOSED_OPTION) {
315 continue;
316 }
317 }
318
319 ValidatorTreePanel.visitTestErrors(node, error -> {
320 String state = error.getIgnoreState();
321 if (state != null) {
322 OsmValidator.addIgnoredError(state, error.getMessage());
323 }
324 changed.set(true);
325 error.setIgnored(true);
326 }, processedNodes);
327 }
328 }
329 if (changed.get()) {
330 tree.resetErrors();
331 OsmValidator.saveIgnoredErrors();
332 invalidateValidatorLayers();
333 }
334 }
335
336 /**
337 * Sets the selection of the map to the current selected items.
338 */
339 private void setSelectedItems() {
340 DataSet ds = MainApplication.getLayerManager().getActiveDataSet();
341 if (tree == null || ds == null)
342 return;
343
344 TreePath[] selectedPaths = tree.getSelectionPaths();
345 if (selectedPaths == null)
346 return;
347
348 Collection<OsmPrimitive> sel = new HashSet<>(40);
349 for (TreePath path : selectedPaths) {
350 DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
351 Enumeration<TreeNode> children = node.breadthFirstEnumeration();
352 while (children.hasMoreElements()) {
353 DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) children.nextElement();
354 Object nodeInfo = childNode.getUserObject();
355 if (nodeInfo instanceof TestError) {
356 TestError error = (TestError) nodeInfo;
357 error.getPrimitives().stream()
358 .filter(OsmPrimitive::isSelectable)
359 .forEach(sel::add);
360 }
361 }
362 }
363 ds.setSelected(sel);
364 }
365
366 /**
367 * Checks for fixes in selected element and, if needed, adds to the sel
368 * parameter all selected elements
369 *
370 * @param sel
371 * The collection where to add all selected elements
372 * @param addSelected
373 * if true, add all selected elements to collection
374 * @return whether the selected elements has any fix
375 */
376 private boolean setSelection(Collection<OsmPrimitive> sel, boolean addSelected) {
377 AtomicBoolean hasFixes = new AtomicBoolean();
378
379 DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
380 if (lastSelectedNode != null && !lastSelectedNode.equals(node)) {
381 ValidatorTreePanel.visitTestErrors(lastSelectedNode, error -> error.setSelected(false));
382 }
383
384 lastSelectedNode = node;
385 if (node != null) {
386 ValidatorTreePanel.visitTestErrors(node, error -> {
387 error.setSelected(true);
388
389 hasFixes.set(hasFixes.get() || error.isFixable());
390 if (addSelected) {
391 error.getPrimitives().stream()
392 .filter(OsmPrimitive::isSelectable)
393 .forEach(sel::add);
394 }
395 });
396 selectButton.setEnabled(true);
397 if (ignoreButton != null) {
398 ignoreButton.setEnabled(node.getDepth() <= 1);
399 }
400 }
401
402 return hasFixes.get();
403 }
404
405 @Override
406 public void activeOrEditLayerChanged(ActiveLayerChangeEvent e) {
407 OsmDataLayer editLayer = e.getSource().getEditLayer();
408 if (editLayer == null) {
409 tree.setErrorList(new ArrayList<TestError>());
410 } else {
411 tree.setErrorList(editLayer.validationErrors);
412 }
413 }
414
415 /**
416 * Add a tree selection listener to the validator tree.
417 * @param listener the TreeSelectionListener
418 * @since 5958
419 */
420 public void addTreeSelectionListener(TreeSelectionListener listener) {
421 tree.addTreeSelectionListener(listener);
422 }
423
424 /**
425 * Remove the given tree selection listener from the validator tree.
426 * @param listener the TreeSelectionListener
427 * @since 5958
428 */
429 public void removeTreeSelectionListener(TreeSelectionListener listener) {
430 tree.removeTreeSelectionListener(listener);
431 }
432
433 /**
434 * Replies the popup menu handler.
435 * @return The popup menu handler
436 * @since 5958
437 */
438 public PopupMenuHandler getPopupMenuHandler() {
439 return popupMenuHandler;
440 }
441
442 /**
443 * Replies the currently selected error, or {@code null}.
444 * @return The selected error, if any.
445 * @since 5958
446 */
447 public TestError getSelectedError() {
448 Object comp = tree.getLastSelectedPathComponent();
449 if (comp instanceof DefaultMutableTreeNode) {
450 Object object = ((DefaultMutableTreeNode) comp).getUserObject();
451 if (object instanceof TestError) {
452 return (TestError) object;
453 }
454 }
455 return null;
456 }
457
458 /**
459 * Watches for double clicks and launches the popup menu.
460 */
461 class MouseEventHandler extends PopupMenuLauncher {
462
463 MouseEventHandler() {
464 super(popupMenu);
465 }
466
467 @Override
468 public void mouseClicked(MouseEvent e) {
469 TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
470 if (selPath == null) {
471 tree.clearSelection();
472 }
473
474 fixButton.setEnabled(false);
475 if (ignoreButton != null) {
476 ignoreButton.setEnabled(false);
477 }
478 selectButton.setEnabled(false);
479
480 boolean isDblClick = isDoubleClick(e);
481
482 Collection<OsmPrimitive> sel = isDblClick ? new HashSet<>(40) : null;
483
484 boolean hasFixes = setSelection(sel, isDblClick);
485 fixButton.setEnabled(hasFixes);
486
487 if (isDblClick) {
488 DataSet ds = MainApplication.getLayerManager().getActiveDataSet();
489 if (ds != null) {
490 ds.setSelected(sel);
491 }
492 if (Config.getPref().getBoolean("validator.autozoom", false)) {
493 AutoScaleAction.zoomTo(sel);
494 }
495 }
496 }
497
498 @Override
499 public void launch(MouseEvent e) {
500 TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
501 if (selPath == null)
502 return;
503 DefaultMutableTreeNode node = (DefaultMutableTreeNode) selPath.getPathComponent(selPath.getPathCount() - 1);
504 if (!(node.getUserObject() instanceof TestError))
505 return;
506 super.launch(e);
507 }
508 }
509
510 /**
511 * Watches for tree selection.
512 */
513 public class SelectionWatch implements TreeSelectionListener {
514 @Override
515 public void valueChanged(TreeSelectionEvent e) {
516 fixButton.setEnabled(false);
517 if (ignoreButton != null) {
518 ignoreButton.setEnabled(false);
519 }
520 selectButton.setEnabled(false);
521
522 Collection<OsmPrimitive> sel = new HashSet<>();
523 boolean hasFixes = setSelection(sel, true);
524 fixButton.setEnabled(hasFixes);
525 popupMenuHandler.setPrimitives(sel);
526 invalidateValidatorLayers();
527 }
528 }
529
530 /**
531 * A visitor that is used to compute the bounds of an error.
532 */
533 public static class ValidatorBoundingXYVisitor extends BoundingXYVisitor implements ValidatorVisitor {
534 @Override
535 public void visit(OsmPrimitive p) {
536 if (p.isUsable()) {
537 p.accept((PrimitiveVisitor) this);
538 }
539 }
540
541 @Override
542 public void visit(WaySegment ws) {
543 if (ws.lowerIndex < 0 || ws.lowerIndex + 1 >= ws.way.getNodesCount())
544 return;
545 visit(ws.getFirstNode());
546 visit(ws.getSecondNode());
547 }
548
549 @Override
550 public void visit(List<Node> nodes) {
551 for (Node n: nodes) {
552 visit(n);
553 }
554 }
555
556 @Override
557 public void visit(TestError error) {
558 if (error != null) {
559 error.visitHighlighted(this);
560 }
561 }
562 }
563
564 /**
565 * Called when the selection was changed to update the list of displayed errors
566 * @param newSelection The new selection
567 */
568 public void updateSelection(Collection<? extends OsmPrimitive> newSelection) {
569 if (!Config.getPref().getBoolean(ValidatorPrefHelper.PREF_FILTER_BY_SELECTION, false))
570 return;
571 if (newSelection.isEmpty()) {
572 tree.setFilter(null);
573 }
574 tree.setFilter(new HashSet<>(newSelection));
575 }
576
577 @Override
578 public void selectionChanged(SelectionChangeEvent event) {
579 updateSelection(event.getSelection());
580 }
581
582 /**
583 * Task for fixing a collection of {@link TestError}s. Can be run asynchronously.
584 */
585 class FixTask extends PleaseWaitRunnable {
586 private final Collection<TestError> testErrors;
587 private final List<Command> fixCommands = new ArrayList<>();
588 private boolean canceled;
589
590 FixTask(Collection<TestError> testErrors) {
591 super(tr("Fixing errors ..."), false /* don't ignore exceptions */);
592 this.testErrors = testErrors == null ? new ArrayList<>() : testErrors;
593 }
594
595 @Override
596 protected void cancel() {
597 this.canceled = true;
598 }
599
600 @Override
601 protected void finish() {
602 // do nothing
603 }
604
605 protected void fixError(TestError error) throws InterruptedException, InvocationTargetException {
606 if (error.isFixable()) {
607 if (error.getPrimitives().stream().noneMatch(OsmPrimitive::isDeleted)) {
608 final Command fixCommand = error.getFix();
609 if (fixCommand != null) {
610 SwingUtilities.invokeAndWait(fixCommand::executeCommand);
611 fixCommands.add(fixCommand);
612 }
613 }
614 // It is wanted to ignore an error if it said fixable, even if fixCommand was null
615 // This is to fix #5764 and #5773:
616 // a delete command, for example, may be null if all concerned primitives have already been deleted
617 error.setIgnored(true);
618 }
619 }
620
621 @Override
622 protected void realRun() throws SAXException, IOException, OsmTransferException {
623 ProgressMonitor monitor = getProgressMonitor();
624 try {
625 monitor.setTicksCount(testErrors.size());
626 final DataSet ds = MainApplication.getLayerManager().getActiveDataSet();
627 int i = 0;
628 SwingUtilities.invokeAndWait(ds::beginUpdate);
629 try {
630 for (TestError error: testErrors) {
631 i++;
632 monitor.subTask(tr("Fixing ({0}/{1}): ''{2}''", i, testErrors.size(), error.getMessage()));
633 if (this.canceled)
634 return;
635 fixError(error);
636 monitor.worked(1);
637 }
638 } finally {
639 SwingUtilities.invokeAndWait(ds::endUpdate);
640 }
641 monitor.subTask(tr("Updating map ..."));
642 SwingUtilities.invokeAndWait(() -> {
643 if (!fixCommands.isEmpty()) {
644 UndoRedoHandler.getInstance().add(
645 fixCommands.size() > 1 ? new AutofixCommand(fixCommands) : fixCommands.get(0), false);
646 }
647 invalidateValidatorLayers();
648 tree.resetErrors();
649 });
650 } catch (InterruptedException e) {
651 tryUndo();
652 throw new JosmRuntimeException(e);
653 } catch (InvocationTargetException e) {
654 // FIXME: signature of realRun should have a generic checked exception we could throw here
655 throw new JosmRuntimeException(e);
656 } finally {
657 if (monitor.isCanceled()) {
658 tryUndo();
659 }
660 monitor.finishTask();
661 }
662 }
663
664 /**
665 * Undo commands as they were not yet added to the UndoRedo Handler
666 */
667 private void tryUndo() {
668 final DataSet ds = MainApplication.getLayerManager().getActiveDataSet();
669 int i = fixCommands.size() - 1;
670 ds.beginUpdate();
671 for (; i >= 0; i--) {
672 fixCommands.get(i).undoCommand();
673 }
674 ds.endUpdate();
675 }
676
677 }
678
679 private static void invalidateValidatorLayers() {
680 MainApplication.getLayerManager().getLayersOfType(ValidatorLayer.class).forEach(ValidatorLayer::invalidate);
681 }
682
683 @Override
684 public void destroy() {
685 if (lookupButton != null && lookupButton.getAction() instanceof DataSelectionListener) {
686 Action a = lookupButton.getAction();
687 SelectionEventManager.getInstance().removeSelectionListener((DataSelectionListener) a);
688 }
689 super.destroy();
690 }
691
692 private static class AutofixCommand extends SequenceCommand {
693 AutofixCommand(Collection<Command> sequenz) {
694 super(tr("auto-fixed validator issues"), sequenz, true);
695 setSequenceComplete(true);
696 }
697
698 @Override
699 public void undoCommand() {
700 getAffectedDataSet().beginUpdate();
701 super.undoCommand();
702 getAffectedDataSet().endUpdate();
703 }
704
705 @Override
706 public boolean executeCommand() {
707 getAffectedDataSet().beginUpdate();
708 boolean rc = super.executeCommand();
709 getAffectedDataSet().endUpdate();
710 return rc;
711 }
712 }
713}
Note: See TracBrowser for help on using the repository browser.