001 // License: GPL. See LICENSE file for details. 002 package org.openstreetmap.josm.actions; 003 004 import static org.openstreetmap.josm.tools.I18n.tr; 005 006 import java.awt.event.ActionEvent; 007 import java.awt.event.KeyEvent; 008 import java.io.IOException; 009 import java.util.ArrayList; 010 import java.util.Collection; 011 import java.util.List; 012 013 import org.openstreetmap.josm.Main; 014 import org.openstreetmap.josm.data.osm.OsmPrimitive; 015 import org.openstreetmap.josm.data.validation.OsmValidator; 016 import org.openstreetmap.josm.data.validation.Test; 017 import org.openstreetmap.josm.data.validation.TestError; 018 import org.openstreetmap.josm.data.validation.util.AggregatePrimitivesVisitor; 019 import org.openstreetmap.josm.gui.PleaseWaitRunnable; 020 import org.openstreetmap.josm.gui.preferences.ValidatorPreference; 021 import org.openstreetmap.josm.gui.util.GuiHelper; 022 import org.openstreetmap.josm.io.OsmTransferException; 023 import org.openstreetmap.josm.tools.Shortcut; 024 import org.xml.sax.SAXException; 025 026 /** 027 * The action that does the validate thing. 028 * <p> 029 * This action iterates through all active tests and give them the data, so that 030 * each one can test it. 031 * 032 * @author frsantos 033 */ 034 public class ValidateAction extends JosmAction { 035 036 /** Serializable ID */ 037 private static final long serialVersionUID = -2304521273582574603L; 038 039 /** Last selection used to validate */ 040 private Collection<OsmPrimitive> lastSelection; 041 042 /** 043 * Constructor 044 */ 045 public ValidateAction() { 046 super(tr("Validation"), "dialogs/validator", tr("Performs the data validation"), 047 Shortcut.registerShortcut("tools:validate", tr("Tool: {0}", tr("Validation")), 048 KeyEvent.VK_V, Shortcut.SHIFT), true); 049 } 050 051 public void actionPerformed(ActionEvent ev) { 052 doValidate(ev, true); 053 } 054 055 /** 056 * Does the validation. 057 * <p> 058 * If getSelectedItems is true, the selected items (or all items, if no one 059 * is selected) are validated. If it is false, last selected items are 060 * revalidated 061 * 062 * @param ev The event 063 * @param getSelectedItems If selected or last selected items must be validated 064 */ 065 public void doValidate(ActionEvent ev, boolean getSelectedItems) { 066 if (Main.map == null || !Main.map.isVisible()) 067 return; 068 069 OsmValidator.initializeErrorLayer(); 070 071 Collection<Test> tests = OsmValidator.getEnabledTests(false); 072 if (tests.isEmpty()) 073 return; 074 075 Collection<OsmPrimitive> selection; 076 if (getSelectedItems) { 077 selection = Main.main.getCurrentDataSet().getAllSelected(); 078 if (selection.isEmpty()) { 079 selection = Main.main.getCurrentDataSet().allNonDeletedPrimitives(); 080 lastSelection = null; 081 } else { 082 AggregatePrimitivesVisitor v = new AggregatePrimitivesVisitor(); 083 selection = v.visit(selection); 084 lastSelection = selection; 085 } 086 } else { 087 if (lastSelection == null) { 088 selection = Main.main.getCurrentDataSet().allNonDeletedPrimitives(); 089 } else { 090 selection = lastSelection; 091 } 092 } 093 094 ValidationTask task = new ValidationTask(tests, selection, lastSelection); 095 Main.worker.submit(task); 096 } 097 098 @Override 099 public void updateEnabledState() { 100 setEnabled(getEditLayer() != null); 101 } 102 103 @Override 104 public void destroy() { 105 // Hack - this action should stay forever because it could be added to toolbar 106 // Do not call super.destroy() here 107 } 108 109 /** 110 * Asynchronous task for running a collection of tests against a collection 111 * of primitives 112 * 113 */ 114 static class ValidationTask extends PleaseWaitRunnable { 115 private Collection<Test> tests; 116 private Collection<OsmPrimitive> validatedPrimitives; 117 private Collection<OsmPrimitive> formerValidatedPrimitives; 118 private boolean canceled; 119 private List<TestError> errors; 120 121 /** 122 * 123 * @param tests the tests to run 124 * @param validatedPrimitives the collection of primitives to validate. 125 * @param formerValidatedPrimitives the last collection of primitives being validates. May be null. 126 */ 127 public ValidationTask(Collection<Test> tests, Collection<OsmPrimitive> validatedPrimitives, Collection<OsmPrimitive> formerValidatedPrimitives) { 128 super(tr("Validating"), false /*don't ignore exceptions */); 129 this.validatedPrimitives = validatedPrimitives; 130 this.formerValidatedPrimitives = formerValidatedPrimitives; 131 this.tests = tests; 132 } 133 134 @Override 135 protected void cancel() { 136 this.canceled = true; 137 } 138 139 @Override 140 protected void finish() { 141 if (canceled) return; 142 143 // update GUI on Swing EDT 144 // 145 GuiHelper.runInEDT(new Runnable() { 146 @Override 147 public void run() { 148 Main.map.validatorDialog.tree.setErrors(errors); 149 Main.map.validatorDialog.unfurlDialog(); 150 Main.main.getCurrentDataSet().fireSelectionChanged(); 151 } 152 }); 153 } 154 155 @Override 156 protected void realRun() throws SAXException, IOException, 157 OsmTransferException { 158 if (tests == null || tests.isEmpty()) 159 return; 160 errors = new ArrayList<TestError>(200); 161 getProgressMonitor().setTicksCount(tests.size() * validatedPrimitives.size()); 162 int testCounter = 0; 163 for (Test test : tests) { 164 if (canceled) 165 return; 166 testCounter++; 167 getProgressMonitor().setCustomText(tr("Test {0}/{1}: Starting {2}", testCounter, tests.size(),test.getName())); 168 test.setPartialSelection(formerValidatedPrimitives != null); 169 test.startTest(getProgressMonitor().createSubTaskMonitor(validatedPrimitives.size(), false)); 170 test.visit(validatedPrimitives); 171 test.endTest(); 172 errors.addAll(test.getErrors()); 173 } 174 tests = null; 175 if (Main.pref.getBoolean(ValidatorPreference.PREF_USE_IGNORE, true)) { 176 getProgressMonitor().subTask(tr("Updating ignored errors ...")); 177 for (TestError error : errors) { 178 if (canceled) return; 179 List<String> s = new ArrayList<String>(); 180 s.add(error.getIgnoreState()); 181 s.add(error.getIgnoreGroup()); 182 s.add(error.getIgnoreSubGroup()); 183 for (String state : s) { 184 if (state != null && OsmValidator.hasIgnoredError(state)) { 185 error.setIgnored(true); 186 } 187 } 188 } 189 } 190 } 191 } 192 }