001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.actions.upload; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.Dimension; 007import java.awt.GridBagLayout; 008import java.util.ArrayList; 009import java.util.Collection; 010import java.util.List; 011 012import javax.swing.JPanel; 013import javax.swing.JScrollPane; 014 015import org.openstreetmap.josm.data.APIDataSet; 016import org.openstreetmap.josm.data.osm.OsmPrimitive; 017import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper; 018import org.openstreetmap.josm.data.validation.OsmValidator; 019import org.openstreetmap.josm.data.validation.Severity; 020import org.openstreetmap.josm.data.validation.Test; 021import org.openstreetmap.josm.data.validation.TestError; 022import org.openstreetmap.josm.data.validation.util.AggregatePrimitivesVisitor; 023import org.openstreetmap.josm.gui.ExtendedDialog; 024import org.openstreetmap.josm.gui.MainApplication; 025import org.openstreetmap.josm.gui.MapFrame; 026import org.openstreetmap.josm.gui.dialogs.validator.ValidatorTreePanel; 027import org.openstreetmap.josm.gui.layer.OsmDataLayer; 028import org.openstreetmap.josm.gui.layer.ValidatorLayer; 029import org.openstreetmap.josm.gui.util.GuiHelper; 030import org.openstreetmap.josm.gui.widgets.HtmlPanel; 031import org.openstreetmap.josm.tools.GBC; 032 033/** 034 * The action that does the validate thing. 035 * <p> 036 * This action iterates through all active tests and give them the data, so that 037 * each one can test it. 038 * 039 * @author frsantos 040 * @since 3669 041 */ 042public class ValidateUploadHook implements UploadHook { 043 044 /** 045 * Validate the modified data before uploading 046 */ 047 @Override 048 public boolean checkUpload(APIDataSet apiDataSet) { 049 050 OsmValidator.initializeTests(); 051 Collection<Test> tests = OsmValidator.getEnabledTests(true); 052 if (tests.isEmpty()) 053 return true; 054 055 AggregatePrimitivesVisitor v = new AggregatePrimitivesVisitor(); 056 v.visit(apiDataSet.getPrimitivesToAdd()); 057 Collection<OsmPrimitive> selection = v.visit(apiDataSet.getPrimitivesToUpdate()); 058 059 List<TestError> errors = new ArrayList<>(30); 060 for (Test test : tests) { 061 test.setBeforeUpload(true); 062 test.setPartialSelection(true); 063 test.startTest(null); 064 test.visit(selection); 065 test.endTest(); 066 if (ValidatorPrefHelper.PREF_OTHER.get() && ValidatorPrefHelper.PREF_OTHER_UPLOAD.get()) { 067 errors.addAll(test.getErrors()); 068 } else { 069 for (TestError e : test.getErrors()) { 070 if (e.getSeverity() != Severity.OTHER) { 071 errors.add(e); 072 } 073 } 074 } 075 test.clear(); 076 } 077 078 if (ValidatorPrefHelper.PREF_USE_IGNORE.get()) { 079 int nume = 0; 080 for (TestError error : errors) { 081 List<String> s = new ArrayList<>(); 082 s.add(error.getIgnoreState()); 083 s.add(error.getIgnoreGroup()); 084 s.add(error.getIgnoreSubGroup()); 085 for (String state : s) { 086 if (state != null && OsmValidator.hasIgnoredError(state)) { 087 error.setIgnored(true); 088 } 089 } 090 if (!error.isIgnored()) { 091 ++nume; 092 } 093 } 094 if (nume == 0) 095 return true; 096 } 097 098 OsmDataLayer editLayer = MainApplication.getLayerManager().getEditLayer(); 099 if (editLayer != null) { 100 editLayer.validationErrors.clear(); 101 editLayer.validationErrors.addAll(errors); 102 } 103 MapFrame map = MainApplication.getMap(); 104 if (map != null) { 105 map.validatorDialog.tree.setErrors(errors); 106 } 107 if (errors.isEmpty()) 108 return true; 109 110 return displayErrorScreen(errors); 111 } 112 113 /** 114 * Displays a screen where the actions that would be taken are displayed and 115 * give the user the possibility to cancel the upload. 116 * @param errors The errors displayed in the screen 117 * @return <code>true</code>, if the upload should continue. <code>false</code> 118 * if the user requested cancel. 119 */ 120 private static boolean displayErrorScreen(List<TestError> errors) { 121 JPanel p = new JPanel(new GridBagLayout()); 122 ValidatorTreePanel errorPanel = new ValidatorTreePanel(errors); 123 errorPanel.expandAll(); 124 HtmlPanel pnlMessage = new HtmlPanel(); 125 pnlMessage.setText("<html><body>" 126 + tr("The following are results of automatic validation. Try fixing" 127 + " these, but be careful (don''t destroy valid data)." 128 + " When in doubt ignore them.<br>When you" 129 + " cancel this dialog, you can find the entries in the validator" 130 + " side panel to inspect them.") 131 + "<table align=\"center\">" 132 + "<tr><td align=\"left\"><b>"+tr("Errors") 133 + " </b></td><td align=\"left\">" 134 + tr("Usually this should be fixed.")+"</td></tr>" 135 + "<tr><td align=\"left\"><b>"+tr("Warnings") 136 + " </b></td><td align=\"left\">" 137 + tr("Fix these when possible.")+"</td></tr>" 138 + "<tr><td align=\"left\"><b>"+tr("Other") 139 + " </b></td><td align=\"left\">" 140 + tr("Informational warnings, expect many false entries.")+"</td></tr>" 141 + "</table>" 142 ); 143 pnlMessage.setPreferredSize(new Dimension(500, 150)); 144 p.add(pnlMessage, GBC.eol().fill(GBC.HORIZONTAL)); 145 p.add(new JScrollPane(errorPanel), GBC.eol().fill(GBC.BOTH)); 146 147 ExtendedDialog ed = new ExtendedDialog(MainApplication.getMainFrame(), 148 tr("Suspicious data found. Upload anyway?"), 149 tr("Continue upload"), tr("Cancel")) 150 .setButtonIcons("ok", "cancel") 151 .setContent(p); 152 int rc = ed.showDialog().getValue(); 153 GuiHelper.destroyComponents(ed, false); 154 ed.dispose(); 155 if (rc != 1) { 156 OsmValidator.initializeTests(); 157 OsmValidator.initializeErrorLayer(); 158 MainApplication.getMap().validatorDialog.unfurlDialog(); 159 MainApplication.getLayerManager().getLayersOfType(ValidatorLayer.class).forEach(ValidatorLayer::invalidate); 160 return false; 161 } 162 return true; 163 } 164}