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